fix: persist quick win reorder changes

This commit is contained in:
2026-04-15 13:34:12 +02:00
parent 25459216bc
commit ce7a371caf
4 changed files with 26 additions and 31 deletions

View File

@@ -351,13 +351,18 @@ Der ausgegebene `VAPID_PRIVATE_KEY` ist bereits `.env`-freundlich mit escaped Ne
- Quick-Wins als gemeinsames Team-Feature ausgebaut
- neuer Optionen-Tab zum Anlegen und Verwalten gemeinsamer Quick-Wins
- bestehende Quick-Wins in den Optionen direkt bearbeitbar gemacht
- Quick-Win-Reihenfolge per Drag & Drop ergänzt und Speichern der Sortierung in den Optionen stabilisiert
- Plus-Dialog von Einzelkarten auf kompakte auswählbare Quick-Win-Chips umgestellt
- mehrere Quick-Wins lassen sich gesammelt als erledigt speichern
- „Sonstiges“ blendet Titel und Aufwand jetzt nur bei Auswahl ein
- neue Aufwand-Stufe `super aufwendig`
- Quick-Win-Popup visuell mit übernommenem Sparkles-Icon aus `heinz.marketing` aufgewertet
- gemeinsame Aufgaben für zwei Personen mit halbierten Punkten pro Person ergänzt
- Aufgabenstatus in `morgen fällig`, `übermorgen fällig` und `bald fällig` feiner aufgeteilt
- Aufgaben können jetzt von allen Nutzern direkt gelöscht werden
- Kalenderdarstellung für lange deutsche Begriffe und Namen bei der Worttrennung nachgeschärft
- deutsche Silbentrennung serverseitig vorbereitet, mit optionalem `pyphen`-Fallback ohne Startfehler im lokalen Dev-Setup
- mobile Layouts für Aufgabenkarten, Bearbeiten-Ansicht und Quick-Win-Verwaltung weiter verdichtet und ausgerichtet
- Footer auf Versionslink, Herkunftshinweis und `hnz.io`-Verweis umgebaut
- Cloudron-Version auf `0.6.5` angehoben

View File

@@ -274,8 +274,11 @@ def update_quick_win(quick_win_id: int):
@login_required
@csrf.exempt
def reorder_quick_wins():
payload = request.get_json(silent=True) or {}
raw_ids = payload.get("ids", [])
payload = request.get_json(silent=True)
if payload is not None:
raw_ids = payload.get("ids", [])
else:
raw_ids = request.form.get("ids", "").split(",")
ordered_ids = [int(item) for item in raw_ids if str(item).isdigit()]
quick_wins = QuickWin.query.filter_by(active=True).all()
@@ -292,7 +295,11 @@ def reorder_quick_wins():
quick_win.sort_order = offset
db.session.commit()
return jsonify({"ok": True})
if payload is not None:
return jsonify({"ok": True})
flash("Die Quick-Win-Reihenfolge wurde gespeichert.", "success")
return redirect(url_for("settings.quick_wins"))
@bp.route("/users/<int:user_id>/toggle-admin", methods=["POST"])

View File

@@ -17,7 +17,7 @@
const currentUserId = document.body.dataset.currentUserId;
const currentUserName = document.body.dataset.currentUserName;
const quickWinSortList = document.querySelector("[data-quick-win-sort-list]");
const quickWinSortToken = document.getElementById("quickWinSortToken");
const quickWinSortIds = document.getElementById("quickWinSortIds");
const quickWinSortSave = document.getElementById("quickWinSortSave");
const quickWinToggleButtons = document.querySelectorAll("[data-quick-win-toggle]");
let draggedQuickWin = null;
@@ -123,22 +123,14 @@
});
}
async function persistQuickWinSort() {
if (!quickWinSortList || !quickWinSortToken) {
function syncQuickWinSortIds() {
if (!quickWinSortList || !quickWinSortIds) {
return;
}
const ids = [...quickWinSortList.querySelectorAll("[data-quick-win-sort-item]")]
.map((item) => item.dataset.quickWinSortItem)
.filter(Boolean);
await fetch("/settings/quick-wins/reorder", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": quickWinSortToken.value,
},
body: JSON.stringify({ ids }),
});
quickWinSortIds.value = ids.join(",");
}
function setQuickWinSortDirty(isDirty) {
@@ -149,6 +141,7 @@
}
if (quickWinSortList) {
syncQuickWinSortIds();
setQuickWinSortDirty(false);
quickWinSortList.querySelectorAll("[data-quick-win-sort-item]").forEach((item) => {
@@ -180,25 +173,12 @@
} else {
item.before(draggedQuickWin);
}
syncQuickWinSortIds();
setQuickWinSortDirty(true);
});
});
}
if (quickWinSortSave) {
quickWinSortSave.addEventListener("click", async () => {
if (!quickWinSortDirty) {
return;
}
try {
await persistQuickWinSort();
setQuickWinSortDirty(false);
} catch (error) {
console.error("Quick-Win-Sortierung konnte nicht gespeichert werden", error);
}
});
}
quickWinToggleButtons.forEach((button) => {
button.addEventListener("click", () => {
const targetId = button.dataset.target;

View File

@@ -37,9 +37,12 @@
<p class="eyebrow">Direkt sichtbar</p>
<h2>Aktive Quick-Wins bearbeiten</h2>
<p class="muted">Per Drag & Drop kannst du die Reihenfolge festlegen, die später auch bei den Quick-Win-Chips erscheint.</p>
<input type="hidden" id="quickWinSortToken" value="{{ csrf_token() }}">
<form method="post" action="{{ url_for('settings.reorder_quick_wins') }}" id="quickWinSortForm">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input type="hidden" name="ids" id="quickWinSortIds" value="{{ quick_wins|map(attribute='id')|join(',') }}">
</form>
<div class="quick-win-list__toolbar">
<button type="button" class="button button--secondary" id="quickWinSortSave" disabled>Reihenfolge speichern</button>
<button type="submit" class="button button--secondary" id="quickWinSortSave" form="quickWinSortForm" disabled>Reihenfolge speichern</button>
</div>
<div class="quick-win-list" data-quick-win-sort-list>
{% for quick_win in quick_wins %}