Development

This commit is contained in:
Matthew Grotke 2026-05-28 12:31:13 -04:00
parent 3b5e9e7eaa
commit 1ed913524f

View file

@ -1797,6 +1797,72 @@ def _render_editable_list(item, tokens):
)
_STANDARD_INPUT_TYPES = {'text', 'password', 'number', 'checkbox', 'select', 'textarea'}
def _js_str(value):
return json.dumps(str(value))
def _get_worker_id(datasource):
for prefix in ('config:', 'live:'):
if datasource.startswith(prefix):
return datasource[len(prefix):]
return ''
def _render_table_worker_script(item, expanded_ra_fields):
"""Emit a <script> registering a table worker for any non-standard inline_edit field types.
Returns empty string when all fields are standard types."""
if not expanded_ra_fields:
return ''
worker_id = _get_worker_id(item.get('datasource', ''))
if not worker_id:
return ''
nonstandard = set()
for fields in expanded_ra_fields.values():
for f in fields:
it = f.get('input_type', 'text')
if it not in _STANDARD_INPUT_TYPES:
nonstandard.add(it)
if not nonstandard:
return ''
if nonstandard == {'credentials'}:
return (
f'<script>registerTableWorker({_js_str(worker_id)}, (function() {{\n'
' function _buildCreds(provider, data) {\n'
' if (provider === \'noip\') {\n'
' return \'<div class="cred-field"><span class="cred-label">U:</span>\' +\n'
' \'<input type="text" name="username" value="\' + _htmlEsc(data.username||\'\')'
' + \'" class="form-input inline-edit-input"/></div>\' +\n'
' \'<div class="cred-field"><span class="cred-label">P:</span>\' +\n'
' \'<input type="password" name="password" value="\' + _htmlEsc(data.password||\'\')'
' + \'" class="form-input inline-edit-input"/></div>\';\n'
' }\n'
' return \'<input type="text" name="api_token" value="\' + _htmlEsc(data.api_token||\'\')'
' + \'" class="form-input inline-edit-input" placeholder="API Token"/>\';\n'
' }\n'
' return {\n'
' renderCell: function(fDef, td, val, row) {\n'
' if (fDef.input_type !== \'credentials\') return false;\n'
' td.innerHTML = _buildCreds(row.provider || \'noip\', row);\n'
' return true;\n'
' },\n'
' afterRowOpen: function(tr, row) {\n'
' var provSel = tr.querySelector(\'td[data-field="provider"] select\');\n'
' var credTd = tr.querySelector(\'td[data-field="credentials"]\');\n'
' if (!provSel || !credTd) return;\n'
' provSel.addEventListener(\'change\', function() {\n'
' credTd.innerHTML = _buildCreds(this.value, row);\n'
' });\n'
' }\n'
' };\n'
'}()));</script>\n'
)
# Unrecognized non-standard types: emit a safe no-op worker
return f'<script>registerTableWorker({_js_str(worker_id)}, {{}});</script>\n'
def _render_table(item, tokens, inherited_req=None):
level = _client_level()
columns = item.get('columns', [])
@ -1820,6 +1886,12 @@ def _render_table(item, tokens, inherited_req=None):
if row_actions:
thead += '<th></th>'
expanded_ra_fields = {
i: _expand_fields(ra.get('fields', []), tokens)
for i, ra in enumerate(row_actions)
if ra.get('method', 'post').lower() == 'inline_edit'
}
if not rows:
colspan = len(columns) + (1 if row_actions else 0)
tbody = f'<tr><td colspan="{colspan}" class="table-empty">{empty}</td></tr>'
@ -1845,7 +1917,7 @@ def _render_table(item, tokens, inherited_req=None):
)
if row_actions:
btns = ''
for ra in row_actions:
for ra_i, ra in enumerate(row_actions):
req = ra.get('client_requirement', inherited_req)
if not _passes(req, level):
continue
@ -1869,29 +1941,39 @@ def _render_table(item, tokens, inherited_req=None):
row_json = e(json.dumps(row))
btns += (
f'<button type="button" class="btn {cls} row-edit-btn"'
f' data-edit-mode="reveal"'
f' data-row-index="{idx}" data-row="{row_json}"'
f' data-target="{target}">{text}</button>'
)
elif method == 'inline_edit':
fields_json = e(json.dumps(_expand_fields(ra.get('fields', []), tokens)))
expanded = expanded_ra_fields.get(ra_i, [])
fields_json = e(json.dumps(expanded))
row_json = e(json.dumps(row))
worker_id = _get_worker_id(item.get('datasource', ''))
has_nonstandard = any(
f.get('input_type', 'text') not in _STANDARD_INPUT_TYPES
for f in expanded
)
worker_attr = f' data-worker-id="{e(worker_id)}"' if has_nonstandard and worker_id else ''
btns += (
f'<button type="button" class="btn {cls} row-inline-edit-btn"'
f'<button type="button" class="btn {cls} row-edit-btn"'
f' data-edit-mode="inline"'
f' data-row-index="{idx}" data-row="{row_json}"'
f' data-action="{action}" data-fields="{fields_json}">{text}</button>'
f' data-action="{action}" data-fields="{fields_json}"{worker_attr}>{text}</button>'
)
else:
btns += f'<a href="{action}?row_index={idx}" class="btn {cls}">{text}</a>'
cells += f'<td class="col-actions">{btns}</td>'
tbody += f'<tr>{cells}</tr>'
worker_script = _render_table_worker_script(item, expanded_ra_fields)
return (
f'{toolbar_html}'
'<div class="table-wrapper">'
'<table class="data-table">'
f'<thead><tr>{thead}</tr></thead>'
f'<tbody>{tbody}</tbody>'
'</table></div>'
f'</table></div>{worker_script}'
)