mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-21 01:00:24 +08:00
320 lines
13 KiB
HTML
320 lines
13 KiB
HTML
<!doctype html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<meta name="color-scheme" content="light" />
|
||
<meta name="theme-color" content="#19353d" />
|
||
<meta
|
||
http-equiv="Content-Security-Policy"
|
||
content="default-src 'none'; script-src 'self'; style-src 'self'; connect-src 'self'; img-src 'self'; base-uri 'none'; form-action 'none'"
|
||
/>
|
||
<title>QingLong 3.0 · 自动化值班台</title>
|
||
<link rel="stylesheet" href="/console.css" />
|
||
<script src="/console.js" defer></script>
|
||
</head>
|
||
<body>
|
||
<a class="skip-link" href="#workspace">跳到操作区</a>
|
||
<div class="shell">
|
||
<aside class="gate" aria-label="连接与导航">
|
||
<header class="brand">
|
||
<span class="brand-mark" aria-hidden="true"><i></i><i></i><i></i></span>
|
||
<span class="brand-name">QingLong</span>
|
||
<span class="brand-version">3.0</span>
|
||
</header>
|
||
|
||
<section class="gate-copy">
|
||
<p class="eyebrow">Local operations</p>
|
||
<h1>自动化<br />值班台</h1>
|
||
<p>在一块屏幕上看清任务、运行与事件,然后只执行你明确确认的动作。</p>
|
||
</section>
|
||
|
||
<div class="connection-state" id="connection-state" data-state="idle">
|
||
<span class="signal" aria-hidden="true"></span>
|
||
<span id="connection-label">等待凭据</span>
|
||
</div>
|
||
|
||
<form id="credential-form" class="credential-form" autocomplete="off">
|
||
<label for="project-input">项目</label>
|
||
<input
|
||
id="project-input"
|
||
name="project"
|
||
value="default"
|
||
inputmode="text"
|
||
maxlength="128"
|
||
spellcheck="false"
|
||
required
|
||
/>
|
||
<label for="token-input">API Credential</label>
|
||
<input
|
||
id="token-input"
|
||
name="token"
|
||
type="password"
|
||
placeholder="ql3c_…"
|
||
maxlength="128"
|
||
spellcheck="false"
|
||
autocomplete="off"
|
||
required
|
||
/>
|
||
<button class="primary-button" type="submit">连接本机</button>
|
||
<button class="quiet-button" id="disconnect-button" type="button" hidden>
|
||
断开并清除凭据
|
||
</button>
|
||
<p class="privacy-note">凭据只保存在当前页面内存;不写入 URL、Cookie 或浏览器存储。</p>
|
||
</form>
|
||
|
||
<nav class="section-nav" aria-label="工作区" hidden>
|
||
<button type="button" data-view="tasks" aria-current="page">
|
||
<span>任务</span><kbd>T</kbd>
|
||
</button>
|
||
<button type="button" data-view="triggers">
|
||
<span>定时</span><kbd>S</kbd>
|
||
</button>
|
||
<button type="button" data-view="secrets">
|
||
<span>凭据</span><kbd>K</kbd>
|
||
</button>
|
||
<button type="button" data-view="runs">
|
||
<span>运行</span><kbd>R</kbd>
|
||
</button>
|
||
</nav>
|
||
|
||
<footer class="gate-footer">
|
||
<span>Loopback only</span>
|
||
<span>Alpha · API v3</span>
|
||
</footer>
|
||
</aside>
|
||
|
||
<main id="workspace" class="workspace" tabindex="-1">
|
||
<header class="masthead">
|
||
<div>
|
||
<p class="eyebrow" id="section-kicker">Connection gate</p>
|
||
<h2 id="section-title">先建立一条本机连接</h2>
|
||
<p id="section-description">
|
||
输入 quickstart 交付的 Owner API Credential。连接成功后才能读取或执行操作。
|
||
</p>
|
||
</div>
|
||
<div class="masthead-actions">
|
||
<button class="action-button" id="create-task-button" type="button" hidden>
|
||
<span aria-hidden="true">+</span> 创建任务
|
||
</button>
|
||
<button class="action-button" id="create-trigger-button" type="button" hidden>
|
||
<span aria-hidden="true">+</span> 创建定时
|
||
</button>
|
||
<button class="action-button" id="create-secret-button" type="button" hidden>
|
||
<span aria-hidden="true">+</span> 创建凭据
|
||
</button>
|
||
<button class="refresh-button" id="refresh-button" type="button" hidden>
|
||
<span aria-hidden="true">↻</span> 刷新
|
||
</button>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="workspace-grid">
|
||
<section class="ledger" id="ledger" aria-live="polite" aria-busy="false">
|
||
<div class="welcome-state">
|
||
<span class="welcome-index">QL / 03</span>
|
||
<p>任务是计划,运行是事实,事件是证据。</p>
|
||
<div class="welcome-rule" aria-hidden="true"><i></i><i></i><i></i></div>
|
||
</div>
|
||
</section>
|
||
|
||
<aside class="detail" id="detail" aria-label="详情">
|
||
<div class="detail-empty">
|
||
<span class="detail-glyph" aria-hidden="true">⌁</span>
|
||
<p>选择一项,查看它的执行围栏与事件轨迹。</p>
|
||
</div>
|
||
</aside>
|
||
</div>
|
||
</main>
|
||
</div>
|
||
|
||
<dialog id="confirmation-dialog" class="confirmation-dialog">
|
||
<form method="dialog">
|
||
<p class="eyebrow">Explicit action</p>
|
||
<h2 id="confirmation-title">确认操作</h2>
|
||
<p id="confirmation-copy"></p>
|
||
<div class="dialog-actions">
|
||
<button class="quiet-button" value="cancel">返回</button>
|
||
<button class="danger-button" id="confirmation-accept" value="accept">
|
||
确认
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</dialog>
|
||
|
||
<dialog id="task-editor-dialog" class="task-editor-dialog">
|
||
<form id="task-editor-form" autocomplete="off">
|
||
<div class="dialog-heading">
|
||
<div>
|
||
<p class="eyebrow">Task authoring</p>
|
||
<h2 id="task-editor-title">创建命令任务</h2>
|
||
</div>
|
||
<button class="quiet-button" id="task-editor-close" type="button">关闭</button>
|
||
</div>
|
||
<p class="editor-intro" id="task-editor-intro">
|
||
定义会先绑定到一次本机证明,再以同一事务写入 Task revision 与安全审计。
|
||
</p>
|
||
<div class="editor-grid">
|
||
<label>
|
||
<span>Task ID</span>
|
||
<input id="task-id-input" maxlength="128" spellcheck="false" required />
|
||
</label>
|
||
<label>
|
||
<span>名称</span>
|
||
<input id="task-name-input" maxlength="160" required />
|
||
</label>
|
||
<label class="editor-wide">
|
||
<span>说明(可选)</span>
|
||
<input id="task-description-input" maxlength="1000" />
|
||
</label>
|
||
<label class="editor-wide">
|
||
<span>可执行文件</span>
|
||
<input
|
||
id="task-command-input"
|
||
value="/bin/echo"
|
||
maxlength="4096"
|
||
spellcheck="false"
|
||
required
|
||
/>
|
||
</label>
|
||
<label class="editor-wide">
|
||
<span>参数 · 每行一个</span>
|
||
<textarea id="task-args-input" rows="5" maxlength="16384" spellcheck="false"></textarea>
|
||
</label>
|
||
<label class="editor-wide">
|
||
<span>Secret 环境变量 · 每行 ENV=secret-name@version</span>
|
||
<textarea id="task-secret-bindings-input" rows="4" maxlength="24576" spellcheck="false" placeholder="API_TOKEN=github-token"></textarea>
|
||
</label>
|
||
<label class="editor-check">
|
||
<input id="task-enabled-input" type="checkbox" checked />
|
||
<span id="task-enabled-label">创建后允许运行</span>
|
||
</label>
|
||
</div>
|
||
<p class="editor-note" id="task-editor-note">
|
||
Alpha 当前从 Console 创建 <code>qinglong/command@v1</code>;高级 Task schema 仍使用受信任管理入口。
|
||
</p>
|
||
<div class="dialog-actions">
|
||
<button class="primary-button" id="task-editor-save" type="submit">
|
||
保存并生成本机证明
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</dialog>
|
||
|
||
<dialog id="trigger-editor-dialog" class="task-editor-dialog">
|
||
<form id="trigger-editor-form" autocomplete="off">
|
||
<div class="dialog-heading">
|
||
<div>
|
||
<p class="eyebrow">Cron scheduling</p>
|
||
<h2 id="trigger-editor-title">创建定时触发器</h2>
|
||
</div>
|
||
<button class="quiet-button" id="trigger-editor-close" type="button">关闭</button>
|
||
</div>
|
||
<p class="editor-intro" id="trigger-editor-intro">
|
||
Trigger 会绑定 Task 当前 revision 与内容摘要;Task 改变后需重新保存定时配置。
|
||
</p>
|
||
<div class="editor-grid">
|
||
<label>
|
||
<span>Trigger ID</span>
|
||
<input id="trigger-id-input" maxlength="128" spellcheck="false" required />
|
||
</label>
|
||
<label>
|
||
<span>Task ID</span>
|
||
<input id="trigger-task-id-input" maxlength="128" spellcheck="false" required />
|
||
</label>
|
||
<label class="editor-wide">
|
||
<span>Cron 表达式 · 5 或 6 段</span>
|
||
<input id="trigger-expression-input" value="0 * * * *" maxlength="512" spellcheck="false" required />
|
||
</label>
|
||
<label>
|
||
<span>时区</span>
|
||
<input id="trigger-timezone-input" value="UTC" maxlength="128" spellcheck="false" required />
|
||
</label>
|
||
<label>
|
||
<span>错过执行窗口</span>
|
||
<select id="trigger-misfire-input">
|
||
<option value="skip">跳过</option>
|
||
<option value="fire_once">补跑一次</option>
|
||
</select>
|
||
</label>
|
||
<label class="editor-check">
|
||
<input id="trigger-enabled-input" type="checkbox" checked />
|
||
<span>保存后启用自动执行</span>
|
||
</label>
|
||
</div>
|
||
<p class="editor-note">
|
||
当前 Console 只开放内置 <code>qinglong/cron@v1</code>;停用会写入新 revision,不删除历史。
|
||
</p>
|
||
<div class="dialog-actions">
|
||
<button class="primary-button" id="trigger-editor-save" type="submit">
|
||
保存并生成本机证明
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</dialog>
|
||
|
||
<dialog id="secret-editor-dialog" class="task-editor-dialog">
|
||
<form id="secret-editor-form" autocomplete="off">
|
||
<div class="dialog-heading">
|
||
<div>
|
||
<p class="eyebrow">Encrypted Secret custody</p>
|
||
<h2 id="secret-editor-title">创建加密凭据</h2>
|
||
</div>
|
||
<button class="quiet-button" id="secret-editor-close" type="button">关闭</button>
|
||
</div>
|
||
<p class="editor-intro" id="secret-editor-intro">
|
||
明文只在当前页面内存和本次 loopback 请求中短暂存在;服务端只持久化 AES-256-GCM 密文。
|
||
</p>
|
||
<div class="editor-grid">
|
||
<label class="editor-wide">
|
||
<span>Secret 名称</span>
|
||
<input id="secret-name-input" maxlength="128" spellcheck="false" autocomplete="off" required />
|
||
</label>
|
||
<label class="editor-wide">
|
||
<span>新值</span>
|
||
<input id="secret-value-input" type="password" maxlength="16384" spellcheck="false" autocomplete="new-password" required />
|
||
</label>
|
||
</div>
|
||
<p class="editor-note" id="secret-editor-note">
|
||
保存需要一次性本机证明;API、审计、Console 与日志都不会返回明文。
|
||
</p>
|
||
<div class="dialog-actions">
|
||
<button class="primary-button" id="secret-editor-save" type="submit">
|
||
加密保存并生成本机证明
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</dialog>
|
||
|
||
<dialog id="presence-dialog" class="presence-dialog">
|
||
<form id="presence-form" autocomplete="off">
|
||
<p class="eyebrow">Local presence · 02:00</p>
|
||
<h2>从部署设备取得证明</h2>
|
||
<p id="presence-copy">
|
||
使用部署 QingLong 的系统用户读取下面的私有文件。证明只绑定这次操作,且只能使用一次。
|
||
</p>
|
||
<code class="proof-ticket" id="presence-file"></code>
|
||
<label class="presence-input">
|
||
<span>文件中的 proof</span>
|
||
<input
|
||
id="presence-proof-input"
|
||
type="password"
|
||
maxlength="128"
|
||
spellcheck="false"
|
||
autocomplete="off"
|
||
required
|
||
/>
|
||
</label>
|
||
<p class="presence-expiry" id="presence-expiry"></p>
|
||
<p class="presence-error" id="presence-error" role="alert" hidden></p>
|
||
<div class="dialog-actions">
|
||
<button class="quiet-button" id="presence-cancel" type="button">取消</button>
|
||
<button class="primary-button" id="presence-submit" type="submit">验证并继续</button>
|
||
</div>
|
||
</form>
|
||
</dialog>
|
||
|
||
<div class="toast" id="toast" role="status" aria-live="polite" hidden></div>
|
||
</body>
|
||
</html>
|