Allow ordering packages in collections

This commit is contained in:
rubenwardy 2023-08-20 22:51:21 +01:00
parent 4bd53e4b1a
commit e5e68826fb
4 changed files with 59 additions and 25 deletions

@ -84,6 +84,7 @@ class CollectionForm(FlaskForm):
min_entries=0) min_entries=0)
package_ids = FieldList(HiddenField(), min_entries=0) package_ids = FieldList(HiddenField(), min_entries=0)
package_removed = FieldList(HiddenField(), min_entries=0) package_removed = FieldList(HiddenField(), min_entries=0)
order = HiddenField()
submit = SubmitField(lazy_gettext("Save")) submit = SubmitField(lazy_gettext("Save"))
@ -178,7 +179,10 @@ def handle_create_edit(collection: Collection, form: CollectionForm,
form.populate_obj(collection) form.populate_obj(collection)
collection.name = name collection.name = name
order = 1 item_lookup = {}
for link in collection.items:
item_lookup[link.package.get_id()] = link
for i, package_id in enumerate(form.package_ids): for i, package_id in enumerate(form.package_ids):
link = next((x for x in collection.items if str(x.package.get_id()) == package_id.data), None) link = next((x for x in collection.items if str(x.package.get_id()) == package_id.data), None)
to_delete = form.package_removed[i].data == "1" to_delete = form.package_removed[i].data == "1"
@ -194,15 +198,15 @@ def handle_create_edit(collection: Collection, form: CollectionForm,
link.package = package link.package = package
link.collection = collection link.collection = collection
link.description = form.descriptions[i].data link.description = form.descriptions[i].data
link.order = order item_lookup[link.package.get_id()] = link
order += 1
db.session.add(link) db.session.add(link)
elif to_delete: elif to_delete:
db.session.delete(link) db.session.delete(link)
else: else:
link.description = form.descriptions[i].data link.description = form.descriptions[i].data
link.order = order
order += 1 for i, package_id in enumerate(form.order.data.split(",")):
item_lookup[package_id].order = i + 1
add_audit_log(severity, current_user, add_audit_log(severity, current_user,
f"Edited collection {collection.author.username}/{collection.name}", f"Edited collection {collection.author.username}/{collection.name}",

@ -57,7 +57,7 @@ class Collection(db.Model):
private = db.Column(db.Boolean, nullable=False, default=False) private = db.Column(db.Boolean, nullable=False, default=False)
packages = db.relationship("Package", secondary=CollectionPackage.__table__, backref="collections") packages = db.relationship("Package", secondary=CollectionPackage.__table__, backref="collections")
items = db.relationship("CollectionPackage", back_populates="collection", order_by=db.asc("created_at"), items = db.relationship("CollectionPackage", back_populates="collection", order_by=db.asc("order"),
cascade="all, delete, delete-orphan") cascade="all, delete, delete-orphan")
collection_name_valid = db.CheckConstraint("name ~* '^[a-z0-9_]+$' AND name != '_game'") collection_name_valid = db.CheckConstraint("name ~* '^[a-z0-9_]+$' AND name != '_game'")

@ -2,6 +2,18 @@
// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3-or-Later // @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3-or-Later
function updateOrder() {
const elements = [...document.querySelector(".sortable").children];
const ids = elements
.filter(x => !x.classList.contains("d-none"))
.map(x => x.dataset.id)
.filter(x => x);
console.log(ids);
document.querySelector("input[name='order']").value = ids.join(",");
}
function removePackage(card) { function removePackage(card) {
const message = document.getElementById("confirm_delete").innerText.trim(); const message = document.getElementById("confirm_delete").innerText.trim();
const title = card.querySelector("h5 a").innerText.trim(); const title = card.querySelector("h5 a").innerText.trim();
@ -12,6 +24,7 @@ function removePackage(card) {
card.querySelector("input[name^=package_removed]").value = "1"; card.querySelector("input[name^=package_removed]").value = "1";
card.classList.add("d-none"); card.classList.add("d-none");
onPackageQueryUpdate(); onPackageQueryUpdate();
updateOrder();
} }
@ -26,6 +39,7 @@ function restorePackage(id) {
card.querySelector("input[name^=package_removed]").value = "0"; card.querySelector("input[name^=package_removed]").value = "0";
card.scrollIntoView(); card.scrollIntoView();
onPackageQueryUpdate(); onPackageQueryUpdate();
updateOrder();
return true; return true;
} }
@ -59,7 +73,7 @@ function addPackage(pkg) {
const url = `/packages/${id}/`; const url = `/packages/${id}/`;
const temp = document.createElement("div"); const temp = document.createElement("div");
temp.innerHTML = ` temp.innerHTML = `
<article class="card my-3"> <article class="card my-3" data-id="${escapeHtml(id)}">
<div class="card-body"> <div class="card-body">
<button class="btn btn-sm btn-danger remove-package float-right" type="button" aria-label="Remove"> <button class="btn btn-sm btn-danger remove-package float-right" type="button" aria-label="Remove">
<i class="fas fa-trash"></i> <i class="fas fa-trash"></i>
@ -90,6 +104,8 @@ function addPackage(pkg) {
const button = card.querySelector(".btn-danger"); const button = card.querySelector(".btn-danger");
button.addEventListener("click", () => removePackage(card)); button.addEventListener("click", () => removePackage(card));
updateOrder();
} }
@ -169,4 +185,9 @@ window.onload = () => {
addPackageQuery.value = ""; addPackageQuery.value = "";
addPackageQuery.classList.remove("d-none"); addPackageQuery.classList.remove("d-none");
addPackageQuery.addEventListener("input", onPackageQueryUpdate); addPackageQuery.addEventListener("input", onPackageQueryUpdate);
updateOrder();
$(".sortable").sortable({
update: updateOrder,
});
}; };

@ -9,7 +9,8 @@
{% endblock %} {% endblock %}
{% block scriptextra %} {% block scriptextra %}
<script src="/static/collection_editor.js?v=4"></script> <script src="/static/libs/jquery-ui.min.js"></script>
<script src="/static/collection_editor.js?v=5"></script>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
@ -45,30 +46,38 @@
</p> </p>
<div id="add_package_results" class="list-group"></div> <div id="add_package_results" class="list-group"></div>
</div> </div>
<div id="package_list"> <div id="package_list" class="sortable">
{% for item in collection.items %} {% for item in collection.items %}
{% set package = item.package %} {% set package = item.package %}
<article class="card my-3"> <article class="card my-3" data-id="{{ package.get_id() }}">
<div class="card-body"> <div class="card-body">
<button class="btn btn-sm btn-danger remove-package float-right" <div class="row">
type="button" aria-label="{{ _('Remove') }}"> <div class="col-auto text-muted pr-2">
<i class="fas fa-trash"></i> <i class="fas fa-bars"></i>
</button> </div>
<h5> <div class="col">
<a href="{{ package.get_url('packages.view') }}" target="_blank"> <button class="btn btn-sm btn-danger remove-package float-right"
{{ _("%(title)s by %(author)s", title=package.title, author=package.author.display_name) }} type="button" aria-label="{{ _('Remove') }}">
</a> <i class="fas fa-trash"></i>
</h5> </button>
<p class="text-muted"> <h5>
{{ package.short_desc }} <a href="{{ package.get_url('packages.view') }}" target="_blank">
</p> {{ _("%(title)s by %(author)s", title=package.title, author=package.author.display_name) }}
{{ render_field(form.descriptions[loop.index - 1], hint=_("You can replace the description with your own")) }} </a>
{{ form.package_ids[loop.index - 1]() }} </h5>
{{ form.package_removed[loop.index - 1]() }} <p class="text-muted">
{{ package.short_desc }}
</p>
{{ render_field(form.descriptions[loop.index - 1], hint=_("You can replace the description with your own")) }}
{{ form.package_ids[loop.index - 1]() }}
{{ form.package_removed[loop.index - 1]() }}
</div>
</div>
</div> </div>
</article> </article>
{% endfor %} {% endfor %}
</div> </div>
{{ form.order() }}
{% endif %} {% endif %}
<div class="mt-5"> <div class="mt-5">