Complete and total rework ahead.
This commit is contained in:
parent
559fd56f33
commit
e420110fb3
95 changed files with 394 additions and 6351 deletions
0
crudkit/ui/__init__.py
Normal file
0
crudkit/ui/__init__.py
Normal file
81
crudkit/ui/fragments.py
Normal file
81
crudkit/ui/fragments.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
from jinja2 import Environment, FileSystemLoader, ChoiceLoader
|
||||
from sqlalchemy.orm import class_mapper, RelationshipProperty
|
||||
from flask import current_app
|
||||
import os
|
||||
|
||||
def get_env():
|
||||
app_loader = current_app.jinja_loader
|
||||
|
||||
default_path = os.path.join(os.path.dirname(__file__), 'templates')
|
||||
fallback_loader = FileSystemLoader(default_path)
|
||||
|
||||
env = Environment(loader=ChoiceLoader([
|
||||
app_loader,
|
||||
fallback_loader
|
||||
]))
|
||||
return env
|
||||
|
||||
def get_crudkit_template(env, name):
|
||||
try:
|
||||
return env.get_template(f'crudkit/{name}')
|
||||
except Exception:
|
||||
return env.get_template(name)
|
||||
|
||||
def render_field(field, value):
|
||||
env = get_env()
|
||||
template = get_crudkit_template(env, 'field.html')
|
||||
return template.render(
|
||||
field_name=field['name'],
|
||||
field_label=field.get('label', field['name']),
|
||||
value=value,
|
||||
field_type=field.get('type', 'text'),
|
||||
options=field.get('options', None)
|
||||
)
|
||||
|
||||
def render_table(objects):
|
||||
env = get_env()
|
||||
template = get_crudkit_template(env, 'table.html')
|
||||
return template.render(objects=objects)
|
||||
|
||||
def render_form(model_cls, values, session=None):
|
||||
env = get_env()
|
||||
template = get_crudkit_template(env, 'form.html')
|
||||
fields = []
|
||||
fk_fields = set()
|
||||
|
||||
mapper = class_mapper(model_cls)
|
||||
for prop in mapper.iterate_properties:
|
||||
# FK Relationship fields (many-to-one)
|
||||
if isinstance(prop, RelationshipProperty) and prop.direction.name == 'MANYTOONE':
|
||||
if session is None:
|
||||
continue
|
||||
|
||||
related_model = prop.mapper.class_
|
||||
options = session.query(related_model).all()
|
||||
fields.append({
|
||||
'name': f"{prop.key}_id",
|
||||
'label': prop.key,
|
||||
'type': 'select',
|
||||
'options': [
|
||||
{'value': getattr(obj, 'id'), 'label': str(obj)}
|
||||
for obj in options
|
||||
]
|
||||
})
|
||||
fk_fields.add(f"{prop.key}_id")
|
||||
|
||||
# Now add basic columns — excluding FKs already covered
|
||||
for col in model_cls.__table__.columns:
|
||||
if col.name in fk_fields:
|
||||
continue
|
||||
if col.name in ('id', 'created_at', 'updated_at'):
|
||||
continue
|
||||
if col.default or col.server_default or col.onupdate:
|
||||
continue
|
||||
fields.append({
|
||||
'name': col.name,
|
||||
'label': col.name,
|
||||
'type': 'text',
|
||||
})
|
||||
|
||||
return template.render(fields=fields, values=values, render_field=render_field)
|
||||
|
||||
16
crudkit/ui/templates/field.html
Normal file
16
crudkit/ui/templates/field.html
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<label for="{{ field_name }}">{{ field_label }}</label>
|
||||
|
||||
{% if field_type == 'select' %}
|
||||
<select name="{{ field_name }}" {%- if not options %}disabled{% endif %}>
|
||||
{% if options %}
|
||||
<option value="">-- Select --</option>
|
||||
{% for opt in options %}
|
||||
<option value="{{ opt.value }}" {% if opt.value|string == value|string %}selected{% endif %}>{{ opt.label }}</option>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<option value="">-- No selection available --</option>
|
||||
{% endif %}
|
||||
</select>
|
||||
{% else %}
|
||||
<input type="text" name="{{ field_name }}" value="{{ value }}">
|
||||
{% endif %}
|
||||
6
crudkit/ui/templates/form.html
Normal file
6
crudkit/ui/templates/form.html
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<form method="POST">
|
||||
{% for field in fields %}
|
||||
{{ render_field(field, values.get(field.name, '')) }}
|
||||
{% endfor %}
|
||||
<button type="submit">Create</button>
|
||||
</form>
|
||||
12
crudkit/ui/templates/table.html
Normal file
12
crudkit/ui/templates/table.html
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<table>
|
||||
{% if objects %}
|
||||
<tr>
|
||||
{% for field in objects[0].__table__.columns %}<th>{{ field.name }}</th>{% endfor %}
|
||||
</tr>
|
||||
{% for obj in objects %}
|
||||
<tr>{% for field in obj.__table__.columns %}<td>{{ obj[field.name] }}</td>{% endfor %}</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr><th>No data.</th></tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
Loading…
Add table
Add a link
Reference in a new issue