149 lines
No EOL
5.8 KiB
Python
149 lines
No EOL
5.8 KiB
Python
from flask import Blueprint, render_template, abort, request
|
|
|
|
import crudkit
|
|
|
|
from crudkit.api._cursor import decode_cursor, encode_cursor
|
|
from crudkit.ui.fragments import render_table, register_template_globals
|
|
|
|
bp_listing = Blueprint("listing", __name__)
|
|
|
|
def init_listing_routes(app):
|
|
# Make helpers available in all templates
|
|
register_template_globals(app)
|
|
|
|
@bp_listing.get("/listing/<model>")
|
|
def show_list(model):
|
|
if model.lower() not in {"inventory", "user", "worklog"}:
|
|
abort(404)
|
|
|
|
cls = crudkit.crud.get_model(model)
|
|
if cls is None:
|
|
abort(404)
|
|
|
|
# read query args
|
|
limit = request.args.get("limit", None)
|
|
limit = int(limit) if (limit is not None and str(limit).isdigit()) else 15
|
|
sort = request.args.get("sort")
|
|
fields_qs = request.args.get("fields")
|
|
cursor = request.args.get("cursor")
|
|
key, _desc, backward = decode_cursor(cursor)
|
|
|
|
# base spec per model
|
|
spec = {}
|
|
columns = []
|
|
row_classes = []
|
|
if model.lower() == 'inventory':
|
|
spec = {"fields": [
|
|
"label",
|
|
"name",
|
|
"barcode",
|
|
"serial",
|
|
"brand.name",
|
|
"model",
|
|
"device_type.description",
|
|
"condition",
|
|
"owner.label",
|
|
"location.label",
|
|
]}
|
|
columns = [
|
|
{"field": "label"},
|
|
{"field": "name"},
|
|
{"field": "barcode", "label": "Barcode #"},
|
|
{"field": "serial", "label": "Serial #"},
|
|
{"field": "brand.name", "label": "Brand"},
|
|
{"field": "model"},
|
|
{"field": "device_type.description", "label": "Device Type"},
|
|
{"field": "condition"},
|
|
{"field": "owner.label", "label": "Contact",
|
|
"link": {"endpoint": "entry.entry", "params": {"id": "{owner.id}", "model": "user"}}},
|
|
{"field": "location.label", "label": "Room"},
|
|
]
|
|
elif model.lower() == 'user':
|
|
spec = {"fields": [
|
|
"label",
|
|
"last_name",
|
|
"first_name",
|
|
"supervisor.label",
|
|
"robot.overlord",
|
|
"staff",
|
|
"active",
|
|
], "sort": "first_name,last_name"} # default for users
|
|
columns = [
|
|
{"field": "label", "label": "Full Name"},
|
|
{"field": "last_name"},
|
|
{"field": "first_name"},
|
|
{"field": "supervisor.label", "label": "Supervisor",
|
|
"link": {"endpoint": "entry.entry", "params": {"id": "{supervisor.id}", "model": "user"}}},
|
|
{"field": "staff", "format": "yesno"},
|
|
{"field": "active", "format": "yesno"},
|
|
]
|
|
row_classes = [
|
|
{"when": {"field": "active", "is": False}, "class": "table-secondary"},
|
|
{"when": {"all": [
|
|
{"field": "staff", "is": False},
|
|
{"field": "active", "is": True}
|
|
]}, "class": "table-success"},
|
|
]
|
|
elif model.lower() == 'worklog':
|
|
spec = {"fields": [
|
|
"work_item.label",
|
|
"contact.label",
|
|
"start_time",
|
|
"end_time",
|
|
"complete",
|
|
]}
|
|
columns = [
|
|
{"field": "work_item.label", "label": "Work Item",
|
|
"link": {"endpoint": "entry.entry", "params": {"id": "{work_item.id}", "model": "inventory"}}},
|
|
{"field": "contact.label", "label": "Contact",
|
|
"link": {"endpoint": "entry.entry", "params": {"id": "{contact.id}", "model": "user"}}},
|
|
{"field": "start_time", "format": "datetime"},
|
|
{"field": "end_time", "format": "datetime"},
|
|
{"field": "complete", "format": "yesno"},
|
|
]
|
|
row_classes = [
|
|
{"when": {"field": "complete", "is": True}, "class": "table-success"},
|
|
{"when": {"field": "complete", "is": False}, "class": "table-danger"}
|
|
]
|
|
|
|
# Build params to feed CRUDService (flat dict; parse_filters expects flat keys)
|
|
params = dict(spec)
|
|
|
|
# overlay fields from query (?fields=...)
|
|
if fields_qs:
|
|
params["fields"] = [p.strip() for p in fields_qs.split(",") if p.strip()]
|
|
|
|
# overlay sort from query (?sort=...)
|
|
if sort:
|
|
params["sort"] = sort
|
|
|
|
# limit semantics: 0 means "unlimited" in your service layer
|
|
params["limit"] = limit
|
|
|
|
# forward *all other* query params as filters (flat), excluding known control keys
|
|
CONTROL_KEYS = {"limit", "cursor", "sort", "fields"}
|
|
for k, v in request.args.items():
|
|
if k in CONTROL_KEYS:
|
|
continue
|
|
if v is None or v == "":
|
|
continue
|
|
params[k] = v
|
|
|
|
service = crudkit.crud.get_service(cls)
|
|
|
|
window = service.seek_window(params, key=key, backward=backward, include_total=True)
|
|
|
|
table = render_table(window.items, columns=columns,
|
|
opts={"object_class": model, "row_classes": row_classes})
|
|
|
|
pagination_ctx = {
|
|
"limit": window.limit,
|
|
"total": window.total,
|
|
"next_cursor": encode_cursor(window.last_key, list(window.order.desc), backward=False),
|
|
"prev_cursor": encode_cursor(window.first_key, list(window.order.desc), backward=True),
|
|
"sort": params.get("sort") # expose current sort to the template
|
|
}
|
|
|
|
return render_template("listing.html", model=model, table=table, pagination=pagination_ctx)
|
|
|
|
app.register_blueprint(bp_listing) |