Got much of the table behavior working with CRUDKit.
This commit is contained in:
parent
56debd88c2
commit
0c2a9847cb
11 changed files with 38 additions and 43 deletions
|
|
@ -31,17 +31,15 @@
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
{% macro pager(model, page, pages, per_page, sort, filters) -%}
|
{% macro pager(model, page, pages, per_page, sort, filters, fields_csv) -%}
|
||||||
<nav class="pager">
|
<nav id="pager" hx-swap-oob="true">
|
||||||
{%- if page > 1 -%}
|
<a hx-get="/ui/{{ model }}/frag/rows?page={{ page-1 }}&per_page={{ per_page }}{% if sort %}&sort={{ sort }}{% endif %}{% if fields_csv %}&fields_csv={{ fields_csv|urlencode }}{% endif %}{% for k,v in filters.items() %}&{{k}}={{ v|urlencode }}{% endfor %}"
|
||||||
<a hx-get="/{{ model }}/frag/rows?page={{ page-1 }}&per_page={{ per_page }}{% if sort %}&sort={{ sort }}{% endif %}{% for k,v in filters.items() %}&{{k}}={{v}}{% endfor %}"
|
hx-target="#rows" rel="prev" hx-swap="innerHTML">Prev</a>
|
||||||
hx-target="#rows" hx-push-url="true">Prev</a>
|
|
||||||
{%- endif -%}
|
|
||||||
<span>Page {{ page }} / {{ pages }}</span>
|
<span>Page {{ page }} / {{ pages }}</span>
|
||||||
{%- if page < pages -%} <a
|
|
||||||
hx-get="/{{ model }}/frag/rows?page={{ page+1 }}&per_page={{ per_page }}{% if sort %}&sort={{ sort }}{% endif %}{% for k,v in filters.items() %}&{{k}}={{v}}{% endfor %}"
|
<a hx-get="/ui/{{ model }}/frag/rows?page={{ page+1 }}&per_page={{ per_page }}{% if sort %}&sort={{ sort }}{% endif %}{% if fields_csv %}&fields_csv={{ fields_csv|urlencode }}{% endif %}{% for k,v in filters.items() %}&{{k}}={{ v|urlencode }}{% endfor %}"
|
||||||
hx-target="#rows" hx-push-url="true">Next</a>
|
hx-target="#rows" rel="next" hx-swap="innerHTML">Next</a>
|
||||||
{%- endif -%}
|
|
||||||
</nav>
|
</nav>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
{% import "_macros.html" as ui %}
|
{% import "crudkit/_macros.html" as ui %}
|
||||||
{% set action = url_for('frags.save', model=model) %}
|
{% set action = url_for('frags.save', model=model) %}
|
||||||
{{ ui.form(schema, action, method="POST", obj_id=obj.id if obj else None, hx=true) }}
|
{{ ui.form(schema, action, method="POST", obj_id=obj.id if obj else None, hx=true) }}
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
{% import "_macros.html" as ui %}
|
{% import "crudkit/_macros.html" as ui %}
|
||||||
{{ ui.lis(items, label_path=label_path, sublabel_path=sublabel_path, getp=getp) }}
|
{{ ui.lis(items, label_path=label_path, sublabel_path=sublabel_path, getp=getp) }}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
{# Renders only <option>...</option> rows #}
|
{# Renders only <option>...</option> rows #}
|
||||||
{% import "_macros.html" as ui %}
|
{% import "crudkit/_macros.html" as ui %}
|
||||||
{{ ui.options(items, value_attr=value_attr, label_path=label_path, getp=getp) }}
|
{{ ui.options(items, value_attr=value_attr, label_path=label_path, getp=getp) }}
|
||||||
|
|
|
||||||
2
crudkit/html/templates/crudkit/pager.html
Normal file
2
crudkit/html/templates/crudkit/pager.html
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
{% import 'crudkit/_macros.html' as ui %}
|
||||||
|
{{ ui.pager(model, page, pages, per_page, sort, filters, fields_csv) }}
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
{% import "_macros.html" as ui %}
|
{% import "crudkit/_macros.html" as ui %}
|
||||||
{{ ui.rows([obj], fields, getp=getp) }}
|
{{ ui.rows([obj], fields, getp=getp) }}
|
||||||
|
|
@ -1,3 +1,2 @@
|
||||||
{% import "_macros.html" as ui %}
|
{% import "crudkit/_macros.html" as ui %}
|
||||||
{{ ui.rows(items, fields, getp=getp) }}
|
{{ ui.rows(items, fields, getp=getp) }}
|
||||||
{{ ui.pager(model, page, pages, per_page, sort, filters) }}
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ def make_fragments_blueprint(db_session_factory, registry: Dict[str, Any], *, na
|
||||||
GET /<model>/frag/rows -> <tr>...</tr> + pager markup if wanted
|
GET /<model>/frag/rows -> <tr>...</tr> + pager markup if wanted
|
||||||
GET /<model>/frag/form -> <form>...</form> (auto-generated)
|
GET /<model>/frag/form -> <form>...</form> (auto-generated)
|
||||||
"""
|
"""
|
||||||
bp = Blueprint(name, __name__, template_folder="templates/crudkit")
|
bp = Blueprint(name, __name__, template_folder="templates")
|
||||||
def session(): return scoped_session(db_session_factory)()
|
def session(): return scoped_session(db_session_factory)()
|
||||||
|
|
||||||
def _parse_filters(args):
|
def _parse_filters(args):
|
||||||
|
|
@ -74,7 +74,7 @@ def make_fragments_blueprint(db_session_factory, registry: Dict[str, Any], *, na
|
||||||
s = session(); svc = CrudService(s, default_eager_policy)
|
s = session(); svc = CrudService(s, default_eager_policy)
|
||||||
items, _ = svc.list(Model, spec)
|
items, _ = svc.list(Model, spec)
|
||||||
|
|
||||||
return render_template("options.html", items=items, value_attr=value_attr, label_path=label_path, getp=_getp)
|
return render_template("crudkit/options.html", items=items, value_attr=value_attr, label_path=label_path, getp=_getp)
|
||||||
|
|
||||||
@bp.get("/<model>/frag/lis")
|
@bp.get("/<model>/frag/lis")
|
||||||
def lis(model):
|
def lis(model):
|
||||||
|
|
@ -91,7 +91,7 @@ def make_fragments_blueprint(db_session_factory, registry: Dict[str, Any], *, na
|
||||||
s = session(); svc = CrudService(s, default_eager_policy)
|
s = session(); svc = CrudService(s, default_eager_policy)
|
||||||
rows, total = svc.list(Model, spec)
|
rows, total = svc.list(Model, spec)
|
||||||
pages = (ceil(total / per_page) if page and per_page else 1)
|
pages = (ceil(total / per_page) if page and per_page else 1)
|
||||||
return render_template("lis.html", items=rows, label_path=label_path, sublabel_path=sublabel_path, page=page or 1, per_page=per_page or 1, total=total, model=model, sort=sort, filters=filters, getp=_getp)
|
return render_template("crudkit/lis.html", items=rows, label_path=label_path, sublabel_path=sublabel_path, page=page or 1, per_page=per_page or 1, total=total, model=model, sort=sort, filters=filters, getp=_getp)
|
||||||
|
|
||||||
@bp.get("/<model>/frag/rows")
|
@bp.get("/<model>/frag/rows")
|
||||||
def rows(model):
|
def rows(model):
|
||||||
|
|
@ -108,7 +108,12 @@ def make_fragments_blueprint(db_session_factory, registry: Dict[str, Any], *, na
|
||||||
s = session(); svc = CrudService(s, default_eager_policy)
|
s = session(); svc = CrudService(s, default_eager_policy)
|
||||||
rows, total = svc.list(Model, spec)
|
rows, total = svc.list(Model, spec)
|
||||||
pages = max(1, ceil(total / per_page))
|
pages = max(1, ceil(total / per_page))
|
||||||
return render_template("rows.html", items=rows, fields=fields, page=page, pages=pages, per_page=per_page, total=total, model=model, sort=sort, filters=filters, getp=_getp)
|
|
||||||
|
rows_html = render_template("crudkit/rows.html", items=rows, fields=fields, getp=_getp)
|
||||||
|
pager_html = render_template("crudkit/pager.html", model=model, page=page, pages=pages,
|
||||||
|
per_page=per_page, sort=sort, filters=filters, fields_csv=fields_csv)
|
||||||
|
|
||||||
|
return rows_html + pager_html
|
||||||
|
|
||||||
@bp.get("/<model>/frag/form")
|
@bp.get("/<model>/frag/form")
|
||||||
def form(model):
|
def form(model):
|
||||||
|
|
@ -123,7 +128,7 @@ def make_fragments_blueprint(db_session_factory, registry: Dict[str, Any], *, na
|
||||||
schema = build_form_schema(Model, s, obj=obj, include=include)
|
schema = build_form_schema(Model, s, obj=obj, include=include)
|
||||||
|
|
||||||
hx = request.args.get("hx", type=int) == 1
|
hx = request.args.get("hx", type=int) == 1
|
||||||
return render_template("form.html", model=model, obj=obj, schema=schema, hx=hx)
|
return render_template("crudkit/form.html", model=model, obj=obj, schema=schema, hx=hx)
|
||||||
|
|
||||||
def coerce_form_types(Model, data: dict) -> dict:
|
def coerce_form_types(Model, data: dict) -> dict:
|
||||||
"""Turn HTML string inputs into the Python types your columns expect."""
|
"""Turn HTML string inputs into the Python types your columns expect."""
|
||||||
|
|
|
||||||
|
|
@ -51,17 +51,16 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro dynamic_table(id, headers=none, fields=none, entry_route=None, title=None, per_page=15, offset=0,
|
{% macro dynamic_table(id, headers=none, fields=none, entry_route=None, title=None, page=1, per_page=15, offset=0,
|
||||||
refresh_url=none) %}
|
refresh_url=none, model=none) %}
|
||||||
<!-- Table Fragment -->
|
<!-- Table Fragment -->
|
||||||
|
|
||||||
{% if rows or refresh_url %}
|
|
||||||
{% if title %}
|
{% if title %}
|
||||||
<label for="datatable-{{ id|default('table')|replace(' ', '-')|lower }}" class="form-label">{{ title }}</label>
|
<label for="datatable-{{ id|default('table')|replace(' ', '-')|lower }}" class="form-label">{{ title }}</label>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="table-responsive" id="table-container-{{ id }}" x-data='Table({
|
<div class="table-responsive" id="table-container-{{ id }}" x-data='Table({
|
||||||
id: "{{ id }}",
|
id: "{{ id }}",
|
||||||
refreshUrl: {{ refresh_url|tojson if refresh_url else "null" }},
|
refreshUrl: null,
|
||||||
headers: {{ headers|tojson if headers else "[]" }},
|
headers: {{ headers|tojson if headers else "[]" }},
|
||||||
perPage: {{ per_page }},
|
perPage: {{ per_page }},
|
||||||
offset: {{ offset if offset else 0 }},
|
offset: {{ offset if offset else 0 }},
|
||||||
|
|
@ -69,17 +68,6 @@ refresh_url=none) %}
|
||||||
})'>
|
})'>
|
||||||
<table id="datatable-{{ id|default('table')|replace(' ', '-')|lower }}"
|
<table id="datatable-{{ id|default('table')|replace(' ', '-')|lower }}"
|
||||||
class="table table-bordered table-sm table-hover table-striped table-light m-0 caption-bottom">
|
class="table table-bordered table-sm table-hover table-striped table-light m-0 caption-bottom">
|
||||||
<caption class="p-0">
|
|
||||||
<nav class="d-flex flex-column align-items-center px-2 py-1">
|
|
||||||
<!-- This is your pagination control -->
|
|
||||||
<ul class="pagination mb-0" x-ref="pagination"></ul>
|
|
||||||
<!-- This is just Alpine text binding -->
|
|
||||||
<div>
|
|
||||||
Page <span x-text="page"></span> of <span x-text="pages"></span>
|
|
||||||
(<span x-text="total"></span> total)
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
</caption>
|
|
||||||
<thead class="sticky-top">
|
<thead class="sticky-top">
|
||||||
<tr>
|
<tr>
|
||||||
{% for h in headers %}
|
{% for h in headers %}
|
||||||
|
|
@ -87,10 +75,13 @@ refresh_url=none) %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody x-ref="body"></tbody>
|
<tbody id="rows"
|
||||||
|
hx-get="/ui/{{ model }}/frag/rows?page={{ page }}&{{ per_page }}&fields_csv={{ fields|join(',') }}"
|
||||||
|
hx-trigger="load"
|
||||||
|
hx-target="#rows"
|
||||||
|
hx-swap="innerHTML">
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<div id="pager"></div>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
|
||||||
<div class="container text-center">No data.</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-tertiary text-primary-emphasis">
|
<body class="bg-tertiary text-primary-emphasis" hx-debug="true">
|
||||||
<nav class="navbar navbar-expand bg-body-tertiary border-bottom">
|
<nav class="navbar navbar-expand bg-body-tertiary border-bottom">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<a class="navbar-brand" href="{{ url_for('main.index') }}">
|
<a class="navbar-brand" href="{{ url_for('main.index') }}">
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,8 @@
|
||||||
id='table',
|
id='table',
|
||||||
headers=header.keys()|list if header else [],
|
headers=header.keys()|list if header else [],
|
||||||
entry_route=entry_route,
|
entry_route=entry_route,
|
||||||
refresh_url = url_for('frags.rows', model=model_name),
|
|
||||||
offset=offset,
|
offset=offset,
|
||||||
fields=fields
|
fields=fields,
|
||||||
|
model=model_name
|
||||||
) }}
|
) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue