paginacja i poprawki uxowe

This commit is contained in:
Mateusz Gruszczyński
2025-08-15 10:01:05 +02:00
parent 4f40bb06b3
commit b61c262179
7 changed files with 200 additions and 90 deletions

103
app.py
View File

@@ -2447,21 +2447,21 @@ def delete_user(user_id):
@admin_required
def admin_receipts(id):
try:
page = request.args.get("page", 1, type=int)
per_page = request.args.get("per_page", 24, type=int)
per_page = max(1, min(per_page, 200)) # sanity check
if id == "all":
all_filenames = {r.filename for r in Receipt.query.all()}
per_page = 24
page = request.args.get("page", 1, type=int)
total_count = Receipt.query.count()
total_pages = (total_count + per_page - 1) // per_page
receipts_paginated = (
pagination = (
Receipt.query.order_by(Receipt.uploaded_at.desc())
.offset((page - 1) * per_page)
.limit(per_page)
.all()
.paginate(page=page, per_page=per_page, error_out=False)
)
receipts_paginated = pagination.items
total_pages = pagination.pages
upload_folder = app.config["UPLOAD_FOLDER"]
files_on_disk = set(os.listdir(upload_folder))
orphan_files = [
@@ -2471,7 +2471,6 @@ def admin_receipts(id):
and f not in all_filenames
and f.startswith("list_")
]
else:
list_id = int(id)
receipts_paginated = (
@@ -2482,13 +2481,12 @@ def admin_receipts(id):
orphan_files = []
page = 1
total_pages = 1
per_page = len(receipts_paginated) or 1
except ValueError:
flash("Nieprawidłowe ID listy.", "danger")
return redirect(url_for("admin_panel"))
args_without_page = request.args.to_dict()
args_without_page.pop("page", None)
query_string = urlencode(args_without_page)
query_string = urlencode({k: v for k, v in request.args.items() if k != "page"})
return render_template(
"admin/receipts.html",
@@ -2496,6 +2494,7 @@ def admin_receipts(id):
orphan_files=orphan_files,
orphan_files_count=len(orphan_files),
page=page,
per_page=per_page,
total_pages=total_pages,
id=id,
query_string=query_string,
@@ -2834,10 +2833,17 @@ def edit_list(list_id):
@login_required
@admin_required
def list_products():
items = Item.query.options(
page = request.args.get("page", 1, type=int)
per_page = request.args.get("per_page", 125, type=int)
per_page = max(1, min(per_page, 300))
items_query = Item.query.options(
joinedload(Item.shopping_list),
joinedload(Item.added_by_user),
).order_by(Item.id.desc()).all()
).order_by(Item.id.desc())
pagination = items_query.paginate(page=page, per_page=per_page, error_out=False)
items = pagination.items
users = User.query.all()
users_dict = {user.id: user.username for user in users}
@@ -2847,19 +2853,7 @@ def list_products():
(s.name or "").strip().lower(): s for s in suggestions if s.name and s.name.strip()
}
seen_names = set()
unique_items = []
used_suggestion_names = set()
for item in items:
normalized_name = (item.name or "").strip().lower()
if not normalized_name:
continue
if normalized_name not in seen_names:
seen_names.add(normalized_name)
unique_items.append(item)
used_suggestion_names.add(normalized_name)
used_suggestion_names = {(item.name or "").strip().lower() for item in items if item.name}
orphan_suggestions = [
s for s in suggestions
if (s.name or "").strip().lower() not in used_suggestion_names and (s.name or "").strip()
@@ -2871,12 +2865,18 @@ def list_products():
if name in all_suggestions_dict
}
query_string = urlencode({k: v for k, v in request.args.items() if k != "page"})
return render_template(
"admin/list_products.html",
items=unique_items,
items=items,
users_dict=users_dict,
suggestions_dict=suggestions_dict,
orphan_suggestions=orphan_suggestions,
page=page,
per_page=per_page,
total_pages=pagination.pages,
query_string=query_string,
)
@@ -2981,19 +2981,23 @@ def recalculate_filesizes_all():
return redirect(url_for("admin_receipts", id="all"))
@app.route("/admin/mass_edit_categories", methods=["GET", "POST"])
@login_required
@admin_required
def admin_mass_edit_categories():
lists = (
ShoppingList.query.options(
joinedload(ShoppingList.categories),
joinedload(ShoppingList.items),
joinedload(ShoppingList.owner),
)
.order_by(ShoppingList.created_at.desc())
.all()
)
page = request.args.get("page", 1, type=int)
per_page = request.args.get("per_page", 50, type=int)
per_page = max(1, min(per_page, 200)) # ogranicz do sensownych wartości
lists_query = ShoppingList.query.options(
joinedload(ShoppingList.categories),
joinedload(ShoppingList.items),
joinedload(ShoppingList.owner),
).order_by(ShoppingList.created_at.desc())
pagination = lists_query.paginate(page=page, per_page=per_page, error_out=False)
lists = pagination.items
categories = Category.query.order_by(Category.name.asc()).all()
@@ -3011,12 +3015,19 @@ def admin_mass_edit_categories():
l.categories.extend(cats)
db.session.commit()
flash("Zaktualizowano kategorie dla wybranych list", "success")
return redirect(url_for("admin_mass_edit_categories"))
return redirect(url_for("admin_mass_edit_categories", page=page, per_page=per_page))
query_string = urlencode({k: v for k, v in request.args.items() if k != "page"})
return render_template(
"admin/mass_edit_categories.html",
lists=lists,
categories=categories
categories=categories,
page=page,
per_page=per_page,
total_pages=pagination.pages,
total_items=pagination.total,
query_string=query_string,
)
@@ -3038,7 +3049,17 @@ def admin_list_items_json(list_id):
for item in l.items
]
return jsonify({"title": l.title, "items": items})
purchased_count = sum(1 for item in l.items if item.purchased)
total_expense = sum(exp.amount for exp in l.expenses)
return jsonify({
"title": l.title,
"items": items,
"total_count": len(l.items),
"purchased_count": purchased_count,
"total_expense": round(total_expense, 2)
})
@app.route("/healthcheck")