Development
This commit is contained in:
parent
8ae6985503
commit
c8607ba8c5
3 changed files with 139 additions and 13 deletions
|
|
@ -459,7 +459,8 @@ DDNS_LOG_MAX = 50
|
|||
def _ddns_log_tail():
|
||||
log_path = f'{CONFIGS_DIR}/ddns.log'
|
||||
try:
|
||||
size_kb = os.path.getsize(log_path) / 1024
|
||||
log_max_kb = _load_ddns().get('general', {}).get('log_max_kb', 1024)
|
||||
size_kb = os.path.getsize(log_path) / 1024
|
||||
with open(log_path) as f:
|
||||
lines = f.readlines()
|
||||
if not lines:
|
||||
|
|
@ -468,10 +469,11 @@ def _ddns_log_tail():
|
|||
tail = lines[-DDNS_LOG_MAX:]
|
||||
shown = len(tail)
|
||||
hidden = total - shown
|
||||
size_str = f'{size_kb:.1f} KB'
|
||||
left = f'Showing last {shown} lines ({hidden} lines not shown)' if hidden > 0 else f'Showing {shown} lines'
|
||||
pct = min(100, round(size_kb / log_max_kb * 100)) if log_max_kb else 0
|
||||
left = f'Showing last {shown} lines ({hidden} lines not shown)' if hidden > 0 else f'Showing {shown} lines'
|
||||
right = f'Log file size: {size_kb:.1f} KB ({pct}% of max)'
|
||||
summary = (f'<div class="text-muted" style="display:flex;justify-content:space-between;margin-top:0.5em;">'
|
||||
f'<span>{left}</span><span>Log file size: {size_str}</span></div>')
|
||||
f'<span>{left}</span><span>{right}</span></div>')
|
||||
return ''.join(tail).strip(), summary
|
||||
except FileNotFoundError:
|
||||
return '(log file not found)', ''
|
||||
|
|
@ -570,7 +572,7 @@ def _ddns_last_checked():
|
|||
return f'Last checked: {_relative_time(dt.timestamp())}'
|
||||
except Exception:
|
||||
pass
|
||||
return ''
|
||||
return 'Last checked: ---'
|
||||
|
||||
def _vpn_info():
|
||||
for vlan in _load_core().get('vlans', []):
|
||||
|
|
@ -676,7 +678,10 @@ def collect_tokens():
|
|||
tokens['BLOCKLIST_STATS_HTML'] = _blocklist_stats_html(core)
|
||||
|
||||
ddns = _load_ddns()
|
||||
tokens['DDNS_TIMER_INTERVAL'] = ddns.get('general', {}).get('timer_interval', '-')
|
||||
ddns_gen = ddns.get('general', {})
|
||||
tokens['DDNS_TIMER_INTERVAL'] = ddns_gen.get('timer_interval', '-')
|
||||
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)]
|
||||
tokens['STAT_DDNS_PROVIDER_COUNT'] = str(len(enabled_p))
|
||||
_ddns_labels = {'noip': 'No-IP', 'cloudflare': 'Cloudflare', 'duckdns': 'DuckDNS'}
|
||||
|
|
@ -827,6 +832,9 @@ def _render_item(item, tokens, inherited_req=None):
|
|||
if t == 'h1':
|
||||
return f'<h1>{e(apply_tokens(item.get("text", ""), tokens))}</h1>'
|
||||
|
||||
if t == 'hr':
|
||||
return '<hr/>'
|
||||
|
||||
if t == 'p':
|
||||
text = e(apply_tokens(item.get('text', ''), tokens))
|
||||
link = item.get('link')
|
||||
|
|
@ -880,11 +888,33 @@ def _render_item(item, tokens, inherited_req=None):
|
|||
return f'<div class="stat-card-grid">{render_items(item.get("items", []), tokens, req)}</div>'
|
||||
|
||||
if t == 'stat_card':
|
||||
label = e(apply_tokens(item.get('label', ''), tokens))
|
||||
value = e(apply_tokens(item.get('value', ''), tokens))
|
||||
sub = e(apply_tokens(item.get('sub', ''), tokens))
|
||||
variant = item.get('variant', '')
|
||||
cls = f'stat-card{(" stat-card-" + variant) if variant else ""}'
|
||||
label = e(apply_tokens(item.get('label', ''), tokens))
|
||||
raw_value = apply_tokens(item.get('value', ''), tokens)
|
||||
value = e(raw_value)
|
||||
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', '')
|
||||
if edit_action and edit_field:
|
||||
return (
|
||||
f'<div class="{cls} stat-card-editable">'
|
||||
f'<div class="stat-card-label">{label}</div>'
|
||||
f'<div class="stat-card-view">'
|
||||
f'<span class="stat-card-value">{value}</span>'
|
||||
f'<button type="button" class="btn btn-ghost btn-sm stat-card-edit-btn">Edit</button>'
|
||||
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'<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="button" class="btn btn-secondary btn-sm stat-card-cancel-btn">Cancel</button>'
|
||||
f'</div>'
|
||||
f'</form>'
|
||||
f'<div class="stat-card-sub">{sub}</div>'
|
||||
f'</div>'
|
||||
)
|
||||
return (f'<div class="{cls}">'
|
||||
f'<div class="stat-card-label">{label}</div>'
|
||||
f'<div class="stat-card-value">{value}</div>'
|
||||
|
|
@ -2547,6 +2577,22 @@ function startApplyPoller(uuid, bar, mine) {
|
|||
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');
|
||||
card.querySelector('.stat-card-view').style.display = 'none';
|
||||
card.querySelector('.stat-card-edit-form').style.display = '';
|
||||
});
|
||||
});
|
||||
document.querySelectorAll('.stat-card-cancel-btn').forEach(function(btn) {
|
||||
btn.addEventListener('click', function() {
|
||||
var card = btn.closest('.stat-card-editable');
|
||||
card.querySelector('.stat-card-view').style.display = '';
|
||||
card.querySelector('.stat-card-edit-form').style.display = 'none';
|
||||
});
|
||||
});
|
||||
})();
|
||||
"""
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue