Polish mobile shopping rows and stabilize backup archives

This commit is contained in:
2026-04-16 15:31:52 +02:00
parent 5e9beb1d98
commit 43fdd7081c
3 changed files with 81 additions and 10 deletions
+15 -3
View File
@@ -52,13 +52,25 @@ def export_backup_archive(
payload["tables"][table_name] = [dict(row) for row in rows] payload["tables"][table_name] = [dict(row) for row in rows]
uploads_root = Path(upload_folder) uploads_root = Path(upload_folder)
with zipfile.ZipFile(archive_path, "w", compression=zipfile.ZIP_DEFLATED) as archive: uploads_snapshot_dir = Path(tempfile.mkdtemp(prefix="nouri-backup-uploads-"))
archive.writestr("backup.json", json.dumps(payload, ensure_ascii=False, indent=2)) try:
if uploads_root.exists(): if uploads_root.exists():
for file_path in uploads_root.rglob("*"): for file_path in uploads_root.rglob("*"):
if file_path.is_file(): if not file_path.is_file():
continue
relative_path = file_path.relative_to(uploads_root) relative_path = file_path.relative_to(uploads_root)
snapshot_path = uploads_snapshot_dir / relative_path
snapshot_path.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(file_path, snapshot_path)
with zipfile.ZipFile(archive_path, "w", compression=zipfile.ZIP_DEFLATED) as archive:
archive.writestr("backup.json", json.dumps(payload, ensure_ascii=False, indent=2))
for file_path in uploads_snapshot_dir.rglob("*"):
if file_path.is_file():
relative_path = file_path.relative_to(uploads_snapshot_dir)
archive.write(file_path, f"uploads/{relative_path.as_posix()}") archive.write(file_path, f"uploads/{relative_path.as_posix()}")
finally:
shutil.rmtree(uploads_snapshot_dir, ignore_errors=True)
return archive_path, backup_name return archive_path, backup_name
+62 -6
View File
@@ -1356,6 +1356,18 @@ h3 {
white-space: nowrap; white-space: nowrap;
} }
.shopping-entry-check-button {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
}
.shopping-entry-check-mark {
font-size: 1rem;
line-height: 1;
}
.shopping-entry-close-form { .shopping-entry-close-form {
flex: 0 0 auto; flex: 0 0 auto;
margin: 0; margin: 0;
@@ -1415,24 +1427,68 @@ h3 {
@media (max-width: 680px) { @media (max-width: 680px) {
.shopping-entry-row { .shopping-entry-row {
align-items: stretch; display: grid;
flex-direction: column; grid-template-columns: minmax(0, 1fr) auto auto;
align-items: center;
gap: 0.7rem;
} }
.shopping-entry-open { .shopping-entry-open {
width: 100%; min-width: 0;
}
.shopping-entry-main {
grid-template-columns: 56px minmax(0, 1fr);
gap: 0.8rem;
align-items: center;
}
.shopping-entry-visual,
.shopping-entry-fallback {
width: 56px;
height: 56px;
border-radius: 16px;
}
.shopping-entry-copy {
gap: 0.12rem;
}
.shopping-entry-copy strong {
font-size: 1rem;
}
.shopping-entry-copy .muted {
display: none;
} }
.shopping-entry-actions, .shopping-entry-actions,
.shopping-entry-actions form, .shopping-entry-actions form,
.shopping-entry-actions button, .shopping-entry-actions button,
.shopping-entry-close-form { .shopping-entry-close-form {
width: 100%; width: auto;
}
.shopping-entry-check-button {
min-width: 0;
padding: 0.75rem 0.9rem;
border-radius: 16px;
gap: 0;
}
.shopping-entry-check-label {
display: none;
}
.shopping-entry-check-mark {
font-size: 1.05rem;
} }
.shopping-entry-close { .shopping-entry-close {
width: 100%; width: 2.75rem;
border-radius: 18px; height: 2.75rem;
min-width: 2.75rem;
border-radius: 16px;
} }
} }
+4 -1
View File
@@ -131,7 +131,10 @@
<div class="shopping-entry-actions"> <div class="shopping-entry-actions">
<form method="post" action="{{ url_for('main.shopping_check', entry_id=entry.id) }}"> <form method="post" action="{{ url_for('main.shopping_check', entry_id=entry.id) }}">
{{ csrf_input() }} {{ csrf_input() }}
<button type="submit">Eingekauft</button> <button type="submit" class="shopping-entry-check-button">
<span class="shopping-entry-check-mark" aria-hidden="true"></span>
<span class="shopping-entry-check-label">Eingekauft</span>
</button>
</form> </form>
</div> </div>
{% if entry.can_edit %} {% if entry.can_edit %}