1
0
forked from BRT/arc

Support datetime input for filters, improve date parsing logic, and update UI labels and button states in monitoring app.

This commit is contained in:
slava 2026-06-05 13:10:58 +05:00
parent 39e07ddb15
commit cfc562eae6

View File

@ -697,16 +697,22 @@ def _ts_str(ts: float) -> str:
def _parse_date(s: str, end: bool = False) -> Optional[float]: def _parse_date(s: str, end: bool = False) -> Optional[float]:
s = (s or "").strip() s = (s or "").strip().replace("T", " ")
if not s: if not s:
return None return None
try: # Принимаем как дату, так и дату со временем (datetime-local), всё в UTC.
d = datetime.strptime(s, "%Y-%m-%d").replace(tzinfo=timezone.utc) for fmt, has_time in (("%Y-%m-%d %H:%M:%S", True),
except ValueError: ("%Y-%m-%d %H:%M", True),
return None ("%Y-%m-%d", False)):
if end: try:
d += timedelta(days=1) d = datetime.strptime(s, fmt).replace(tzinfo=timezone.utc)
return d.timestamp() except ValueError:
continue
# Для верхней границы без времени берём весь день целиком.
if end and not has_time:
d += timedelta(days=1)
return d.timestamp()
return None
def _opt(value: str, current: str, label: str = "") -> str: def _opt(value: str, current: str, label: str = "") -> str:
@ -1127,11 +1133,11 @@ def admin_dashboard(
<label>Тип<select name=type>{type_opts}</select></label> <label>Тип<select name=type>{type_opts}</select></label>
<label>Event<input name=event value="{html_lib.escape(event)}" placeholder="task_error…"></label> <label>Event<input name=event value="{html_lib.escape(event)}" placeholder="task_error…"></label>
<label>Поиск в тексте<input name=q value="{html_lib.escape(q)}" placeholder="подстрока"></label> <label>Поиск в тексте<input name=q value="{html_lib.escape(q)}" placeholder="подстрока"></label>
<label>Дата с<input name=date_from type=date value="{html_lib.escape(date_from)}"></label> <label>С (UTC)<input name=date_from type=datetime-local step=1 value="{html_lib.escape(date_from)}"></label>
<label>Дата по<input name=date_to type=date value="{html_lib.escape(date_to)}"></label> <label>По (UTC)<input name=date_to type=datetime-local step=1 value="{html_lib.escape(date_to)}"></label>
<button type=submit>Фильтр</button> <button type=submit>Фильтр</button>
<a href="/admin"><button type=button class=sec>Сброс</button></a> <a href="/admin"><button type=button class=sec>Сброс</button></a>
<button id=arBtn type=button class=sec onclick="_arToggle()" style="min-width:90px">Стоп</button> <button id=arBtn type=button class=sec onclick="_arToggle()" style="min-width:90px">Старт</button>
<span id=arStatus class=muted style="font-size:12px;align-self:center"></span> <span id=arStatus class=muted style="font-size:12px;align-self:center"></span>
</form> </form>
<form id=bulkForm class=bulkbar method=post action="/admin/entries/delete" <form id=bulkForm class=bulkbar method=post action="/admin/entries/delete"
@ -1151,10 +1157,11 @@ def admin_dashboard(
{_LOCAL_TIME_JS} {_LOCAL_TIME_JS}
<script> <script>
(function(){{ (function(){{
var running = true; var running = false;
var timer = null; var timer = null;
var btn = document.getElementById('arBtn'); var btn = document.getElementById('arBtn');
var stat = document.getElementById('arStatus'); var stat = document.getElementById('arStatus');
stat.textContent='выключено';
function applyLocalTimes(scope){{ function applyLocalTimes(scope){{
var pad=function(n){{return(n<10?'0':'')+n;}}; var pad=function(n){{return(n<10?'0':'')+n;}};
@ -1199,8 +1206,6 @@ def admin_dashboard(
stat.textContent='на паузе'; stat.textContent='на паузе';
}} }}
}}; }};
tick();
}})(); }})();
</script> </script>
</body></html>""" </body></html>"""
@ -1630,8 +1635,8 @@ def admin_desktops(request: Request, date_from: str = "", date_to: str = "") ->
<title>ARC monitoring десктопы</title>{_STYLE}{_DESK_STYLE}</head><body> <title>ARC monitoring десктопы</title>{_STYLE}{_DESK_STYLE}</head><body>
{_header('desktops')} {_header('desktops')}
<form class=filters method=get action="/admin/desktops"> <form class=filters method=get action="/admin/desktops">
<label>Дата с<input name=date_from type=date value="{html_lib.escape(date_from)}"></label> <label>С (UTC)<input name=date_from type=datetime-local step=1 value="{html_lib.escape(date_from)}"></label>
<label>Дата по<input name=date_to type=date value="{html_lib.escape(date_to)}"></label> <label>По (UTC)<input name=date_to type=datetime-local step=1 value="{html_lib.escape(date_to)}"></label>
<button type=submit>Фильтр</button> <button type=submit>Фильтр</button>
<a href="/admin/desktops"><button type=button class=sec>Сброс</button></a> <a href="/admin/desktops"><button type=button class=sec>Сброс</button></a>
<button type=button class=sec onclick="return _collapseAll()">Свернуть всё</button> <button type=button class=sec onclick="return _collapseAll()">Свернуть всё</button>
@ -1838,8 +1843,8 @@ def admin_screens(request: Request, device: str = "",
{_header('screens')} {_header('screens')}
<form class=filters method=get action="/admin/screens"> <form class=filters method=get action="/admin/screens">
<label>Девайс<select name=device onchange="this.form.submit()">{''.join(dev_opts)}</select></label> <label>Девайс<select name=device onchange="this.form.submit()">{''.join(dev_opts)}</select></label>
<label>Дата с<input name=date_from type=date value="{html_lib.escape(date_from)}"></label> <label>С (UTC)<input name=date_from type=datetime-local step=1 value="{html_lib.escape(date_from)}"></label>
<label>Дата по<input name=date_to type=date value="{html_lib.escape(date_to)}"></label> <label>По (UTC)<input name=date_to type=datetime-local step=1 value="{html_lib.escape(date_to)}"></label>
<button type=submit>Фильтр</button> <button type=submit>Фильтр</button>
<a href="/admin/screens"><button type=button class=sec>Сброс</button></a> <a href="/admin/screens"><button type=button class=sec>Сброс</button></a>
<span class=muted>история экрана · хранение {SCREENSHOT_RETENTION_HOURS} ч · время UTC</span> <span class=muted>история экрана · хранение {SCREENSHOT_RETENTION_HOURS} ч · время UTC</span>
@ -1995,8 +2000,8 @@ def admin_dumps(request: Request, device: str = "",
{_header('dumps')} {_header('dumps')}
<form class=filters method=get action="/admin/dumps"> <form class=filters method=get action="/admin/dumps">
<label>Девайс<select name=device onchange="this.form.submit()">{''.join(dev_opts)}</select></label> <label>Девайс<select name=device onchange="this.form.submit()">{''.join(dev_opts)}</select></label>
<label>Дата с<input name=date_from type=date value="{html_lib.escape(date_from)}"></label> <label>С (UTC)<input name=date_from type=datetime-local step=1 value="{html_lib.escape(date_from)}"></label>
<label>Дата по<input name=date_to type=date value="{html_lib.escape(date_to)}"></label> <label>По (UTC)<input name=date_to type=datetime-local step=1 value="{html_lib.escape(date_to)}"></label>
<button type=submit>Фильтр</button> <button type=submit>Фильтр</button>
<a href="/admin/dumps"><button type=button class=sec>Сброс</button></a> <a href="/admin/dumps"><button type=button class=sec>Сброс</button></a>
<span class=muted>XML + скриншот · хранение {SCREEN_DUMP_RETENTION_DAYS} сут · время UTC</span> <span class=muted>XML + скриншот · хранение {SCREEN_DUMP_RETENTION_DAYS} сут · время UTC</span>