Development

This commit is contained in:
Matthew Grotke 2026-05-24 02:42:11 -04:00
parent c8607ba8c5
commit e289583c4b
3 changed files with 55 additions and 22 deletions

View file

@ -680,6 +680,8 @@ def collect_tokens():
ddns = _load_ddns()
ddns_gen = ddns.get('general', {})
tokens['DDNS_TIMER_INTERVAL'] = ddns_gen.get('timer_interval', '-')
_interval_secs = _parse_interval_to_seconds(ddns_gen.get('timer_interval', '')) or 600
tokens['DDNS_TIMER_INTERVAL_MINS'] = str(_interval_secs // 60)
tokens['DDNS_GEN_LOG_MAX_KB'] = str(ddns_gen.get('log_max_kb', 1024))
tokens['DDNS_GEN_LOG_ERRORS_ONLY'] = 'true' if ddns_gen.get('log_errors_only') else 'false'
enabled_p = [p for p in ddns.get('providers', []) if p.get('enabled', True)]
@ -833,7 +835,7 @@ def _render_item(item, tokens, inherited_req=None):
return f'<h1>{e(apply_tokens(item.get("text", ""), tokens))}</h1>'
if t == 'hr':
return '<hr/>'
return '<hr class="divider"/>'
if t == 'p':
text = e(apply_tokens(item.get('text', ''), tokens))
@ -894,9 +896,19 @@ def _render_item(item, tokens, inherited_req=None):
sub = e(apply_tokens(item.get('sub', ''), tokens))
variant = item.get('variant', '')
cls = f'stat-card{(" stat-card-" + variant) if variant else ""}'
edit_action = item.get('edit_action', '')
edit_field = item.get('edit_field', '')
edit_action = item.get('edit_action', '')
edit_field = item.get('edit_field', '')
edit_input_type = item.get('edit_input_type', 'text')
edit_suffix = item.get('edit_suffix', '')
edit_min = item.get('edit_min', '')
edit_raw = apply_tokens(item.get('edit_value', item.get('value', '')), tokens)
if edit_action and edit_field:
min_attr = f' min="{e(edit_min)}"' if edit_min else ''
suffix_html = f'<span>{e(edit_suffix)}</span>' if edit_suffix else ''
input_wrap = (f'<div style="display:flex;align-items:center;gap:0.5em">'
f'<input type="{e(edit_input_type)}" name="{e(edit_field)}" value="{e(edit_raw)}"'
f' data-original="{e(edit_raw)}" class="form-input"{min_attr} style="width:5rem"/>'
f'{suffix_html}</div>')
return (
f'<div class="{cls} stat-card-editable">'
f'<div class="stat-card-label">{label}</div>'
@ -906,9 +918,9 @@ def _render_item(item, tokens, inherited_req=None):
f'</div>'
f'<form class="stat-card-edit-form" style="display:none" action="{e(edit_action)}" method="post">'
f'<input type="hidden" name="config_hash" value="{e(core_hash())}"/>'
f'<input type="text" name="{e(edit_field)}" value="{e(raw_value)}" class="form-input"/>'
f'{input_wrap}'
f'<div style="margin-top:0.5em;display:flex;gap:0.5em">'
f'<button type="submit" class="btn btn-primary btn-sm">Save</button>'
f'<button type="submit" class="btn btn-primary btn-sm" disabled>Save</button>'
f'<button type="button" class="btn btn-secondary btn-sm stat-card-cancel-btn">Cancel</button>'
f'</div>'
f'</form>'
@ -1072,8 +1084,9 @@ def _render_field(item, tokens):
checked = 'checked' if value.lower() in ('true', '1', 'yes') else ''
cb_label = item.get('checkbox_label')
if cb_label:
label_html = f'<label class="form-label">{label}</label>' if label else ''
return (f'<div class="form-group">'
f'<label class="form-label">{label}</label>'
f'{label_html}'
f'<label class="form-checkbox-row">'
f'<input type="checkbox" name="{name}" {checked} class="form-checkbox"/>'
f' <span class="form-checkbox-label">{e(cb_label)}</span>'
@ -1118,9 +1131,15 @@ def _render_field(item, tokens):
if input_type == 'number':
min_attr = f' min="{item["min"]}"' if 'min' in item else ''
max_attr = f' max="{item["max"]}"' if 'max' in item else ''
inp = (f'<input type="number" name="{name}" value="{e(value)}"{min_attr}{max_attr}'
f' class="form-input{extra_cls}"{readonly}/>')
if item.get('layout') == 'inline':
return (f'<div class="form-group" style="display:flex;align-items:center;gap:0.75em">'
f'<label class="form-label" style="margin:0;white-space:nowrap">{label}</label>'
f'<div style="width:6rem">{inp}</div>'
f'{hint_html}</div>')
return (f'<div class="form-group"><label class="form-label">{label}</label>'
f'<input type="number" name="{name}" value="{e(value)}"{min_attr}{max_attr} class="form-input{extra_cls}"{readonly}/>'
f'{hint_html}</div>')
f'{inp}{hint_html}</div>')
if input_type == 'textarea':
rows = item.get('rows', 4)
@ -2578,18 +2597,22 @@ document.querySelectorAll('.pre-block[data-scroll-bottom]').forEach(function(el)
el.scrollTop = el.scrollHeight;
});
(function() {
document.querySelectorAll('.stat-card-edit-btn').forEach(function(btn) {
btn.addEventListener('click', function() {
var card = btn.closest('.stat-card-editable');
document.querySelectorAll('.stat-card-editable').forEach(function(card) {
var form = card.querySelector('.stat-card-edit-form');
var input = form ? form.querySelector('input[data-original]') : null;
var saveBtn = form ? form.querySelector('button[type="submit"]') : null;
function updateSave() {
if (input && saveBtn) saveBtn.disabled = (input.value === input.dataset.original);
}
if (input) input.addEventListener('input', updateSave);
card.querySelector('.stat-card-edit-btn').addEventListener('click', function() {
card.querySelector('.stat-card-view').style.display = 'none';
card.querySelector('.stat-card-edit-form').style.display = '';
form.style.display = '';
});
});
document.querySelectorAll('.stat-card-cancel-btn').forEach(function(btn) {
btn.addEventListener('click', function() {
var card = btn.closest('.stat-card-editable');
form && form.querySelector('.stat-card-cancel-btn').addEventListener('click', function() {
card.querySelector('.stat-card-view').style.display = '';
card.querySelector('.stat-card-edit-form').style.display = 'none';
form.style.display = 'none';
if (input) { input.value = input.dataset.original; updateSave(); }
});
});
})();