Add filtering functionality to inventory listing and enhance templates for better data presentation
This commit is contained in:
parent
a7708ce9c5
commit
5df5f86fd2
8 changed files with 64 additions and 9 deletions
Binary file not shown.
Binary file not shown.
48
routes.py
48
routes.py
|
@ -4,7 +4,7 @@ import html
|
||||||
from sqlalchemy.orm import joinedload
|
from sqlalchemy.orm import joinedload
|
||||||
from typing import Callable, Any, List
|
from typing import Callable, Any, List
|
||||||
from . import db
|
from . import db
|
||||||
from .utils import eager_load_user_relationships, eager_load_inventory_relationships, eager_load_room_relationships, eager_load_worklog_relationships
|
from .utils import eager_load_user_relationships, eager_load_inventory_relationships, eager_load_room_relationships, eager_load_worklog_relationships, chunk_list
|
||||||
|
|
||||||
main = Blueprint('main', __name__)
|
main = Blueprint('main', __name__)
|
||||||
|
|
||||||
|
@ -106,7 +106,8 @@ def render_paginated_table(
|
||||||
entry_route: str,
|
entry_route: str,
|
||||||
row_fn: Callable[[Any], List[dict]],
|
row_fn: Callable[[Any], List[dict]],
|
||||||
endpoint: str,
|
endpoint: str,
|
||||||
per_page=15
|
per_page=15,
|
||||||
|
extra_args={}
|
||||||
):
|
):
|
||||||
data = make_paginated_data(query, page, per_page)
|
data = make_paginated_data(query, page, per_page)
|
||||||
return render_template(
|
return render_template(
|
||||||
|
@ -120,7 +121,8 @@ def render_paginated_table(
|
||||||
endpoint=endpoint,
|
endpoint=endpoint,
|
||||||
total_pages=data['total_pages'],
|
total_pages=data['total_pages'],
|
||||||
headers=headers,
|
headers=headers,
|
||||||
entry_route=entry_route
|
entry_route=entry_route,
|
||||||
|
extra_args=extra_args
|
||||||
)
|
)
|
||||||
|
|
||||||
@main.route("/")
|
@main.route("/")
|
||||||
|
@ -130,24 +132,56 @@ def index():
|
||||||
def link(text, endpoint, **values):
|
def link(text, endpoint, **values):
|
||||||
return {"text": text, "url": url_for(endpoint, **values)}
|
return {"text": text, "url": url_for(endpoint, **values)}
|
||||||
|
|
||||||
|
FILTER_MAP = {
|
||||||
|
'user': Inventory.owner_id,
|
||||||
|
'room': Inventory.location_id,
|
||||||
|
'brand': Inventory.brand_id,
|
||||||
|
}
|
||||||
|
|
||||||
@main.route("/inventory")
|
@main.route("/inventory")
|
||||||
def list_inventory():
|
def list_inventory():
|
||||||
page = request.args.get('page', default=1, type=int)
|
page = request.args.get('page', default=1, type=int)
|
||||||
query = eager_load_inventory_relationships(db.session.query(Inventory)).order_by(Inventory.inventory_name, Inventory.barcode, Inventory.serial)
|
filter_by = request.args.get('filter_by', type=str)
|
||||||
|
id = request.args.get('id', type=int)
|
||||||
|
|
||||||
|
query = db.session.query(Inventory)
|
||||||
|
query = eager_load_inventory_relationships(query)
|
||||||
|
query = query.order_by(Inventory.inventory_name, Inventory.barcode, Inventory.serial)
|
||||||
|
|
||||||
|
if filter_by and id:
|
||||||
|
column = FILTER_MAP.get(filter_by)
|
||||||
|
if column is not None:
|
||||||
|
query = query.filter(column == id)
|
||||||
|
else:
|
||||||
|
return "Invalid filter_by parameter", 400
|
||||||
|
|
||||||
return render_paginated_table(
|
return render_paginated_table(
|
||||||
query=query,
|
query=query,
|
||||||
page=page,
|
page=page,
|
||||||
title="Inventory",
|
title="Inventory (Filtered)" if filter_by else "Inventory",
|
||||||
headers=inventory_headers,
|
headers=inventory_headers,
|
||||||
row_fn=lambda i: [fn(i) for fn in inventory_headers.values()],
|
row_fn=lambda i: [fn(i) for fn in inventory_headers.values()],
|
||||||
endpoint="main.list_inventory",
|
endpoint="main.list_inventory",
|
||||||
entry_route="inventory_item"
|
entry_route="inventory_item",
|
||||||
|
extra_args={'filter_by': filter_by, 'id': id}
|
||||||
)
|
)
|
||||||
|
|
||||||
@main.route("/inventory/index")
|
@main.route("/inventory/index")
|
||||||
def inventory_index():
|
def inventory_index():
|
||||||
category = request.args.get('category')
|
category = request.args.get('category')
|
||||||
return render_template('inventory_index.html', title="Inventory Index", category=category)
|
listing = None
|
||||||
|
|
||||||
|
if category == 'user':
|
||||||
|
users = db.session.query(User.id, User.first_name, User.last_name).order_by(User.first_name, User.last_name).all()
|
||||||
|
listing = chunk_list([(user.id, f"{user.first_name or ''} {user.last_name or ''}".strip()) for user in users], 12)
|
||||||
|
elif category == 'location':
|
||||||
|
pass
|
||||||
|
elif category == 'type':
|
||||||
|
pass
|
||||||
|
elif category:
|
||||||
|
return f"Dude, why {category}?"
|
||||||
|
|
||||||
|
return render_template('inventory_index.html', title="Inventory Index", category=category, listing=listing)
|
||||||
|
|
||||||
@main.route("/inventory_item/<int:id>")
|
@main.route("/inventory_item/<int:id>")
|
||||||
def inventory_item(id):
|
def inventory_item(id):
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{% macro render_table(headers, rows, entry_route=None, title=None) %}
|
{% macro render_table(headers, rows, entry_route=None, title=None) %}
|
||||||
|
{% if rows %}
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table
|
<table
|
||||||
class="table table-bordered table-sm table-hover table-striped table-light m-0{% if title %} caption-top{% endif %}">
|
class="table table-bordered table-sm table-hover table-striped table-light m-0{% if title %} caption-top{% endif %}">
|
||||||
|
@ -32,6 +33,9 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="container text-center">No data.</div>
|
||||||
|
{% endif %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro render_pagination(endpoint, page, has_prev, has_next, total_pages, page_variable='page', extra_args={}) %}
|
{% macro render_pagination(endpoint, page, has_prev, has_next, total_pages, page_variable='page', extra_args={}) %}
|
||||||
|
@ -43,6 +47,7 @@
|
||||||
{% set _ = next_args.update({page_variable: page + 1}) %}
|
{% set _ = next_args.update({page_variable: page + 1}) %}
|
||||||
{% set _ = first_args.update({page_variable: 1}) %}
|
{% set _ = first_args.update({page_variable: 1}) %}
|
||||||
{% set _ = last_args.update({page_variable: total_pages}) %}
|
{% set _ = last_args.update({page_variable: total_pages}) %}
|
||||||
|
{% if total_pages > 1 %}
|
||||||
|
|
||||||
<div class="d-flex justify-content-between pt-3 px-5 align-items-center">
|
<div class="d-flex justify-content-between pt-3 px-5 align-items-center">
|
||||||
<div>
|
<div>
|
||||||
|
@ -72,4 +77,5 @@
|
||||||
class="btn btn-primary{% if not has_next %} disabled{% endif %}">Last »</a>
|
class="btn btn-primary{% if not has_next %} disabled{% endif %}">Last »</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
|
@ -132,7 +132,7 @@ submit_button=True) }}
|
||||||
total_pages=worklog_pagination['total_pages'],
|
total_pages=worklog_pagination['total_pages'],
|
||||||
endpoint='main.inventory_item',
|
endpoint='main.inventory_item',
|
||||||
page_variable='worklog_page',
|
page_variable='worklog_page',
|
||||||
extra_args={'id': item.id, 'worklog_page': worklog_page}
|
extra_args={'id': item.id, 'worklog_page': worklog_page, 'filter_by': filter_by, 'id': id}
|
||||||
) }}
|
) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -77,6 +77,18 @@ title=title
|
||||||
By Type
|
By Type
|
||||||
</a></div>
|
</a></div>
|
||||||
</div>
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="container">
|
||||||
|
{% for line in listing %}
|
||||||
|
<div class="row my-3">
|
||||||
|
{% for id, name in line %}
|
||||||
|
<div class="col text-center">
|
||||||
|
<a href="{{ url_for('main.list_inventory', filter_by='user', id=id) }}" class="link-success link-underline-opacity-0">{{ name }}</a>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -13,5 +13,5 @@
|
||||||
) }}
|
) }}
|
||||||
|
|
||||||
{{ tables.render_table(header, rows, entry_route) }}
|
{{ tables.render_table(header, rows, entry_route) }}
|
||||||
{{ tables.render_pagination(endpoint, page, has_prev, has_next, total_pages) }}
|
{{ tables.render_pagination(endpoint, page, has_prev, has_next, total_pages, extra_args=extra_args) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
3
utils.py
3
utils.py
|
@ -28,3 +28,6 @@ def eager_load_worklog_relationships(query):
|
||||||
joinedload(WorkLog.contact),
|
joinedload(WorkLog.contact),
|
||||||
joinedload(WorkLog.work_item)
|
joinedload(WorkLog.work_item)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def chunk_list(lst, chunk_size):
|
||||||
|
return [lst[i:i + chunk_size] for i in range(0, len(lst), chunk_size)]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue