init biliup-next
This commit is contained in:
346
src/biliup_next/app/dashboard.py
Normal file
346
src/biliup_next/app/dashboard.py
Normal file
@ -0,0 +1,346 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
def render_dashboard_html() -> str:
|
||||
return """<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>biliup-next Control</title>
|
||||
<link rel="stylesheet" href="/assets/dashboard.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-shell">
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-brand">
|
||||
<p class="eyebrow">Biliup Next</p>
|
||||
<h1>Control</h1>
|
||||
<p class="sidebar-copy">围绕任务状态、运行时健康和配置管理组织的本地控制面。</p>
|
||||
</div>
|
||||
<nav class="sidebar-nav">
|
||||
<button class="nav-btn active" data-view="overview">Overview</button>
|
||||
<button class="nav-btn" data-view="tasks">Tasks</button>
|
||||
<button class="nav-btn" data-view="settings">Settings</button>
|
||||
<button class="nav-btn" data-view="logs">Logs</button>
|
||||
</nav>
|
||||
<div class="sidebar-section">
|
||||
<label class="sidebar-label">Control Token</label>
|
||||
<div class="sidebar-token">
|
||||
<input id="tokenInput" placeholder="optional control token" />
|
||||
<button id="saveTokenBtn" class="secondary compact">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-section">
|
||||
<div class="button-stack">
|
||||
<button id="refreshBtn">刷新视图</button>
|
||||
<button id="runOnceBtn" class="secondary">执行一轮 Worker</button>
|
||||
<button id="saveSettingsBtn" class="secondary">保存 Settings</button>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="content">
|
||||
<header class="topbar">
|
||||
<div>
|
||||
<p class="eyebrow">Operational Workspace</p>
|
||||
<h2 id="viewTitle">Overview</h2>
|
||||
</div>
|
||||
<div class="topbar-meta">
|
||||
<div class="status-chip">API · <span id="healthValue">-</span></div>
|
||||
<div class="status-chip">Doctor · <span id="doctorValue">-</span></div>
|
||||
<div class="status-chip">Tasks · <span id="tasksValue">-</span></div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div id="banner" class="banner"></div>
|
||||
|
||||
<section class="view active" data-view="overview">
|
||||
<div class="panel-grid two-up">
|
||||
<section class="panel">
|
||||
<div class="panel-head"><h3>Runtime Snapshot</h3></div>
|
||||
<div class="stats">
|
||||
<div class="stat-card">
|
||||
<span class="stat-label">Health</span>
|
||||
<strong id="overviewHealthValue" class="stat-value">-</strong>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<span class="stat-label">Doctor</span>
|
||||
<strong id="overviewDoctorValue" class="stat-value">-</strong>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<span class="stat-label">Tasks</span>
|
||||
<strong id="overviewTasksValue" class="stat-value">-</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div id="overviewTaskSummary" class="summary-strip" style="margin-top:14px;"></div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-head"><h3>Import To Stage</h3></div>
|
||||
<div class="field-grid">
|
||||
<input id="stageSourcePath" placeholder="/absolute/path/to/video.mp4" />
|
||||
<button id="importStageBtn" class="secondary">复制到隔离 Stage</button>
|
||||
</div>
|
||||
<div class="field-grid upload-grid">
|
||||
<input id="stageFileInput" type="file" />
|
||||
<button id="uploadStageBtn" class="secondary">上传到隔离 Stage</button>
|
||||
</div>
|
||||
<p class="muted-note">只会复制或上传到 `biliup-next/data/workspace/stage/`,不会移动原文件。</p>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="panel-grid two-up">
|
||||
<section class="panel">
|
||||
<div class="panel-head"><h3>Services</h3></div>
|
||||
<div id="serviceList" class="stack-list"></div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-head">
|
||||
<h3>Recent Actions</h3>
|
||||
<button id="refreshHistoryBtn" class="secondary compact">刷新</button>
|
||||
</div>
|
||||
<div class="filter-grid">
|
||||
<label class="checkbox-row"><input id="historyCurrentTask" type="checkbox" />仅当前任务</label>
|
||||
<select id="historyStatusFilter">
|
||||
<option value="">全部状态</option>
|
||||
<option value="ok">ok</option>
|
||||
<option value="warn">warn</option>
|
||||
<option value="error">error</option>
|
||||
</select>
|
||||
<input id="historyActionFilter" placeholder="action_name,如 worker_run_once" />
|
||||
</div>
|
||||
<div id="recentActionList" class="stack-list"></div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="panel-grid two-up">
|
||||
<section class="panel">
|
||||
<div class="panel-head">
|
||||
<h3>Scheduler Queue</h3>
|
||||
<button id="refreshSchedulerBtn" class="secondary compact">刷新</button>
|
||||
</div>
|
||||
<div id="schedulerSummary" class="summary-strip"></div>
|
||||
<div id="schedulerList" class="stack-list"></div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-head"><h3>Stage Scan Result</h3></div>
|
||||
<div id="stageScanSummary" class="stack-list"></div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="panel-grid two-up">
|
||||
<section class="panel">
|
||||
<div class="panel-head"><h3>Doctor Checks</h3></div>
|
||||
<div id="doctorChecks" class="stack-list"></div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-head"><h3>Retry & Manual Attention</h3></div>
|
||||
<div id="overviewRetrySummary" class="stack-list"></div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="panel-grid two-up">
|
||||
<section class="panel">
|
||||
<div class="panel-head"><h3>Modules</h3></div>
|
||||
<div id="moduleList" class="stack-list"></div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-head"><h3>Overview Notes</h3></div>
|
||||
<div class="stack-list">
|
||||
<div class="row-card">
|
||||
<strong>先看 Health / Doctor</strong>
|
||||
<div class="muted-note">系统级异常通常先体现在依赖检查,而不是单任务状态。</div>
|
||||
</div>
|
||||
<div class="row-card">
|
||||
<strong>再看 Retry Summary</strong>
|
||||
<div class="muted-note">优先处理已到重试时间和需要人工介入的任务。</div>
|
||||
</div>
|
||||
<div class="row-card">
|
||||
<strong>最后看 Recent Actions</strong>
|
||||
<div class="muted-note">用动作流判断最近系统是否真的在前进。</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="view" data-view="tasks">
|
||||
<div class="tasks-layout">
|
||||
<section class="panel task-index-panel">
|
||||
<div class="panel-head"><h3>Task Index</h3></div>
|
||||
<div class="task-index-summary">
|
||||
<div id="taskStatusSummary" class="summary-strip"></div>
|
||||
<div class="task-pagination-toolbar">
|
||||
<div id="taskPaginationSummary" class="muted-note">-</div>
|
||||
<div class="button-row">
|
||||
<select id="taskPageSizeSelect">
|
||||
<option value="12">12 / page</option>
|
||||
<option value="24" selected>24 / page</option>
|
||||
<option value="48">48 / page</option>
|
||||
</select>
|
||||
<button id="taskPrevPageBtn" class="secondary compact">上一页</button>
|
||||
<button id="taskNextPageBtn" class="secondary compact">下一页</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="task-filters">
|
||||
<input id="taskSearchInput" placeholder="搜索任务标题或 task id" />
|
||||
<select id="taskStatusFilter">
|
||||
<option value="">全部状态</option>
|
||||
<option value="created">created</option>
|
||||
<option value="transcribed">transcribed</option>
|
||||
<option value="songs_detected">songs_detected</option>
|
||||
<option value="split_done">split_done</option>
|
||||
<option value="published">published</option>
|
||||
<option value="collection_synced">collection_synced</option>
|
||||
<option value="failed_retryable">failed_retryable</option>
|
||||
<option value="failed_manual">failed_manual</option>
|
||||
</select>
|
||||
<select id="taskSortSelect">
|
||||
<option value="updated_desc">最近更新</option>
|
||||
<option value="updated_asc">最早更新</option>
|
||||
<option value="title_asc">标题 A-Z</option>
|
||||
<option value="title_desc">标题 Z-A</option>
|
||||
<option value="attention_state">按关注状态</option>
|
||||
<option value="status_group">按状态分组</option>
|
||||
<option value="split_comment_status">按纯享评论</option>
|
||||
<option value="full_comment_status">按主视频评论</option>
|
||||
<option value="cleanup_state">按清理状态</option>
|
||||
<option value="next_retry_asc">按下次重试</option>
|
||||
</select>
|
||||
<select id="taskDeliveryFilter">
|
||||
<option value="">全部交付状态</option>
|
||||
<option value="legacy_untracked">主视频评论未追踪</option>
|
||||
<option value="pending_comment">评论待完成</option>
|
||||
<option value="cleanup_removed">已清理视频</option>
|
||||
</select>
|
||||
<select id="taskAttentionFilter">
|
||||
<option value="">全部关注状态</option>
|
||||
<option value="manual_now">仅看需人工</option>
|
||||
<option value="retry_now">仅看到点重试</option>
|
||||
<option value="waiting_retry">仅看等待重试</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="taskListState" class="task-list-state">正在加载任务列表…</div>
|
||||
<div id="taskList" class="task-table-wrap"></div>
|
||||
</section>
|
||||
|
||||
<div class="task-workspace">
|
||||
<section class="panel task-panel">
|
||||
<div class="panel-head">
|
||||
<h3>Task Detail</h3>
|
||||
<div class="button-row">
|
||||
<button id="runTaskBtn" class="secondary compact">执行当前任务</button>
|
||||
<button id="retryStepBtn" class="secondary compact">重试选中 Step</button>
|
||||
<button id="resetStepBtn" class="secondary compact">重置到选中 Step</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="taskWorkspaceState" class="task-workspace-state show">选择一个任务后,这里会显示当前链路、重试状态和最近动作。</div>
|
||||
<div id="taskHero" class="task-hero empty">选择一个任务后,这里会显示当前链路、重试状态和最近动作。</div>
|
||||
<div id="taskRetryPanel" class="retry-banner hidden"></div>
|
||||
<div class="detail-layout">
|
||||
<div id="taskDetail" class="detail-grid"></div>
|
||||
<div id="taskSummary" class="summary-card">暂无最近结果</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="panel-grid two-up">
|
||||
<section class="panel">
|
||||
<div class="panel-head"><h3>Steps</h3></div>
|
||||
<div id="stepList" class="stack-list"></div>
|
||||
</section>
|
||||
<section class="panel">
|
||||
<div class="panel-head"><h3>Artifacts</h3></div>
|
||||
<div id="artifactList" class="stack-list"></div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="panel-grid two-up">
|
||||
<section class="panel">
|
||||
<div class="panel-head"><h3>History</h3></div>
|
||||
<div id="historyList" class="stack-list"></div>
|
||||
</section>
|
||||
<section class="panel">
|
||||
<div class="panel-head"><h3>Timeline</h3></div>
|
||||
<div id="timelineList" class="timeline-list"></div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="view" data-view="settings">
|
||||
<section class="panel">
|
||||
<div class="panel-head"><h3>Settings</h3></div>
|
||||
<div class="settings-toolbar">
|
||||
<input id="settingsSearch" placeholder="过滤配置项,例如 codex / season / retry" />
|
||||
<div class="button-row">
|
||||
<button id="syncFormToJsonBtn" class="secondary compact">表单同步到 JSON</button>
|
||||
<button id="syncJsonToFormBtn" class="secondary compact">JSON 重绘表单</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="settingsForm" class="settings-groups"></div>
|
||||
<details class="settings-advanced">
|
||||
<summary>Advanced JSON Editor</summary>
|
||||
<textarea id="settingsEditor" spellcheck="false"></textarea>
|
||||
</details>
|
||||
<p class="muted-note">敏感字段显示为 `__BILIUP_NEXT_SECRET__`。保留占位符表示不改原值,改为空字符串表示清空。</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="view" data-view="logs">
|
||||
<div class="logs-workspace">
|
||||
<section class="panel logs-index-panel">
|
||||
<div class="panel-head"><h3>Log Index</h3></div>
|
||||
<div class="task-filters">
|
||||
<input id="logSearchInput" placeholder="搜索日志文件名" />
|
||||
<label class="checkbox-row"><input id="filterCurrentTask" type="checkbox" />按当前任务标题过滤</label>
|
||||
<label class="checkbox-row"><input id="logAutoRefresh" type="checkbox" />自动刷新</label>
|
||||
</div>
|
||||
<div class="button-row" style="margin-bottom:12px;">
|
||||
<button id="refreshLogBtn" class="secondary compact">刷新日志</button>
|
||||
</div>
|
||||
<div id="logListState" class="task-list-state show">正在加载日志索引…</div>
|
||||
<div id="logList" class="task-list"></div>
|
||||
</section>
|
||||
<div class="log-content-stack">
|
||||
<section class="panel">
|
||||
<div class="panel-head"><h3>Log Content</h3></div>
|
||||
<div class="filter-grid">
|
||||
<input id="logLineFilter" placeholder="过滤内容关键字" />
|
||||
<div class="muted-note" id="logPath">-</div>
|
||||
<div class="muted-note" id="logMeta">-</div>
|
||||
</div>
|
||||
<pre id="logContent"></pre>
|
||||
</section>
|
||||
<section class="panel">
|
||||
<div class="panel-head"><h3>Logs Guide</h3></div>
|
||||
<div class="stack-list">
|
||||
<div class="row-card">
|
||||
<strong>优先看当前任务</strong>
|
||||
<div class="muted-note">勾选“按当前任务标题过滤”,可快速聚焦任务链路。</div>
|
||||
</div>
|
||||
<div class="row-card">
|
||||
<strong>先看系统,再看任务</strong>
|
||||
<div class="muted-note">如果服务异常,先看 `systemd` 状态;如果单任务异常,再看 steps/history/timeline。</div>
|
||||
</div>
|
||||
<div class="row-card">
|
||||
<strong>上传异常</strong>
|
||||
<div class="muted-note">优先看 `upload.log`、任务时间线里的 publish error,以及下一次重试时间。</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
<script type="module" src="/assets/app/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
Reference in New Issue
Block a user