Development

This commit is contained in:
Matthew Grotke 2026-05-24 03:02:10 -04:00
parent e289583c4b
commit efdc2c63f2
4 changed files with 114 additions and 7 deletions

View file

@ -324,10 +324,10 @@ def _config_datasource(name):
if ptype == 'noip':
row['credentials'] = (f'<div style="line-height:1.3">'
f'<b>U:</b> {e(p.get("username", "-"))}<br/>'
f'<b>P:</b> &bull;&bull;&bull;</div>')
f'<b>P:</b> &bull;&bull;&bull;&bull;&bull;&bull;</div>')
elif ptype in ('cloudflare', 'duckdns'):
tok = p.get('api_token', '')
row['credentials'] = f'<b>API Token:</b> {e(tok[:24])}...' if tok else '(not set)'
row['credentials'] = f'<b>API Token:</b> {e(tok[:20])}...' if tok else '(not set)'
else:
row['credentials'] = '-'
row['hostnames'] = json.dumps(p.get('hostnames', p.get('subdomains', [])))
@ -686,6 +686,13 @@ def collect_tokens():
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)]
tokens['STAT_DDNS_PROVIDER_COUNT'] = str(len(enabled_p))
_ip_check = ddns.get('ip_check_services', [])
_http_svc = [s['url'] for s in _ip_check if s.get('type') == 'http']
_dig_svc = [s['url'] for s in _ip_check if s.get('type') == 'dig']
tokens['STAT_IP_CHECK_TOTAL'] = str(len(_ip_check))
tokens['STAT_IP_CHECK_SUB'] = f'{len(_http_svc)} http and {len(_dig_svc)} dig'
tokens['IP_CHECK_HTTP_JSON'] = json.dumps(_http_svc)
tokens['IP_CHECK_DIG_JSON'] = json.dumps(_dig_svc)
_ddns_labels = {'noip': 'No-IP', 'cloudflare': 'Cloudflare', 'duckdns': 'DuckDNS'}
tokens['DDNS_PROVIDER_OPTIONS'] = json.dumps([
{'value': p, 'label': _ddns_labels.get(p, p.title())}
@ -872,8 +879,9 @@ def _render_item(item, tokens, inherited_req=None):
return f'<a href="{action}" class="btn {e(cls)}">{text}</a>'
if t == 'button_cancel':
text = e(apply_tokens(item.get('text', 'Cancel'), tokens))
return f'<button type="button" class="btn btn-secondary btn-cancel" disabled>{text}</button>'
text = e(apply_tokens(item.get('text', 'Cancel'), tokens))
extra_cls = (' ' + item['class']) if item.get('class') else ''
return f'<button type="button" class="btn btn-secondary btn-cancel{extra_cls}" disabled>{text}</button>'
if t == 'page_header':
return f'<div class="page-header">{render_items(item.get("items", []), tokens, req)}</div>'
@ -902,6 +910,19 @@ def _render_item(item, tokens, inherited_req=None):
edit_suffix = item.get('edit_suffix', '')
edit_min = item.get('edit_min', '')
edit_raw = apply_tokens(item.get('edit_value', item.get('value', '')), tokens)
reveal_card_id = item.get('reveal_card_id', '')
if reveal_card_id:
return (
f'<div class="{cls}">'
f'<div class="stat-card-label">{label}</div>'
f'<div style="display:flex;align-items:center;gap:0.5em">'
f'<span class="stat-card-value">{value}</span>'
f'<button type="button" class="btn btn-ghost btn-sm"'
f' data-reveal-card="{e(reveal_card_id)}">Edit</button>'
f'</div>'
f'<div class="stat-card-sub">{sub}</div>'
f'</div>'
)
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 ''
@ -2596,6 +2617,12 @@ function startApplyPoller(uuid, bar, mine) {
document.querySelectorAll('.pre-block[data-scroll-bottom]').forEach(function(el) {
el.scrollTop = el.scrollHeight;
});
document.querySelectorAll('[data-reveal-card]').forEach(function(btn) {
btn.addEventListener('click', function() {
var card = document.getElementById(btn.dataset.revealCard);
if (card) card.style.display = card.style.display === 'none' ? '' : 'none';
});
});
(function() {
document.querySelectorAll('.stat-card-editable').forEach(function(card) {
var form = card.querySelector('.stat-card-edit-form');