Console: Overview home and Inbox
维护者通常 1 天内回复
评估
- 难度
- 5/5
- 预计耗时
- 一周以上
- 新手友好度
- 38/100
- Issue 类型
- 功能
- 描述清晰度
- 描述清楚
- 活跃度
- 活跃
- 技术栈
- react, typescript
调研方向
Start by reading the named UI modules, especially ui/src/model/inbox.ts and ui/src/model/overview.ts, plus the existing Overview and Attention screens and their end to end specs. Then trace the named state modules and routes to see how workers, requests, leases, tokens, stats and events feed the pages. Done means Overview, Inbox and Usage match the specified content, ordering, links and failure behavior, with the named UI and end to end specs updated; the issue spans many screens, shared state and routing.
由索引模型根据 Issue 内容生成。
描述
Part of #756.
Scope
The home page becomes Overview, giving the whole system at a glance, and Inbox replaces Attention as the full list of what needs a person. After this PR an operator sees on one page whether anything is wrong, how full each platform is, and how busy the last hour was. They see every item that needs them, including long waits, absent phones and leases about to end. Usage moves into the shared frame too.
In short
/ shows five numbers:
- Leased: leases held of all devices, with the ready count under it.
- Waiting: requests waiting, with the longest wait under it.
- Workers: connected of all workers.
- Wait p95: the 95th percentile wait in the range picked.
- Ending soon: leases with under 5 minutes left (
EXPIRING_UNDER_MS, which goes from 15 to 5 minutes here, so the Leases page's filter becomes "Ending < 5 min").
Under them:
-
When the Inbox has no problem item and every read it rests on succeeded, one line: "Nothing needs you". When a read failed, one line instead: "Could not check: ", for example "Could not check: waiting requests". It never says "Nothing needs you" then.
-
When the Inbox has problem items, a Needs you panel shows the first four in Inbox order, each row opening its drawer at
/inbox/<key>. Under them is the link "All in Inbox ()". -
Capacity · all workers: one bar per platform (iOS, Android), counting every device of every worker the console has read, except
deletedones. The parts:- leased;
- ready;
- booting (
provisioningorreclaiming); - drained (ready, on a drained worker);
- quarantined;
- absent;
- shut down;
- offline (any state, on a worker that is not connected).
Each part shows its count and word. A connected worker whose devices are not read yet adds nothing, and the bar says "1 worker not read yet" or " workers not read yet".
-
Two charts for the range in
?range=(1h, 6h, 24h, 7d), under today's titles Leases held and Requests in the queue. The range chips sit in the shared toolbar under the header, on the left, as on Usage. -
The workers table from Fleet (#766), with all workers and no pager, and a link "Open Fleet".
Today's Utilisation tile, the Device slots in use chart, the Granted figure and the Recent activity panel leave Overview. The Device slots in use chart moves to Usage. Usage is rebuilt in the shared frame: its header, its range chips in the toolbar, its tables in the one table component.
Ordering, used by Needs you and the Inbox:
- Broken and Needs a look items keep worker order (as today's Attention list), then device, then the key.
- Waiting items go longest wait first.
- Heads-up items go least time left first.
/inbox lists every Inbox item, in three groups: Broken, Needs a look, Heads-up. Chips above the list filter by group. A row opens the drawer at /inbox/<key>. The drawer has a box saying what happened, then the details of the worker, device, request or lease it is about. The sidebar's Inbox count is the number of problem items (Broken plus Needs a look). It is hidden at 0.
New Inbox items, beside today's six attention kinds:
| Item | Key | Group | Title, word for word |
|---|---|---|---|
an enrolled phone in state absent |
<workerId>/<deviceId>/absent |
Needs a look | <model> is absent (<reason>), reason locked, untrusted or not-present |
a request waiting over 60 000 ms, from its createdAt to the daemon's now as the console reads it (corrected by the Date header, ADR 0013 §4) |
request/<requestId>/waiting |
Needs a look | <requester> has waited <duration>, requester as the Queue page names it |
a lease from GET /v1/leases whose deadline is under 5 min from the daemon's now |
lease/<leaseId>/ending |
Heads-up | <holder> · <model> ends in <m:ss>, holder as the Leases page names it; at or past the deadline, ends now |
<model> is the device's spec.model. An Inbox address ends in / when the key holds a ., as leasePath does (ui/src/model/leases.ts:115-119), so a gateway lease id survives a reload.
flowchart LR
A["/ Overview (new)"] -->|Needs you row| B["/inbox/<key> drawer (new)"]
A -->|All in Inbox| C["/inbox (new, was /attention)"]
C --> B
If this goes wrong, an operator sees "Nothing needs you" while a worker is lost, or misses a request that has waited minutes.
Technical spec
Facts
| # | Fact | Source |
|---|---|---|
| F1 | Attention items today: disconnected, incompatible, drained, over RAM budget (worker), quarantined, stalled (device); keys <workerId>/<condition> (<workerId>/ram for the budget) and <workerId>/<deviceId>/<condition>; disconnected, incompatible and quarantined are error, the rest warn |
ui/src/model/attention.ts:14-77 |
| F2 | All attention items come from /v1/workers |
ui/src/model/attention.ts:35-37 |
| F3 | A status device carries state, physical and absentReason (locked, untrusted, not-present); a worker view lists devices in that shape |
src/contract/schemas.ts:47,211-216,230, src/contract/worker-view.ts:69 |
| F4 | A waiting request has createdAt, stage, queuePosition, reason, workerId and per-worker reasons |
src/contract/schemas.ts:409-417 |
| F5 | The longest wait is computed as the daemon's now minus the oldest createdAt; times are counted against the daemon's clock, corrected by the Date header; the Leases filter uses the same now.server |
ui/src/model/overview.ts:141,158, ui/src/state/overview.ts:35, ui/src/state/leases.ts:66, ADR 0013 §4 |
| F6 | The expiring rule is deadline minus now under EXPIRING_UNDER_MS (15 min), module-private |
ui/src/model/leases.ts:130-135 |
| F6a | The default lease length is 15 minutes | src/core/config.ts:52 (DEFAULT_LEASE_TTL_MS = 15 * 60_000) |
| F6b | Leases come from GET /v1/leases, holder names from GET /v1/tokens (ids when refused) |
ADR 0013 §1, ui/src/state/leases.ts:52-56 |
| F6c | The daemon serves the console page only when the last path segment has no .; leasePath adds a trailing / |
src/http/server.ts:108-111, ui/src/model/leases.ts:115-119 |
| F6d | Device states include shutdown and deleted; deleted records stay in the file |
src/contract/schemas.ts:36-45, src/core/AGENTS.md |
| F7 | The Overview reads /v1/workers, /v1/lease-requests, recent events and useFigures(range) |
ui/src/state/overview.ts:20-39 |
| F8 | The figures come from GET /v1/stats?since=<1h|6h|24h|7d>, range in ?range= |
ui/src/state/figures.ts:23-27, ui/src/model/range.ts:27-28 |
| F8a | A single host answers both GET /v1/lease-requests and GET /v1/stats |
src/daemon/dispatcher.ts:314,793,812, e2e/console/usage.spec.ts:134-251 |
| F9 | The three chart series are leasesHeld, queueDepth, slotsUsed, drawn by MinuteChart with a MinuteTable |
ui/src/model/figures.ts:62-81, ui/src/screens/overview/index.tsx:56 |
| F10 | Usage shows slots only as a stat today | ui/src/model/usage.ts:90-91 |
| F11 | Capacity today is per platform, running of limit, over connected workers only | ui/src/model/overview.ts:82-105 |
| F12 | The shell shows the attention count on the /attention entry |
ui/src/app/shell.tsx:27-35, ui/src/state/shell.ts (useAttentionCount) |
| F13 | Ids may hold a slash; itemPath encodes the whole id as one segment |
ui/src/model/paths.ts:1-18 |
| F14 | e2e: attention.spec.ts and overview.spec.ts assert today's headings, lists and texts |
e2e/console/attention.spec.ts, e2e/console/overview.spec.ts |
| F15 | e2e can drain a worker, stop one, hold a lease with lease --detach, start a waiting request with cliBackground, and stub a route's answer through page.route |
e2e/console/workers.spec.ts:285,716, e2e/console/waiting.spec.ts:81, e2e/console/long-lists.spec.ts:119-127 |
| F16 | Worker health and load findings | ui/src/model/fleet.ts:17-50, ui/src/model/load-thresholds.ts:7 |
Modules touched
Searches: attentionItems, attentionTone, AttentionScreen, useAttentionCount, "/attention", attention (case-insensitive, ui/src and e2e/console), EXPIRING_UNDER_MS, platformUse, FigureChartPanel, slotsUsed.
ui/src/model/attention.tsbecomesmodel/inbox.ts: the three new kinds, groups, order, keys, problem count.WAITING_TOO_LONG_MS = 60_000is new.EXPIRING_UNDER_MSis exported frommodel/leases.ts, its one home, and becomes 5 minutes.ui/src/model/leases.ts: the filter's label becomes "Ending < 5 min";e2e/console/leases.spec.ts:315checks it by that name.ui/src/model/overview.ts: the five numbers, capacity by part, the could-not-check line.ui/src/model/event-list.ts: its "Open attention item" link becomes "Open Inbox item" at/inbox/<key>.ui/src/state/overview.ts(adds/v1/leasesand/v1/tokens),state/attention.ts(becomesstate/inbox.ts),state/shell.ts: Inbox count.ui/src/screens/overview/,screens/attention/(becomesscreens/inbox/),screens/usage/(the shared frame, the Device slots in use chart).ui/src/app/routes.ts,app/routes.test.ts,app/shell.tsx,ds/icon.tsx:/inbox;/attentionand its icon go.ui/src/model/paths.ts,model/paths.test.ts:Sectiongains/inboxand drops/attention; the trailing/for keys with a..e2e/console/attention.spec.ts(becomesinbox.spec.ts),overview.spec.ts,usage.spec.ts,views.spec.ts,shell.spec.ts,long-lists.spec.ts,fixtures.ts.docs/CONSOLE.md(Overview, Attention → Inbox, Usage),ui/AGENTS.md.
flowchart LR
s1["screens/overview (changed)"] --> st1["state/overview (changed)"]
s2["screens/inbox (new)"] --> st2["state/inbox (new)"]
st1 --> m1["model/overview (changed)"]
st1 --> m2["model/inbox (new)"]
st2 --> m2
m2 --> m3["model/leases (export)"]
shell["app/shell (changed)"] --> st2
Contract and event changes
None. The pages read /v1/workers, /v1/lease-requests, /v1/leases, /v1/tokens, /v1/stats and the events, all routes the console reads today.
Other code on the same state
Searches: EXPIRING_UNDER_MS, isExpiring, createdAt, stalled, absent.
- The Leases page's filter (#765) and the Inbox heads-up use the same exported
EXPIRING_UNDER_MSand the samenow.server, so they cannot disagree. - The Queue page (#767) shows the same requests. The Inbox only adds an item; it changes nothing on the request.
- #769 adds the one fix button (Undrain on a drained worker), reading
model/inbox.ts's items.
Failure modes
| Call | Outcome | What happens | Limit, counted from |
|---|---|---|---|
GET /v1/stats with history unavailable |
503 | the charts and Wait p95 show the daemon's message, as today | — |
GET /v1/workers fails |
error | Overview shows "Could not check: workers" and no capacity; Inbox shows the error as today | the client's timeout |
GET /v1/lease-requests fails (any error, timeout) |
error | "Could not check: waiting requests"; the Inbox shows the rest with a banner saying the same | the client's timeout |
GET /v1/leases fails |
error | "Could not check: leases"; Ending soon shows — |
the client's timeout |
GET /v1/tokens refused |
403 | holders show their ids, as Leases does | — |
/inbox/<key> for an item that cleared |
not found | the drawer says "This is no longer in the Inbox." | the next refetch |
Rules in play
- DESIGN.md "A status always has a word": every capacity part prints its count and word; the bar is
role="img"with the same words as its name. - DESIGN.md "A count ... is a number, not a status": the Inbox count has no status colour.
- ADR 0013 §1: Overview and Inbox read only routes the console reads today.
- Architecture rule 10: one home for the ending-soon rule (
EXPIRING_UNDER_MS). - ADR 0013 §4: every wait and time left counts against the daemon's clock.
Tests
Seam: the browser lane (e2e/console/attention.spec.ts becomes inbox.spec.ts; overview.spec.ts), with a real daemon, and with page.route stubs for times a real daemon cannot reach quickly, as long-lists.spec.ts stubs. The pure rules run in Node in model/inbox.test.ts, modelled on ui/src/model/attention.test.ts.
- each of today's six attention kinds is an Inbox item with today's key and tone (move
attention.test.tscases) - an absent physical device is a Needs a look item titled
<model> is absent (<reason>)for each oflocked,untrusted,not-present; a device in another state is not - a request is an item at 60 001 ms waited and not at 59 999 ms, both by the daemon's now (model test)
- a lease is a heads-up at 4:59 left and not at 5:01, and one past its deadline says
ends now; the Leases filter agrees on the same leases (model test) - items keep the order given: worker order for problems, longest wait first, least time left first
- items group as Broken, Needs a look, Heads-up, in that order; the problem count excludes heads-ups
- Overview with an empty Inbox shows "Nothing needs you" and no Needs you panel; with a disconnected worker it shows the panel with that item first, and the link "All in Inbox ()"
- with five problem items the panel shows four, and a row opens
/inbox/<key> - with
/v1/lease-requestsstubbed to fail, Overview says "Could not check: waiting requests" and not "Nothing needs you" - Overview shows the five numbers with the daemon's values: one lease held of four devices with the ready count, one request waiting with its longest wait, two of two workers, Wait p95, and Ending soon counting a lease stubbed to 4 minutes left and not one at 10
- Overview's workers table lists all workers with no pager, and "Open Fleet" goes to
/fleet - Overview's and Usage's range chips sit in the shared toolbar
- capacity counts every read device per platform: a drained worker's ready device counts as drained, a disconnected worker's devices as offline, a
shutdowndevice as shut down, adeletedone not at all (model test) - the Leases held and Requests in the queue charts follow
?range=for each of 1h, 6h, 24h and 7d; Usage shows the Device slots in use chart in the shared frame (extendoverview.spec.ts,usage.spec.ts) /inboxlists a drained worker under Needs a look and a disconnected one under Broken; the chips show one group at a time- a waiting request stubbed with a
createdAt61 s before the daemon's now shows under Needs a look, and one at 30 s does not - a lease stubbed with 4 minutes left shows under Heads-up, and one with 10 minutes does not
- an Inbox item whose key holds a
.reloads at its address - an Inbox row opens
/inbox/<key>with the what-happened box and the item's details; a cleared item says "This is no longer in the Inbox." - the sidebar's Inbox count equals the problem items and is hidden at 0
- on a single host, Overview shows all five numbers and both charts (extend
overview.spec.ts's worker-mode case) - axe passes on Overview and Inbox, empty and busy, in light and dark (extend
shell.spec.ts's axe pass); no<style>element or CSP violation (extendviews.spec.ts)
Done when
pnpm test:console --project=chromiumpasses, and CI's Console check passes in every browser.
Out of scope
- The fix button and every action (#769).
Depends on
- #765
- #766
- #767
Written by an agent.
- 主要语言
- TypeScript
- 星标
- 20
- 派生
- 2
- 平均合并
- 8 小时 13 分钟
- 30 天内合并 PR
- 297
环境准备
这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
callstackincubator/simlock 的其他 Issue
-
难度 2/5 1-3 小时 新手友好度 70/100
callstackincubator/simlock#639 · 1 条评论 ·
维护者通常 1 天内回复
-
feature:spec
难度 5/5 一周以上 新手友好度 25/100
callstackincubator/simlock#771 ·
维护者通常 1 天内回复
-
task:ready
难度 5/5 一周以上 新手友好度 25/100
callstackincubator/simlock#770 ·
维护者通常 1 天内回复
-
task:ready
难度 5/5 一周以上 新手友好度 25/100
callstackincubator/simlock#769 ·
维护者通常 1 天内回复
-
Console: Queue and Activity in the shared frame, Activity scrolls back through history可能已有人在做 关联的 PR 仍在进行中或已合并。 未关闭task:ready
难度 4/5 3-5 天 新手友好度 48/100
callstackincubator/simlock#767 ·
维护者通常 1 天内回复
查看 callstackincubator/simlock 的全部 Issue
相似的 Issue
-
area: repo priority: P2 type: bug
难度 2/5 1-3 小时 新手友好度 76/100
appandflow/stim#4107 · 1 条评论 ·
维护者通常 1 天内回复
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
难度 1/5 1-3 小时 新手友好度 60/100
lingdojo/kana-dojo#32859 · 1 条评论 · 5 个 reaction ·
维护者通常 1 天内回复
-
code-quality refactoring
难度 2/5 1-3 小时 新手友好度 78/100
github/gh-aw-firewall#10364 ·
维护者通常 1 天内回复
-
Merge the duplicate kaffir_corn record into sorghum可能已有人在做 @Crypto-Shroom 今天认领。 未关闭
难度 2/5 1-3 小时 新手友好度 65/100
Crypto-Shroom/Bird-Feed-Calculator#322 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 75/100
drizzle-team/drizzle-orm#6552 ·
维护者通常 2 天内回复