Soem crudkit fixes aimed at eliminating session sharing.

This commit is contained in:
Yaro Kasear 2025-09-15 11:51:56 -05:00
parent d045a1a05f
commit cf795086f1
10 changed files with 107 additions and 47 deletions

View file

@ -1,12 +1,14 @@
from typing import List, Optional, TYPE_CHECKING
from sqlalchemy import Boolean, ForeignKey, Integer, Unicode
from sqlalchemy import Boolean, ForeignKey, Integer, Unicode, func, case, literal
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.sql import expression as sql
from crudkit.core.base import Base, CRUDMixin
from . import RoomFunction
if TYPE_CHECKING:
from .user import User
@ -32,4 +34,14 @@ class Room(Base, CRUDMixin):
@hybrid_property
def label(self):
return f"{self.name} - {self.room_function.description}"
name = self.name or "Unassigned"
desc = self.room_function.description if (self.room_function and self.room_function.description) else None
return f"{name} - {desc}"
@label.expression
def label(cls):
return func.concat(
func.coalesce(cls.name, literal("Unassigned")),
case((cls.function_id.isnot(None), literal(" - ")), else_=literal("")),
func.coalesce(RoomFunction.description, literal(""))
)

View file

@ -1,15 +1,12 @@
from flask import Blueprint, current_app, jsonify, render_template, request, send_file
from flask import Blueprint, current_app, render_template, send_file
from pathlib import Path
from sqlalchemy import func, select
import pandas as pd
from crudkit.core.service import CRUDService
from crudkit.core.spec import CRUDSpec
import crudkit
from crudkit.ui.fragments import render_table
from ..db import get_session
from ..models.device_type import DeviceType
from ..models.inventory import Inventory
from ..models.work_log import WorkLog
@ -18,9 +15,8 @@ bp_index = Blueprint("index", __name__)
def init_index_routes(app):
@bp_index.get("/")
def index():
session = get_session()
inventory_service = CRUDService(Inventory, session)
work_log_service = CRUDService(WorkLog, session)
inventory_service = crudkit.crud.get_service(Inventory)
work_log_service = crudkit.crud.get_service(WorkLog)
work_logs = work_log_service.list({
"complete__ne": 1,
"fields": [

View file

@ -1,4 +1,4 @@
from flask import Blueprint, render_template, abort
from flask import Blueprint, render_template, abort, request
import crudkit
@ -9,25 +9,65 @@ bp_listing = Blueprint("listing", __name__)
def init_listing_routes(app):
@bp_listing.get("/listing/<model>")
def show_list(model):
page_num = int(request.args.get("page", 1))
if model.lower() not in {"inventory", "user", "worklog"}:
abort(404)
cls = crudkit.crud.get_model(model)
if cls is None:
abort(404)
spec = {}
columns = []
if model.lower() == 'inventory':
spec = {"fields": [
"label",
"name",
"barcode",
"serial",
"device_type.description"
"brand.name",
"model",
"device_type.description",
"condition",
"owner.label",
"location.label",
]}
spec["limit"] = 0
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": "user.get_item", "params": {"id": "{owner.id}"}}},
{"field": "location.label", "label": "Room"},
]
if model.lower() == 'user':
spec = {"fields": [
"label",
"last_name",
"first_name",
"supervisor.label",
"staff",
"active",
]}
columns = [
{"field": "label", "label": "Full Name"},
{"field": "last_name"},
{"field": "first_name"},
{"field": "supervisor.label", "label": "Supervisor", "link": {"endpoint": "user.get_item", "params": {"id": "{supervisor.id}"}}},
{"field": "staff"},
{"field": "active"},
]
spec["limit"] = 15
spec["offset"] = (page_num - 1) * 15
service = crudkit.crud.get_service(cls)
rows = service.list(spec)
table = render_table(rows, opts={"object_class": model})
table = render_table(rows, columns=columns, opts={"object_class": model})
return render_template("listing.html", model=model, table=table)

View file

@ -29,7 +29,7 @@
{% block premain %}
{% endblock %}
<main class="container mt-3">
<main class="container-fluid mt-3">
{% block main %}
{% endblock %}
</main>

View file

@ -1,26 +1,28 @@
<table class="table table-light table-striped table-hover table-bordered border-tertiary text-nowrap overflow-x-auto">
<thead>
<tr>
{% for col in columns %}
<div class="table-responsive mx-5" style="max-height: 80vh;">
<table class="table table-light table-striped table-hover table-bordered border-tertiary text-nowrap overflow-x-auto mx-auto">
<thead>
<tr>
{% for col in columns %}
<th>{{ col.label }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% if rows %}
{% endfor %}
</tr>
</thead>
<tbody>
{% if rows %}
{% for row in rows %}
<tr onclick="location.href='{{ url_for( 'crudkit.' + kwargs['opts']['object_class'] + '.get_item', id=row.id) }}'" style="cursor: pointer;">
{% for cell in row.cells %}
{% if cell.href %}
<td class="{{ cell.class or '' }}"><a href="{{ cell.href }}" class="link-success link-underline link-underline-opacity-0 fw-semibold">{{ cell.text if cell.text is not none else '-' }}</a></td>
{% else %}
<td class="{{ cell.class or '' }}">{{ cell.text if cell.text is not none else '-' }}</td>
{% endif %}
{% endfor %}
</tr>
<tr onclick="location.href='{{ url_for( 'crudkit.' + kwargs['opts']['object_class'] + '.get_item', id=row.id) }}'" style="cursor: pointer;">
{% for cell in row.cells %}
{% if cell.href %}
<td class="{{ cell.class or '' }}"><a href="{{ cell.href }}" class="link-success link-underline link-underline-opacity-0 fw-semibold">{{ cell.text if cell.text is not none else '-' }}</a></td>
{% else %}
<td class="{{ cell.class or '' }}">{{ cell.text if cell.text is not none else '-' }}</td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
{% else %}
{% else %}
<tr><td colspan="{{ columns|length }}">No data.</td></tr>
{% endif %}
</tbody>
</table>
{% endif %}
</tbody>
</table>
</div>

View file

@ -14,13 +14,13 @@
<h1 class="display-2 text-center">{{ title or "Inventory Manager" }}</h1>
<p class="lead text-center">Find out about all of your assets.</p>
<div class="row">
<div class="col pivot-cell">
<div class="row mx-5">
<div class="col pivot-cell ms-5">
<p class="display-6 text-center">Active Worklogs</p>
{{ logs | safe }}
</div>
<div class="col pivot-cell">
<div class="col pivot-cell me-5">
<p class="display-6 text-center">Inventory Report</p>
<div class="d-flex flex-wrap gap-2 align-items-end mb-2">

View file

@ -1,5 +1,10 @@
{% extends 'base.html' %}
{% block title %}
Inventory Manager - {{ model|title }} Listing
{% endblock %}
{% block main %}
<h1 class="display-4 text-center mt-5">{{ model|title }} Listing</h1>
{{ table | safe }}
{% endblock %}