Console: Overview home and Inbox
Maintainer thường phản hồi trong vòng 1 ngày
@V3RON đang làm issue này rồi.
Từ ngày 20/10/2026.
Đánh giá
- Độ khó
- 5/5
- Thời gian dự kiến
- Hơn một tuần
- Mức phù hợp với người mới
- 38/100
- Loại issue
- Tính năng
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- react, typescript
- Lĩnh vực
- developer-experience, frontend
Hướng nghiên cứu
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.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
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.
- Ngôn ngữ chính
- TypeScript
- Star
- 20
- Fork
- 2
- Merge trung bình
- 8 giờ
- Pull request đã merge (30 ngày)
- 316
Chuẩn bị môi trường
Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của callstackincubator/simlock
-
bug:new
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
callstackincubator/simlock#817 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug:triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
callstackincubator/simlock#778 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
callstackincubator/simlock#639 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
task:draft
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 35/100
callstackincubator/simlock#839 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
A gateway updates a chosen worker, incompatible ones included, and routes around it meanwhileĐang mởtask:ready
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 35/100
callstackincubator/simlock#838 ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của callstackincubator/simlock
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
phivk/rubiks-lab#33 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
BUG:Edit Album strips spaces from the password so albums with a leading/trailing space in the password can't be editedCó thể đã có người làm @ManyaJain111 đã nhận hôm nay. Đang mởbug enhancement possible-duplicate
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 77/100
AOSSIE-Org/PictoPy#1637 · 4 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
chaitin/MonkeyCode#1437 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
rtdb-info-connected-order test: unhandled 'connection is closed' rejection fails the CLI suiteĐang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 1 ngày
-
area:cards enhancement migration ready-for-agent
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
fil-donadoni/tolaria#6309 ·
Maintainer thường phản hồi trong vòng 1 ngày