Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Console: Overview home and Inbox

クローズ
#768 コメント 1 件 リアクション 0 件 担当者 1 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

@V3RON がすでに取り組んでいます。

2026年10月20日 から。

  • #793 @V3RON による — マージ済み

評価

難易度
5/5
見積もり時間
1週間以上
初心者へのやさしさ
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 の本文から書いたものです。

説明

task:ready

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 deleted ones. The parts:

    • leased;
    • ready;
    • booting (provisioning or reclaiming);
    • 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/&lt;key&gt; 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.ts becomes model/inbox.ts: the three new kinds, groups, order, keys, problem count. WAITING_TOO_LONG_MS = 60_000 is new. EXPIRING_UNDER_MS is exported from model/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:315 checks 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/leases and /v1/tokens), state/attention.ts (becomes state/inbox.ts), state/shell.ts: Inbox count.
  • ui/src/screens/overview/, screens/attention/ (becomes screens/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; /attention and its icon go.
  • ui/src/model/paths.ts, model/paths.test.ts: Section gains /inbox and drops /attention; the trailing / for keys with a ..
  • e2e/console/attention.spec.ts (becomes inbox.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_MS and the same now.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.ts cases)
  • an absent physical device is a Needs a look item titled <model> is absent (<reason>) for each of locked, 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-requests stubbed 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 shutdown device as shut down, a deleted one 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 (extend overview.spec.ts, usage.spec.ts)
  • /inbox lists 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 createdAt 61 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 (extend views.spec.ts)

Done when

  • pnpm test:console --project=chromium passes, 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時間 10分
マージ済み PR(30日)
354

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

callstackincubator/simlock のほかの issue

callstackincubator/simlock の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。