Enhance inventory management by updating timestamp type to DateTime, adding stale worklog display on the index page, and improving template styles and scripts for better user experience.

This commit is contained in:
Yaro Kasear 2025-06-16 10:26:30 -05:00
parent 0835248f34
commit 58754c71bd
7 changed files with 73 additions and 16 deletions

View file

@ -6,7 +6,7 @@ if TYPE_CHECKING:
from .work_log import WorkLog
from .rooms import Room
from sqlalchemy import Boolean, ForeignKeyConstraint, ForeignKey, Identity, Index, Integer, PrimaryKeyConstraint, String, Unicode, text
from sqlalchemy import Boolean, ForeignKeyConstraint, ForeignKey, Identity, Index, Integer, PrimaryKeyConstraint, String, Unicode, DateTime, text
from sqlalchemy.dialects.mssql import DATETIME2, MONEY
from sqlalchemy.orm import Mapped, mapped_column, relationship
import datetime
@ -20,7 +20,7 @@ class Inventory(db.Model):
)
id: Mapped[int] = mapped_column("ID", Integer, Identity(start=1, increment=1), primary_key=True)
timestamp: Mapped[datetime.datetime] = mapped_column('Date Entered', DATETIME2)
timestamp: Mapped[datetime.datetime] = mapped_column('Date Entered', DateTime)
condition: Mapped[str] = mapped_column('Working Condition', Unicode(255))
needed: Mapped[str] = mapped_column("Needed", Unicode(255))
type_id: Mapped[int] = mapped_column('Item Type', Integer, ForeignKey("Items.ID"))

View file

@ -1,11 +1,11 @@
from flask import Blueprint, render_template, url_for, request, redirect
from .models import Area, Brand, Item, Inventory, RoomFunction, User, WorkLog, Room
import html
from .models import Brand, Item, Inventory, RoomFunction, User, WorkLog, Room
from sqlalchemy import or_
from sqlalchemy.orm import aliased
from typing import Callable, Any, List
from . import db
from .utils import eager_load_user_relationships, eager_load_inventory_relationships, eager_load_room_relationships, eager_load_worklog_relationships, chunk_list
from datetime import datetime, timedelta
main = Blueprint('main', __name__)
@ -130,7 +130,27 @@ def render_paginated_table(
@main.route("/")
def index():
return render_template("index.html", title="Inventory Manager")
stale_worklog_page = request.args.get('stale_worklog_page', 1, int)
cutoff = datetime.utcnow() - timedelta(days=14)
worklog_query = eager_load_worklog_relationships(
db.session.query(WorkLog)
).filter(
(WorkLog.start_time < cutoff) & (WorkLog.complete == False)
)
stale_pagination = make_paginated_data(worklog_query, stale_worklog_page, 3)
stale_count = len(worklog_query.all())
stale_worklog_headers = {k: v for k, v in worklog_headers.items() if k not in ['End Time', 'Quick Analysis?', 'Complete?', 'Follow Up?']}
return render_template(
"index.html",
title="Inventory Manager",
stale_pagination=stale_pagination,
stale_count=stale_count,
stale_worklog_headers=stale_worklog_headers,
stale_worklog_rows=[{"id": log.id, "cells": [fn(log) for fn in stale_worklog_headers.values()]} for log in stale_pagination['items']],
)
def link(text, endpoint, **values):
return {"text": text, "url": url_for(endpoint, **values)}
@ -338,10 +358,12 @@ def search():
UserAlias.last_name.ilike(f"%{query}%")
))
inventory_pagination = make_paginated_data(inventory_query, inventory_page)
user_query = eager_load_user_relationships(db.session.query(User)).filter(
user_query = eager_load_user_relationships(db.session.query(User).join(UserAlias, User.supervisor)).filter(
or_(
User.first_name.ilike(f"%{query}%"),
User.last_name.ilike(f"%{query}%")
User.last_name.ilike(f"%{query}%"),
UserAlias.first_name.ilike(f"%{query}%"),
UserAlias.last_name.ilike(f"%{query}%")
))
user_pagination = make_paginated_data(user_query, user_page)
worklog_query = eager_load_worklog_relationships(db.session.query(WorkLog).join(UserAlias, WorkLog.contact).join(InventoryAlias, WorkLog.work_item)).filter(

View file

@ -22,7 +22,7 @@
{% if cell.type == 'bool' %}
{{ cell.html | safe }}
{% elif cell.url %}
<a href="{{ cell.url }}">{{ cell.text }}</a>
<a class="link-success link-underline-opacity-0" href="{{ cell.url }}">{{ cell.text }}</a>
{% else %}
{{ cell.text or '-' }}
{% endif %}

View file

@ -7,5 +7,31 @@
<div class="container text-center">
<h1 class="display-4">Welcome to Inventory Manager</h1>
<p class="lead">Find out about all of your assets.</p>
<div class="row">
{% if stale_pagination['items'] %}
<div class="col">
<div class="card">
<div class="card-body">
<h5 class="card-title">Stale Worklogs</h5>
<h6 class="card-subtitle mb-2 text-body-secondary">You have {{ stale_count }} worklogs
that need attention!</h6>
{{ tables.render_table(
stale_worklog_headers,
stale_worklog_rows,
'index'
)}}
{{ tables.render_pagination(
'index',
stale_pagination['page'],
stale_pagination['has_prev'],
stale_pagination['has_next'],
stale_pagination['total_pages'],
page_variable='stale_worklog_page'
)}}
</div>
</div>
</div>
{% endif %}
</div>
</div>
{% endblock %}

View file

@ -14,9 +14,7 @@
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.6/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-4Q6Gf2aSP4eDXB8Miphtr37CMZZQ5oXLH2yaXMJ2w8e2ZtHTl7GptT4jmndRuHDT" crossorigin="anonymous">
<style>
{
% block style %
}
{% block style %}
.sticky-top {
position: sticky;
@ -43,18 +41,16 @@
background-color: white;
}
{
% endblock %
}
{% endblock %}
</style>
</head>
<body class="bg-tertiary text-primary-emphasis">
<nav class="navbar navbar-expand bg-body-tertiary border-bottom">
<div class="container-fluid">
<span class="navbar-brand">
<a class="navbar-brand" href="{{ url_for('index') }}">
Inventory Manager
</span>
</a>
<button class="navbar-toggler">
<span class="navbar-toggler-icon"></span>
</button>
@ -76,6 +72,9 @@
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.6/dist/js/bootstrap.bundle.min.js"
integrity="sha384-j1CDi7MgGQ12Z7Qab0qlWQ/Qqz24Gc6BM0thvEMVjHnfYGF0rmFCozFSxQBxwHKO"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mark.js/8.11.1/mark.min.js"
integrity="sha512-5CYOlHXGh6QpOFA/TeTylKLWfB3ftPsde7AnmhuitiTX4K5SqCLBeKro6sPS8ilsz1Q4NRx3v8Ko2IBiszzdww=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="{{ url_for('static', filename='js/datalist.js') }}"></script>
<script>
const searchInput = document.querySelector('#search');

View file

@ -77,3 +77,13 @@ title=title,
{% endif %}
</div>
{% endblock %}
{% block script %}
{% if query %}
const query = "{{ query|e }}";
if (query) {
const instance = new Mark(document.querySelector("main"));
instance.mark(query);
}
{% endif %}
{% endblock %}