Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add bulk delete, bulk archive/unarchive, and bulk metadata edit buttons in books table page #3113

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
d0d9985
Add bulk delete button
jmarmstrong1207 Aug 2, 2024
d9a2a7a
Add bulk archive/unarchive buttons
jmarmstrong1207 Aug 2, 2024
ca9fc74
typo fix
jmarmstrong1207 Aug 2, 2024
34fec0e
Move buttons into table
jmarmstrong1207 Aug 2, 2024
4ed0633
Add bulk read/unread buttons; Fix buttons not working when moved into…
jmarmstrong1207 Aug 2, 2024
ecda717
Add bulk metadata edit button
jmarmstrong1207 Aug 2, 2024
ab3d4e4
Fix emptying metadata form after submit
jmarmstrong1207 Aug 3, 2024
9def910
switch title_sort to sort in api edit request
jmarmstrong1207 Aug 3, 2024
96fb2c1
Auto disable author/title sort input in metadata edit form
jmarmstrong1207 Aug 3, 2024
a335dd7
Make edit metadata pass all data in a single REST call. Modularize ed…
jmarmstrong1207 Aug 3, 2024
bee6a35
remove spacing
jmarmstrong1207 Aug 3, 2024
e31763d
Fix kobo sync status marking as archived even though state = false
jmarmstrong1207 Aug 3, 2024
2ae80d3
Fix book_read_status marking as read even though read_status is passe…
jmarmstrong1207 Aug 3, 2024
2afce66
Fix change_archived so state=none is a toggle. Fixes /togglearchived …
jmarmstrong1207 Aug 3, 2024
de3f883
Add change_archived_books() description
jmarmstrong1207 Aug 3, 2024
fe78222
Add shift-click to select multiple books at once
jmarmstrong1207 Aug 5, 2024
7e5d897
Merge branch 'master' into bulk-delete
jmarmstrong1207 Sep 11, 2024
31380f2
fix typo
jmarmstrong1207 Sep 17, 2024
338441f
fix author sort not updating when bulk editing
jmarmstrong1207 Sep 17, 2024
54d9d33
Revert "Add shift-click to select multiple books at once"
jmarmstrong1207 Sep 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add bulk archive/unarchive buttons
  • Loading branch information
jmarmstrong1207 committed Aug 2, 2024
commit d9a2a7a1e8fdeb0425da78078de00c0dea60effb
20 changes: 17 additions & 3 deletions cps/editbooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,6 @@ def get_sorted_entry(field, bookid):
return json.dumps({'authors': " & ".join([a.name for a in calibre_db.order_authors([book])])})
return ""


@editbook.route("/ajax/simulatemerge", methods=['POST'])
@user_login_required
@edit_required
Expand All @@ -488,10 +487,10 @@ def simulate_merge_list_book():
return json.dumps({'to': to_book, 'from': from_book})
return ""

@editbook.route("/ajax/simulatedeleteselectedbooks", methods=['POST'])
@editbook.route("/ajax/displayselectedbooks", methods=['POST'])
@user_login_required
@edit_required
def simulate_delete_selected_books():
def display_selected_books():
vals = request.get_json().get('selections')
books = []
if vals:
Expand All @@ -500,6 +499,21 @@ def simulate_delete_selected_books():
return json.dumps({'books': books})
return ""

@editbook.route("/ajax/archiveselectedbooks", methods=['POST'])
@login_required_if_no_ano
@edit_required
def archive_selected_books():
vals = request.get_json().get('selections')
state = request.get_json().get('archive')
if vals:
for book_id in vals:
is_archived = change_archived_books(book_id, state,
message="Book {} archive bit set to: {}".format(book_id, state))
if is_archived:
kobo_sync_status.remove_synced_book(book_id)
return json.dumps({'success': True})
return ""

@editbook.route("/ajax/deleteselectedbooks", methods=['POST'])
@user_login_required
@edit_required
Expand Down
90 changes: 86 additions & 4 deletions cps/static/js/table.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,21 @@ $(function() {
if (selections.length >= 1) {
$("#delete_selected_books").removeClass("disabled");
$("#delete_selected_books").attr("aria-disabled", false);

$("#archive_selected_books").removeClass("disabled");
$("#archive_selected_books").attr("aria-disabled", false);

$("#unarchive_selected_books").removeClass("disabled");
$("#unarchive_selected_books").attr("aria-disabled", false);
} else {
$("#delete_selected_books").addClass("disabled");
$("#delete_selected_books").attr("aria-disabled", true);

$("#archive_selected_books").addClass("disabled");
$("#archive_selected_books").attr("aria-disabled", true);

$("#unarchive_selected_books").addClass("disabled");
$("#unarchive_selected_books").attr("aria-disabled", true);
}
if (selections.length < 1) {
$("#delete_selection").addClass("disabled");
Expand Down Expand Up @@ -143,6 +154,78 @@ $(function() {
});
});

$("#archive_selected_books").click(function(event) {
if ($(this).hasClass("disabled")) {
event.stopPropagation()
} else {
$('#archive_selected_modal').modal("show");
}
$.ajax({
method:"post",
contentType: "application/json; charset=utf-8",
dataType: "json",
url: window.location.pathname + "/../ajax/displayselectedbooks",
data: JSON.stringify({"selections":selections}),
success: function success(booTitles) {
$('#display-archive-selected-books').empty();
$.each(booTitles.books, function(i, item) {
$("<span>- " + item + "</span><p></p>").appendTo("#display-archive-selected-books");
});

}
});
});

$("#archive_selected_confirm").click(function(event) {
$.ajax({
method:"post",
contentType: "application/json; charset=utf-8",
dataType: "json",
url: window.location.pathname + "/../ajax/archiveselectedbooks",
data: JSON.stringify({"selections":selections, "archive": true}),
success: function success(booTitles) {
$("#books-table").bootstrapTable("refresh");
$("#books-table").bootstrapTable("uncheckAll");
}
});
});

$("#unarchive_selected_books").click(function(event) {
if ($(this).hasClass("disabled")) {
event.stopPropagation()
} else {
$('#unarchive_selected_modal').modal("show");
}
$.ajax({
method:"post",
contentType: "application/json; charset=utf-8",
dataType: "json",
url: window.location.pathname + "/../ajax/displayselectedbooks",
data: JSON.stringify({"selections":selections}),
success: function success(booTitles) {
$('#display-unarchive-selected-books').empty();
$.each(booTitles.books, function(i, item) {
$("<span>- " + item + "</span><p></p>").appendTo("#display-unarchive-selected-books");
});

}
});
});

$("#unarchive_selected_confirm").click(function(event) {
$.ajax({
method:"post",
contentType: "application/json; charset=utf-8",
dataType: "json",
url: window.location.pathname + "/../ajax/archiveselectedbooks",
data: JSON.stringify({"selections":selections, "archive": false}),
success: function success(booTitles) {
$("#books-table").bootstrapTable("refresh");
$("#books-table").bootstrapTable("uncheckAll");
}
});
});

$("#delete_selected_books").click(function(event) {
if ($(this).hasClass("disabled")) {
event.stopPropagation()
Expand All @@ -153,12 +236,12 @@ $(function() {
method:"post",
contentType: "application/json; charset=utf-8",
dataType: "json",
url: window.location.pathname + "/../ajax/simulatedeleteselectedbooks",
url: window.location.pathname + "/../ajax/displayselectedbooks",
data: JSON.stringify({"selections":selections}),
success: function success(booTitles) {
$('#selected-books').empty();
$('#display-delete-selected-books').empty();
$.each(booTitles.books, function(i, item) {
$("<span>- " + item + "</span><p></p>").appendTo("#selected-books");
$("<span>- " + item + "</span><p></p>").appendTo("#display-delete-selected-books");
});

}
Expand Down Expand Up @@ -895,7 +978,6 @@ function BookCheckboxChange(checkbox, userId, field) {
});
}


function selectHeader(element, field) {
if (element.value !== "None") {
confirmDialog(element.id, "GeneralChangeModal", 0, function () {
Expand Down
48 changes: 46 additions & 2 deletions cps/templates/book_table.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ <h2 class="{{page}}">{{_(title)}}</h2>
<div class="row form-group">
<div class="btn btn-default disabled" id="merge_books" aria-disabled="true">{{_('Merge selected books')}}</div>
<div class="btn btn-default disabled" id="delete_selected_books" aria-disabled="true">{{_('Delete selected books')}}</div>
<div class="btn btn-default disabled" id="archive_selected_books" aria-disabled="true">{{_('Archive selected books')}}</div>
<div class="btn btn-default disabled" id="unarchive_selected_books" aria-disabled="true">{{_('Unarchive selected books')}}</div>
<div class="btn btn-default disabled" id="delete_selection" aria-disabled="true">{{_('Remove Selections')}}</div>
</div>
<div class="row form-group">
Expand Down Expand Up @@ -103,6 +105,7 @@ <h2 class="{{page}}">{{_(title)}}</h2>
</tr>
</thead>
</table>

{% endblock %}
{% block modal %}
{{ delete_book(current_user.role_delete_books()) }}
Expand Down Expand Up @@ -141,17 +144,58 @@ <h2 class="{{page}}">{{_(title)}}</h2>
<p></p>
<div class="text-left">{{_('The following books will be deleted:')}}</div>
<p></p>
<div class="text-left" id="selected-books"></div>
<div class="text-left" id="display-delete-selected-books"></div>
<div class="modal-footer">
<input id="delete_selected_confirm" type="button" class="btn btn-danger" value="{{_('Delete')}}" name="delete_selected_confirm" id="delete_selected_confirm" data-dismiss="modal">
<button id="delete_selected_abort" type="button" class="btn btn-default" data-dismiss="modal">{{_('Cancel')}}</button>
</div>
</div>
</div>
</div>
</div>

<div class="modal fade" id="archive_selected_modal" role="dialog" aria-labelledby="metaArchiveSelectedLabel">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-danger text-center">
<span>{{_('Are you really sure?')}}</span>
</div>
<div class="modal-body">
<p></p>
<div class="text-left">{{_('The following books will be archived:')}}</div>
<p></p>
<div class="text-left" id="display-archive-selected-books"></div>
<div class="modal-footer">
<input id="archive_selected_confirm" type="button" class="btn btn-danger" value="{{_('Archive')}}" name="archive_selected_confirm" id="archive_selected_confirm" data-dismiss="modal">
<button id="archive_selected_abort" type="button" class="btn btn-default" data-dismiss="modal">{{_('Cancel')}}</button>
</div>
</div>
</div>
</div>
</div>
{% endif %}

<div class="modal fade" id="unarchive_selected_modal" role="dialog" aria-labelledby="metaUnArchiveSelectedLabel">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-danger text-center">
<span>{{_('Are you really sure?')}}</span>
</div>
<div class="modal-body">
<p></p>
<div class="text-left">{{_('The following books will be unarchived:')}}</div>
<p></p>
<div class="text-left" id="display-unarchive-selected-books"></div>
<div class="modal-footer">
<input id="unarchive_selected_confirm" type="button" class="btn btn-danger" value="{{_('Archive')}}" name="unarchive_selected_confirm" id="unarchive_selected_confirm" data-dismiss="modal">
<button id="unarchive_selected_abort" type="button" class="btn btn-default" data-dismiss="modal">{{_('Cancel')}}</button>
</div>
</div>
</div>
</div>
</div>
{% endif %}
{% endblock %}

{% block js %}
<script src="{{ url_for('static', filename='js/libs/bootstrap-table/bootstrap-table.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/libs/bootstrap-table/bootstrap-table-locale-all.min.js') }}"></script>
Expand Down