Redo breadcrumb logic to something less painful.

This commit is contained in:
Yaro Kasear 2025-07-29 10:18:34 -05:00
parent 3ae6f85dc7
commit 2a7a72f31e
11 changed files with 88 additions and 57 deletions

View file

@ -4,7 +4,6 @@ from sqlalchemy.engine.url import make_url
import logging
import os
db = SQLAlchemy()
logger = logging.getLogger('sqlalchemy.engine')
@ -39,4 +38,9 @@ def create_app():
app.register_blueprint(main)
app.register_blueprint(image_bp)
from .routes.helpers import generate_breadcrumbs
@app.context_processor
def inject_breadcrumbs():
return {'breadcrumbs': generate_breadcrumbs()}
return app

View file

@ -4,12 +4,37 @@ import hashlib
import io
import os
from flask import url_for, jsonify
from flask import url_for, jsonify, request
from flask import current_app as app
from ..models import Inventory
from ..models import User, Inventory, WorkLog
from ..models.image import ImageAttachable
ROUTE_BREADCRUMBS = {
'main.user': {
'trail': [('Users', 'main.list_users')],
'model': User,
'arg': 'id',
'label_attr': 'identifier',
'url_func': lambda i: url_for('main.user', id=i.id)
},
'main.inventory_item': {
'trail': [('Inventory', 'main.list_inventory')],
'model': Inventory,
'arg': 'id',
'label_attr': 'identifier',
'url_func': lambda i: url_for('main.inventory_item', id=i.id)
},
'main.worklog': {
'trail': [('Work Log', 'main.list_worklog')],
'model': WorkLog,
'arg': 'id',
'label_attr': 'identifier',
'url_func': lambda i: url_for('main.worklog', id=i.id)
}
}
inventory_headers = {
"Date Entered": lambda i: {"text": i.timestamp.strftime("%Y-%m-%d") if i.timestamp else None},
"Identifier": lambda i: {"text": i.identifier},
@ -104,4 +129,35 @@ def make_csv(export_func, columns, rows):
"success": True,
"csv": base64.b64encode(csv_string.encode()).decode(),
"count": len(rows)
})
})
def generate_breadcrumbs():
crumbs = []
endpoint = request.endpoint
view_args = request.view_args or {}
if endpoint in ROUTE_BREADCRUMBS:
print(endpoint, view_args)
config = ROUTE_BREADCRUMBS[endpoint]
for label, ep in config.get('trail', []):
crumbs.append({'label': label, 'url': url_for(ep)})
obj_id = view_args.get(config['arg'])
if obj_id:
obj = config['model'].query.get(obj_id)
if obj:
crumbs.append({
'label': getattr(obj, config['label_attr'], str(obj)),
'url': config['url_func'](obj)
})
else:
# fallback to ugly slashes
path = request.path.strip('/').split('/')
accumulated = ''
for segment in path:
accumulated += '/' + segment
crumbs.append({'label': segment.title(), 'url': accumulated})
return crumbs

View file

@ -1,24 +1,18 @@
{% import "fragments/_icon_fragment.html" as icons %}
{% macro breadcrumb_header(breadcrumbs=[], title=None) %}
<!-- Breadcrumb Fragment -->
<ol class="breadcrumb m-0">
<li class="breadcrumb-item">
<a href="{{ url_for('main.index') }}" class="link-success link-underline-opacity-0">
{{ icons.render_icon('house', 16) }}
</a>
</li>
{% for crumb in breadcrumbs %}
<li class="breadcrumb-item">
{% if crumb.url %}
<a href="{{ crumb.url }}" class="link-success link-underline-opacity-0">{{ crumb.label }}</a>
{% else %}
{{ crumb.label }}
{% endif %}
</li>
{% endfor %}
{% if title %}
<li class="breadcrumb-item active">{{ title }}</li>
{% macro render_breadcrumb(breadcrumbs=[]) %}
<nav aria-label="breadcrumb">
<ol class="breadcrumb m-0">
<li class="breadcrumb-item"><a href="{{ url_for('main.index') }}" class="link-success link-underline-opacity-0">{{ icons.render_icon('house', 16) }}</a></li>
{% for crumb in breadcrumbs %}
<li class="breadcrumb-item{% if loop.last %} active{% endif %}" {% if loop.last %}aria-current="page"{% endif %}>
{% if not loop.last %}
<a href="{{ crumb.url }}" class="link-success link-underline-opacity-0">{{ crumb.label }}</a>
{% else %}
{{ crumb.label }}
{% endif %}
</ol>
</li>
{% endfor %}
</ol>
</nav>
{% endmacro %}

View file

@ -115,12 +115,7 @@
{% endset %}
{{ toolbars.render_toolbar(
id='inventory',
left=breadcrumbs.breadcrumb_header(
breadcrumbs=[
{'label': "Inventory", 'url': url_for('main.list_inventory')}
],
title=title
),
left=breadcrumb_macro.render_breadcrumb(breadcrumbs=breadcrumbs),
right=buttonBar
) }}
{% if item.condition in ["Removed", "Disposed"] %}

View file

@ -4,9 +4,7 @@
{% block title %}{{ title }}{% endblock %}
{% block precontent %}
{{ toolbars.render_toolbar('index', left=breadcrumbs.breadcrumb_header(
title=title
)) }}
{{ toolbars.render_toolbar('index', left=breadcrumb_macro.render_breadcrumb(breadcrumbs=breadcrumbs)) }}
{% endblock %}
{% block content %}

View file

@ -1,5 +1,5 @@
{% import "fragments/_button_fragment.html" as buttons %}
{% import "fragments/_breadcrumb_fragment.html" as breadcrumbs %}
{% import "fragments/_breadcrumb_fragment.html" as breadcrumb_macro %}
{% import "fragments/_combobox_fragment.html" as combos %}
{% import "fragments/_dropdown_fragment.html" as dropdowns %}
{% import "fragments/_editor_fragment.html" as editor %}
@ -59,7 +59,8 @@
</div>
</div>
</nav>
{% block precontent %}{% endblock %}
{% block precontent %}
{% endblock %}
<main class="container-flex m-5">
{% block content %}{% endblock %}
</main>

View file

@ -6,9 +6,7 @@
{% block precontent %}
{{ toolbars.render_toolbar(
id='search',
left = breadcrumbs.breadcrumb_header(
title=title
)
left = breadcrumb_macro.render_breadcrumb(breadcrumbs=breadcrumbs)
) }}
{% if not results['inventory']['rows'] and not results['users']['rows'] and not results['worklog']['rows'] %}
<div class="alert alert-danger rounded-0">There are no results for "{{ query }}".</div>

View file

@ -98,9 +98,7 @@
{% endset %}
{{ toolbars.render_toolbar(
id='settings',
left=breadcrumbs.breadcrumb_header(
title=title
),
left=breadcrumb_macro.render_breadcrumb(breadcrumbs=breadcrumbs),
right=buttons.render_button(
id='save',
icon='floppy',

View file

@ -21,10 +21,7 @@
{% endset %}
{{ toolbars.render_toolbar(
'table',
left = breadcrumbs.breadcrumb_header(
title=title,
breadcrumbs=breadcrumb
),
left = breadcrumb_macro.render_breadcrumb(breadcrumbs=breadcrumbs),
right = toolbarButtons
) }}
{% endblock %}

View file

@ -75,12 +75,7 @@
{% endset %}
{{ toolbars.render_toolbar(
id = 'newUser',
left = breadcrumbs.breadcrumb_header(
title=title,
breadcrumbs=[
{'label': 'Users', 'url': url_for('main.list_users')}
]
),
left = breadcrumb_macro.render_breadcrumb(breadcrumbs=breadcrumbs),
right = iconBar
) }}
{% if not user.active %}

View file

@ -120,12 +120,7 @@
{% endset %}
{{ toolbars.render_toolbar(
id='newWorklog',
left=breadcrumbs.breadcrumb_header(
breadcrumbs=[
{'label': 'Work Log', 'url': url_for('main.list_worklog')}
],
title=title
),
left=breadcrumb_macro.render_breadcrumb(breadcrumbs=breadcrumbs),
right=iconBar
) }}
{% if log.complete %}