Dropdown functionality!

This commit is contained in:
Yaro Kasear 2025-08-15 11:22:02 -05:00
parent 39a8199618
commit fe5e283be6
5 changed files with 75 additions and 22 deletions

View file

@ -23,7 +23,6 @@ class Room(db.Model):
inventory: Mapped[List['Inventory']] = relationship('Inventory', back_populates='location') inventory: Mapped[List['Inventory']] = relationship('Inventory', back_populates='location')
users: Mapped[List['User']] = relationship('User', back_populates='location') users: Mapped[List['User']] = relationship('User', back_populates='location')
ui_label_attr = 'name'
ui_eagerload = tuple() ui_eagerload = tuple()
ui_extra_attrs = ('area_id', 'function_id') ui_extra_attrs = ('area_id', 'function_id')

View file

@ -97,6 +97,8 @@ function DropDown(cfg) {
id: cfg.id, id: cfg.id,
refreshUrl: cfg.refreshUrl, refreshUrl: cfg.refreshUrl,
selectUrl: cfg.selectUrl, selectUrl: cfg.selectUrl,
recordId: cfg.recordId, // NEW
field: cfg.field, // NEW
selectedId: null, selectedId: null,
selectedLabel: '', selectedLabel: '',
@ -125,19 +127,21 @@ function DropDown(cfg) {
if (button) { if (button) {
button.textContent = label || '-'; button.textContent = label || '-';
button.dataset.invValue = id; button.dataset.invValue = id;
button.classList.add("rounded-end-0"); button.classList.add("rounded-end-0", "border-end-0");
button.classList.add("border-end-0");
button.classList.remove("rounded-end"); button.classList.remove("rounded-end");
} }
clear?.classList.toggle('d-none', !id); clear?.classList.toggle('d-none', !id);
if (this.selectUrl) { if (this.selectUrl && this.recordId && this.field) {
const payload = { id: this.recordId };
payload[this.field] = id ? parseInt(id) : null;
fetch(this.selectUrl, { fetch(this.selectUrl, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id }) body: JSON.stringify(payload)
}).catch(() => {}); }).catch(() => { });
} }
}, },
@ -153,12 +157,21 @@ function DropDown(cfg) {
if (button) { if (button) {
button.textContent = '-'; button.textContent = '-';
button.removeAttribute('data-inv-value'); button.removeAttribute('data-inv-value');
button.classList.remove("rounded-end-0", "border-end-0");
button.classList.remove("rounded-end-0");
button.classList.remove("border-end-0");
button.classList.add("rounded-end"); button.classList.add("rounded-end");
} }
clear?.classList.add('d-none'); clear?.classList.add('d-none');
if (this.selectUrl && this.recordId && this.field) {
const payload = { id: this.recordId };
payload[this.field] = null;
fetch(this.selectUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
}).catch(() => { });
}
this.$dispatch('dropdown:cleared', {}); this.$dispatch('dropdown:cleared', {});
} }
}; };

View file

@ -42,8 +42,7 @@
</div> </div>
{% endmacro %} {% endmacro %}
{% macro dynamic_dropdown(id, list = none, label = none, current_item = none, entry_link = none, enabled = true, refresh_url = none, select_url = none, record_id = none, field_name = none) %}
{% macro dynamic_dropdown(id, list = none, label = none, current_item = none, entry_link = none, enabled = true, refresh_url = none, select_url = none) %}
<label for="{{ id }}" class="form-label"> <label for="{{ id }}" class="form-label">
{{ label or '' }} {{ label or '' }}
{% if entry_link %} {% if entry_link %}
@ -53,7 +52,9 @@
<div class="dropdown" id="{{ id }}-dropdown" x-data='DropDown({ <div class="dropdown" id="{{ id }}-dropdown" x-data='DropDown({
id: {{ id|tojson }}, id: {{ id|tojson }},
refreshUrl: {{ refresh_url|tojson if refresh_url else "null" }}, refreshUrl: {{ refresh_url|tojson if refresh_url else "null" }},
selectUrl: {{ select_url|tojson if select_url else "null" }} selectUrl: {{ select_url|tojson if select_url else "null" }},
recordId: {{ record_id|tojson if record_id else "null"}},
field: {{ field_name|tojson if field_name else "null"}}
})' })'
hx-preserve x-init="init()"> hx-preserve x-init="init()">
<div class="btn-group w-100"> <div class="btn-group w-100">

View file

@ -106,23 +106,29 @@
<div class="row mt-2"> <div class="row mt-2">
<div class="col-6"> <div class="col-6">
{{ dropdowns.render_dropdown( {{ dropdowns.dynamic_dropdown(
id='supervisor', id='supervisor',
list=users,
label='Supervisor', label='Supervisor',
current_item=user.supervisor if user.supervisor else None, current_item=user.supervisor if user.supervisor else None,
entry_link='user', entry_link='user',
enabled=user.active enabled=user.active,
refresh_url = url_for('ui.list_items', model_name='user'),
select_url = url_for('ui.update_item', model_name='user'),
record_id = user.id,
field_name = 'supervisor_id'
) }} ) }}
</div> </div>
<div class="col-6"> <div class="col-6">
{{ dropdowns.render_dropdown( {{ dropdowns.dynamic_dropdown(
id='location', id='location',
list=rooms,
label='Location', label='Location',
current_item=user.location if user.location else None, current_item=user.location if user.location else None,
enabled=user.active enabled=user.active,
refresh_url = url_for('ui.list_items', model_name='room'),
select_url = url_for('ui.update_item', model_name='user'),
record_id = user.id,
field_name = 'location_id'
) }} ) }}
</div> </div>
</div> </div>

View file

@ -73,14 +73,48 @@ def default_create(session, Model, payload):
session.commit() session.commit()
return obj return obj
# def default_update(session, Model, id_, payload):
# obj = session.get(Model, id_)
# if not obj:
# return None
# label = infer_label_attr(Model)
# if (nv := payload.get(label) or payload.get("name")):
# setattr(obj, label, nv)
# session.commit()
# return obj
def default_update(session, Model, id_, payload): def default_update(session, Model, id_, payload):
obj = session.get(Model, id_) obj = session.get(Model, id_)
if not obj: if not obj:
return None return None
label = infer_label_attr(Model)
if (nv := payload.get(label) or payload.get("name")): editable = getattr(Model, 'ui_editable_cols', None)
setattr(obj, label, nv)
session.commit() changed = False
for k, v in payload.items():
if k == 'id':
continue
col = _mapped_column(Model, k)
if col is None:
continue
if editable and k not in editable:
continue
if v == '' or v is None:
nv = None
else:
try:
nv = int(v) if col.type.python_type is int else v
except Exception:
nv = v
setattr(obj, k, nv)
changed = True
if changed:
session.commit()
return obj return obj
def default_delete(session, Model, ids): def default_delete(session, Model, ids):