More entry code and some fixups.
This commit is contained in:
parent
2ae96e5c80
commit
d8e8790987
7 changed files with 233 additions and 57 deletions
|
|
@ -6,6 +6,8 @@ import crudkit
|
|||
|
||||
from crudkit.integrations.flask import init_app
|
||||
|
||||
from .debug_pretty import init_pretty
|
||||
|
||||
from .routes.index import init_index_routes
|
||||
from .routes.listing import init_listing_routes
|
||||
from .routes.entry import init_entry_routes
|
||||
|
|
@ -13,6 +15,8 @@ from .routes.entry import init_entry_routes
|
|||
def create_app(config_cls=crudkit.DevConfig) -> Flask:
|
||||
app = Flask(__name__)
|
||||
|
||||
init_pretty(app)
|
||||
|
||||
runtime = init_app(app, config=crudkit.ProdConfig)
|
||||
crudkit.init_crud(app)
|
||||
print(f"Effective DB URL: {str(runtime.engine.url)}")
|
||||
|
|
|
|||
31
inventory/debug_pretty.py
Normal file
31
inventory/debug_pretty.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
from flask import request
|
||||
from werkzeug.wrappers.response import Response
|
||||
|
||||
def init_pretty(app):
|
||||
@app.after_request
|
||||
def _pretty_html(resp: Response):
|
||||
if not app.debug:
|
||||
print("Not debugging.")
|
||||
return resp
|
||||
if resp.mimetype != "text/html":
|
||||
return resp
|
||||
if request.args.get("pretty") != "1":
|
||||
return resp
|
||||
|
||||
html = resp.get_data(as_text=True)
|
||||
try:
|
||||
# Prefer lxml if present; falls back to bs4
|
||||
from lxml import html as lhtml
|
||||
pretty = lhtml.tostring(
|
||||
lhtml.fromstring(html),
|
||||
encoding="unicode",
|
||||
method="html",
|
||||
pretty_print=True,
|
||||
)
|
||||
except Exception:
|
||||
from bs4 import BeautifulSoup
|
||||
pretty = BeautifulSoup(html, "html.parser").prettify(formatter="html")
|
||||
|
||||
resp.set_data(pretty)
|
||||
resp.headers["Content-Length"] = str(len(pretty.encode("utf-8")))
|
||||
return resp
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
from typing import List, Optional, TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Boolean, Integer, ForeignKey, Unicode, func
|
||||
from sqlalchemy import Boolean, Integer, ForeignKey, Unicode, case, func, literal
|
||||
from sqlalchemy.ext.hybrid import hybrid_property
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.sql import expression as sql
|
||||
|
|
@ -41,8 +41,25 @@ class User(Base, CRUDMixin):
|
|||
|
||||
@hybrid_property
|
||||
def label(self):
|
||||
return f"{self.first_name} {self.last_name}"
|
||||
out = f"{self.first_name} {self.last_name}"
|
||||
if self.title:
|
||||
out = out + f" ({self.title})"
|
||||
return out
|
||||
|
||||
@label.expression
|
||||
def label(cls):
|
||||
return func.concat(cls.first_name, " ", cls.last_name)
|
||||
first = func.coalesce(cls.first_name, "")
|
||||
last = func.coalesce(cls.last_name, "")
|
||||
title = func.coalesce(cls.title, "")
|
||||
|
||||
have_first = func.length(func.trim(first)) > 0
|
||||
have_last = func.length(func.trim(last)) > 0
|
||||
|
||||
space = case((have_first & have_last, literal(" ")), else_=literal(""))
|
||||
|
||||
title_part = case(
|
||||
(func.length(func.trim(title)) > 0, func.concat(" (", title, ")")),
|
||||
else_=literal("")
|
||||
)
|
||||
|
||||
return func.concat(first, space, last, title_part)
|
||||
|
|
|
|||
|
|
@ -21,35 +21,65 @@ def init_entry_routes(app):
|
|||
fields_spec = []
|
||||
layout = []
|
||||
if model == "inventory":
|
||||
fields["fields"] = ["label", "name", "barcode", "serial"]
|
||||
fields["fields"] = ["label", "name", "serial", "barcode", "brand", "model", "device_type", "owner", "location", "condition", "image"]
|
||||
fields_spec = [
|
||||
{"name": "label", "label": "", "row": "label", "wrap": {"class": "col"}},
|
||||
{"name": "name", "label": "Name", "row": "identification", "wrap": {"class": "col"}},
|
||||
{"name": "barcode", "label": "Bar Code #", "row": "identification", "wrap": {"class": "col"}},
|
||||
{"name": "serial", "label": "Serial #", "row": "identification", "wrap": {"class": "col"}},
|
||||
{"name": "label", "type": "display", "label": "",
|
||||
"label_attrs": {"class": "display-6 me-2"}, "row": "label",
|
||||
"attrs": {"class": "display-6 mb-3"}},
|
||||
|
||||
{"name": "name", "row": "names", "label": "Name", "wrap": {"class": "col-3"},
|
||||
"attrs": {"class": "form-control"}, "label_attrs": {"class": "form-label"}},
|
||||
{"name": "serial", "row": "names", "label": "Serial #", "wrap": {"class": "col"},
|
||||
"attrs": {"class": "form-control"}, "label_attrs": {"class": "form-label"}},
|
||||
{"name": "barcode", "row": "names", "label": "Barcode #", "wrap": {"class": "col"},
|
||||
"attrs": {"class": "form-control"}, "label_attrs": {"class": "form-label"}},
|
||||
|
||||
{"name": "brand", "label_spec": "{name}", "row": "device", "wrap": {"class": "col"},
|
||||
"attrs": {"class": "form-control"}, "label": "Brand", "label_attrs": {"class": "form-label"}},
|
||||
{"name": "model", "row": "device", "wrap": {"class": "col"}, "attrs": {"class": "form-control"},
|
||||
"label": "Model #", "label_attrs": {"class": "form-label"}},
|
||||
{"name": "device_type", "label_spec": "{description}", "row": "device", "wrap": {"class": "col"},
|
||||
"attrs": {"class": "form-control"}, "label": "Device Type", "label_attrs": {"class": "form-label"}},
|
||||
|
||||
{"name": "owner", "row": "status", "label": "Contact", "wrap": {"class": "col"},
|
||||
"attrs": {"class": "form-control"}, "label_attrs": {"class": "form-label"},
|
||||
"label_spec": "{first_name} {last_name}"},
|
||||
{"name": "location", "row": "status", "label": "Location", "wrap": {"class": "col"},
|
||||
"attrs": {"class": "form-control"}, "label_attrs": {"class": "form-label"},
|
||||
"label_spec": "{name} - {room_function.description}"},
|
||||
{"name": "condition", "row": "status", "label": "Condition", "wrap": {"class": "col"},
|
||||
"attrs": {"class": "form-control"}, "label_attrs": {"class": "form-label"}},
|
||||
|
||||
{"name": "image", "label": "", "row": "image", "type": "template", "label_spec": "{filename}",
|
||||
"template": "image_display.html", "attrs": {"class": "img-fluid img-thumbnail"}}
|
||||
]
|
||||
layout = [
|
||||
{"name": "label", "order": 10, "attrs": {"class": "row"}},
|
||||
{"name": "identification", "order": 20, "attrs": {"class": "row"}},
|
||||
{"name": "label", "order": 5},
|
||||
{"name": "kitchen_sink", "order": 6, "attrs": {"class": "row"}},
|
||||
{"name": "everything", "order": 10, "attrs": {"class": "col"}, "parent": "kitchen_sink"},
|
||||
{"name": "names", "order": 20, "attrs": {"class": "row"}, "parent": "everything"},
|
||||
{"name": "device", "order": 30, "attrs": {"class": "row mt-2"}, "parent": "everything"},
|
||||
{"name": "status", "order": 40, "attrs": {"class": "row mt-2"}, "parent": "everything"},
|
||||
{"name": "image", "order": 50, "attrs": {"class": "col-4"}, "parent": "kitchen_sink"}
|
||||
]
|
||||
elif model.lower() == 'user':
|
||||
fields["fields"] = ["label", "first_name", "last_name", "title", "active", "staff", "location", "supervisor"]
|
||||
fields_spec = [
|
||||
{"name": "label", "row": "label", "label": "User Record",
|
||||
"label_attrs": {"class": "display-6"}, "type": "display",
|
||||
"attrs": {"class": "display-4 mb-3"}, "wrap": {"class": "text-center"}},
|
||||
{"name": "label", "row": "label", "label": "",
|
||||
"label_attrs": {"class": "display-6 me-2"}, "type": "display",
|
||||
"attrs": {"class": "display-6 mb-3"}},
|
||||
|
||||
{"name": "last_name", "label": "Last Name", "label_attrs": {"class": "form-label"},
|
||||
"attrs": {"placeholder": "Doe", "class": "form-control"},
|
||||
"row": "name", "wrap": {"class": "col-2"}},
|
||||
"row": "name", "wrap": {"class": "col-3"}},
|
||||
|
||||
{"name": "first_name", "label": "First Name", "label_attrs": {"class": "form-label"},
|
||||
"attrs": {"placeholder": "John", "class": "form-control"},
|
||||
"row": "name", "wrap": {"class": "col-2"}},
|
||||
"row": "name", "wrap": {"class": "col-3"}},
|
||||
|
||||
{"name": "title", "label": "Title", "label_attrs": {"class": "form-label"},
|
||||
"attrs": {"placeholder": "President of the Universe", "class": "form-control"},
|
||||
"row": "name", "wrap": {"class": "col-2"}},
|
||||
"row": "name", "wrap": {"class": "col-3"}},
|
||||
|
||||
{"name": "supervisor", "label": "Supervisor", "label_attrs": {"class": "form-label"},
|
||||
"label_spec": "{first_name} {last_name}", "row": "details", "wrap": {"class": "col-3"},
|
||||
|
|
@ -67,8 +97,8 @@ def init_entry_routes(app):
|
|||
]
|
||||
layout = [
|
||||
{"name": "label", "order": 0},
|
||||
{"name": "name", "order": 10, "attrs": {"class": "row mb-3"}},
|
||||
{"name": "details", "order": 20, "attrs": {"class": "row"}},
|
||||
{"name": "name", "order": 10, "attrs": {"class": "row"}},
|
||||
{"name": "details", "order": 20, "attrs": {"class": "row mt-2"}},
|
||||
{"name": "checkboxes", "order": 30, "parent": "name", "attrs": {"class": "col d-flex flex-column justify-content-end"}}
|
||||
]
|
||||
elif model == "worklog":
|
||||
|
|
@ -85,7 +115,7 @@ def init_entry_routes(app):
|
|||
instance=obj,
|
||||
fields_spec=fields_spec,
|
||||
layout=layout,
|
||||
submit_attrs={"class": "btn btn-primary"}
|
||||
submit_attrs={"class": "btn btn-primary mt-3"}
|
||||
)
|
||||
return render_template("entry.html", form=form)
|
||||
|
||||
|
|
|
|||
4
inventory/templates/image_display.html
Normal file
4
inventory/templates/image_display.html
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<img src="{{ url_for('static', filename=field['value_label']) }}" alt="{{ value }}"
|
||||
{% if field['attrs'] %}{% for k,v in field['attrs'].items() %}
|
||||
{{k}}{% if v is not sameas true %}="{{ v }}"{% endif %}
|
||||
{% endfor %}{% endif %}>
|
||||
Loading…
Add table
Add a link
Reference in a new issue