feat(worktime): localize rdp worktime report
This commit is contained in:
@@ -311,10 +311,10 @@ def render_html(rows, host, report_date, selected_day=None):
|
|||||||
json_url = "/reports/worktime/today?" + urlencode({"host": resolve_host(host), **({"day": selected_day} if selected_day in {"today", "yesterday"} else {"date": date_local})})
|
json_url = "/reports/worktime/today?" + urlencode({"host": resolve_host(host), **({"day": selected_day} if selected_day in {"today", "yesterday"} else {"date": date_local})})
|
||||||
form_action = "/reports/worktime/today"
|
form_action = "/reports/worktime/today"
|
||||||
cards = [
|
cards = [
|
||||||
("Users", str(summary["users_count"])),
|
("Пользователи", str(summary["users_count"])),
|
||||||
("Total active", summary["total_active_hhmm"]),
|
("Активное время", summary["total_active_hhmm"]),
|
||||||
("Top user", f"{summary['top_user']} · {summary['top_user_active_hhmm']}" if summary["top_user"] else "n/a"),
|
("Лидер дня", f"{summary['top_user']} · {summary['top_user_active_hhmm']}" if summary["top_user"] else "н/д"),
|
||||||
("Range", f"{summary['first_activity']} -> {summary['last_activity']}" if summary["first_activity"] else "no activity"),
|
("Диапазон", f"{summary['first_activity']} -> {summary['last_activity']}" if summary["first_activity"] else "нет активности"),
|
||||||
]
|
]
|
||||||
trs = []
|
trs = []
|
||||||
detail_cards = []
|
detail_cards = []
|
||||||
@@ -345,12 +345,12 @@ def render_html(rows, host, report_date, selected_day=None):
|
|||||||
"<span class='badge'>{active}</span>"
|
"<span class='badge'>{active}</span>"
|
||||||
"</div>"
|
"</div>"
|
||||||
"<div class='detail-grid'>"
|
"<div class='detail-grid'>"
|
||||||
"<div><span>User ID</span><strong>{user_id}</strong></div>"
|
"<div><span>Пользователь</span><strong>{user_id}</strong></div>"
|
||||||
"<div><span>Utilization</span><strong>{utilization}%</strong></div>"
|
"<div><span>Загрузка</span><strong>{utilization}%</strong></div>"
|
||||||
"<div><span>First activity</span><strong>{first_activity}</strong></div>"
|
"<div><span>Начало активности</span><strong>{first_activity}</strong></div>"
|
||||||
"<div><span>Last activity</span><strong>{last_activity}</strong></div>"
|
"<div><span>Конец активности</span><strong>{last_activity}</strong></div>"
|
||||||
"<div><span>Sessions</span><strong>{sessions}</strong></div>"
|
"<div><span>Сессии</span><strong>{sessions}</strong></div>"
|
||||||
"<div><span>Active samples</span><strong>{active_samples} / {samples}</strong></div>"
|
"<div><span>Активные сэмплы</span><strong>{active_samples} / {samples}</strong></div>"
|
||||||
"</div>"
|
"</div>"
|
||||||
"</article>"
|
"</article>"
|
||||||
.format(
|
.format(
|
||||||
@@ -359,21 +359,21 @@ def render_html(rows, host, report_date, selected_day=None):
|
|||||||
active=html.escape(row["active_hhmm"]),
|
active=html.escape(row["active_hhmm"]),
|
||||||
user_id=html.escape(row["user_id"]),
|
user_id=html.escape(row["user_id"]),
|
||||||
utilization=utilization,
|
utilization=utilization,
|
||||||
first_activity=html.escape(row["first_activity"] or "n/a"),
|
first_activity=html.escape(row["first_activity"] or "н/д"),
|
||||||
last_activity=html.escape(row["last_activity"] or "n/a"),
|
last_activity=html.escape(row["last_activity"] or "н/д"),
|
||||||
sessions=row["sessions_count"],
|
sessions=row["sessions_count"],
|
||||||
active_samples=row["active_samples"],
|
active_samples=row["active_samples"],
|
||||||
samples=row["samples_count"],
|
samples=row["samples_count"],
|
||||||
))
|
))
|
||||||
if not trs:
|
if not trs:
|
||||||
trs.append('<tr><td colspan="9">No data for today yet.</td></tr>')
|
trs.append('<tr><td colspan="9">За выбранную дату данных пока нет.</td></tr>')
|
||||||
detail_cards.append("<article class='detail-card empty'><h3>No per-user activity for selected date.</h3></article>")
|
detail_cards.append("<article class='detail-card empty'><h3>За выбранную дату нет активности пользователей.</h3></article>")
|
||||||
return f"""<!doctype html>
|
return f"""<!doctype html>
|
||||||
<html lang="en">
|
<html lang="ru">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>AW-rus Worktime</title>
|
<title>AW-rus Отчёт по работе в RDP</title>
|
||||||
<style>
|
<style>
|
||||||
:root {{
|
:root {{
|
||||||
color-scheme: light;
|
color-scheme: light;
|
||||||
@@ -553,20 +553,20 @@ def render_html(rows, host, report_date, selected_day=None):
|
|||||||
<body>
|
<body>
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
<section class="hero">
|
<section class="hero">
|
||||||
<h1>RDP Worktime Report</h1>
|
<h1>Отчёт по работе в RDP</h1>
|
||||||
<div class="meta">Host: {resolve_host(host)} · Date: {date_local} · Timezone: {REPORT_TZ} · Generated UTC: {generated}</div>
|
<div class="meta">Хост: {resolve_host(host)} · Дата: {date_local} · Часовой пояс: {REPORT_TZ} · Сформировано UTC: {generated}</div>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<a href="{today_url}">Today</a>
|
<a href="{today_url}">Сегодня</a>
|
||||||
<a href="{yesterday_url}">Yesterday</a>
|
<a href="{yesterday_url}">Вчера</a>
|
||||||
<a href="{csv_url}">Download CSV</a>
|
<a href="{csv_url}">Скачать CSV</a>
|
||||||
<a href="{json_url}">View JSON</a>
|
<a href="{json_url}">Открыть JSON</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<form method="get" action="{form_action}">
|
<form method="get" action="{form_action}">
|
||||||
<input type="hidden" name="format" value="html">
|
<input type="hidden" name="format" value="html">
|
||||||
<input type="hidden" name="host" value="{html.escape(resolve_host(host))}">
|
<input type="hidden" name="host" value="{html.escape(resolve_host(host))}">
|
||||||
<input type="date" name="date" value="{date_local}">
|
<input type="date" name="date" value="{date_local}">
|
||||||
<button type="submit">Open Date</button>
|
<button type="submit">Открыть дату</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="summary-grid">
|
<div class="summary-grid">
|
||||||
@@ -574,19 +574,19 @@ def render_html(rows, host, report_date, selected_day=None):
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section class="card">
|
<section class="card">
|
||||||
<h2 class="section-title">Per-user table</h2>
|
<h2 class="section-title">Таблица по пользователям</h2>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>User</th>
|
<th>Пользователь</th>
|
||||||
<th>User ID</th>
|
<th>Учётная запись</th>
|
||||||
<th>Active</th>
|
<th>Активно</th>
|
||||||
<th>Active sec</th>
|
<th>Активно, сек</th>
|
||||||
<th>First activity</th>
|
<th>Начало активности</th>
|
||||||
<th>Last activity</th>
|
<th>Конец активности</th>
|
||||||
<th>Idle sec</th>
|
<th>Простой, сек</th>
|
||||||
<th>Sessions</th>
|
<th>Сессии</th>
|
||||||
<th>Samples</th>
|
<th>Сэмплы</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -595,7 +595,7 @@ def render_html(rows, host, report_date, selected_day=None):
|
|||||||
</table>
|
</table>
|
||||||
</section>
|
</section>
|
||||||
<section class="card">
|
<section class="card">
|
||||||
<h2 class="section-title">Per-user details</h2>
|
<h2 class="section-title">Детали по пользователям</h2>
|
||||||
<div class="details-wrap">
|
<div class="details-wrap">
|
||||||
{''.join(detail_cards)}
|
{''.join(detail_cards)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,11 +13,11 @@
|
|||||||
if (!existing) return;
|
if (!existing) return;
|
||||||
|
|
||||||
existing.innerHTML =
|
existing.innerHTML =
|
||||||
'RDP report: ' +
|
'RDP отчёт: ' +
|
||||||
'<a href="' + htmlUrl + '" style="color:#fcd34d" target="_blank">HTML</a> | ' +
|
'<a href="' + htmlUrl + '" style="color:#fcd34d" target="_blank">HTML</a> | ' +
|
||||||
'<a href="' + csvUrl + '" style="color:#7dd3fc" target="_blank">CSV</a> | ' +
|
'<a href="' + csvUrl + '" style="color:#7dd3fc" target="_blank">CSV</a> | ' +
|
||||||
'<a href="' + jsonUrl + '" style="color:#86efac" target="_blank">JSON</a> | ' +
|
'<a href="' + jsonUrl + '" style="color:#86efac" target="_blank">JSON</a> | ' +
|
||||||
'<a href="#" id="aw-report-toggle" style="color:#f9fafb">Panel</a>';
|
'<a href="#" id="aw-report-toggle" style="color:#f9fafb">Панель</a>';
|
||||||
|
|
||||||
var panel = document.createElement("div");
|
var panel = document.createElement("div");
|
||||||
panel.id = "aw-report-panel";
|
panel.id = "aw-report-panel";
|
||||||
@@ -38,12 +38,12 @@
|
|||||||
|
|
||||||
panel.innerHTML =
|
panel.innerHTML =
|
||||||
'<div style="display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:#0f172a;color:#fff;font:600 13px/1.2 sans-serif">' +
|
'<div style="display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:#0f172a;color:#fff;font:600 13px/1.2 sans-serif">' +
|
||||||
'<div>RDP Worktime Report</div>' +
|
'<div>Отчёт по работе в RDP</div>' +
|
||||||
'<div style="display:flex;gap:12px;align-items:center">' +
|
'<div style="display:flex;gap:12px;align-items:center">' +
|
||||||
'<a href="' + htmlUrl + '" target="_blank" style="color:#93c5fd;text-decoration:none">Open</a>' +
|
'<a href="' + htmlUrl + '" target="_blank" style="color:#93c5fd;text-decoration:none">Открыть</a>' +
|
||||||
'<a href="#" id="aw-report-close" style="color:#fff;text-decoration:none">Close</a>' +
|
'<a href="#" id="aw-report-close" style="color:#fff;text-decoration:none">Закрыть</a>' +
|
||||||
"</div></div>" +
|
"</div></div>" +
|
||||||
'<iframe src="' + htmlUrl + '" title="RDP Worktime Report" style="border:0;width:100%;height:calc(100% - 42px);background:#fff"></iframe>';
|
'<iframe src="' + htmlUrl + '" title="Отчёт по работе в RDP" style="border:0;width:100%;height:calc(100% - 42px);background:#fff"></iframe>';
|
||||||
|
|
||||||
document.body.appendChild(panel);
|
document.body.appendChild(panel);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user