Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Console: Queue and Activity in the shared frame, Activity scrolls back through history

Đang mở
#767 0 bình luận 0 reaction 1 người được giao Xem trên GitHub

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.

  • #789 của @V3RON — đang mở

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
48/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

Hướng nghiên cứu

Start with ui/src/data/event-feed.ts, ui/src/model/events.ts, ui/src/state/events.ts, and ui/src/ds/feed.tsx to trace event loading, merging, and virtual-list behavior. Then read the Activity and Queue screen entry points and the named model and feed tests. Done means older history loads and ends as specified, the list stays stable while reading, Queue and Activity use the shared frame and drawer, and the browser cases cover the listed states.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

task:ready

Part of #756.

Scope

Queue and Activity move to the shared frame, with the drawer. Activity scrolls back through the daemon's whole event history as far as it is kept, instead of stopping at one hour. After this PR an operator reads why each request waits in the same table and drawer as everything else. They can scroll Activity back days to see what happened overnight.

In short

Queue (/queue) is a table: place, requester and the device asked for, stage, why it waits, and how long it has waited. Above it, the Wait p95 number is shown as today. A row opens the drawer at /queue/<requestId>. The drawer shows today's inspector facts: Waiting, Place, Stage, Device, Queue, Why, and the one row per worker on a gateway.

Activity (/activity) is the event list, newest first, in the shared toolbar: the type chips (All, Leases, Devices, Workers, Components, Other) on the left and a search box on the right. A row opens the drawer at /activity/<eventId> with the payload and the link to what it is about. New events arrive on top as today. While the reader has scrolled down, nothing moves, and the button "<n> new events" appears at the top.

  • Infinite scroll: the page first loads the last hour, as today (GET /v1/events?since=1h). When the reader comes within 20 rows of the end, it asks for the 100 events before the oldest one it holds (GET /v1/events?before=<oldest id>&limit=100, from #764). With no event held, it asks for the newest 100 (?limit=100). It adds them at the bottom and repeats until the history ends, or until the list holds 10,000 events, today's cap.
  • It loads by itself only while the chips are on All and the search is empty. With a filter on, the last row is the button Load older events: each press loads one page of 100, which may add no visible row.
  • Search matches, ignoring case, any part of a row's event name or its summary line (who, which device, which worker), over the events held. The text is in the address as ?q=.
  • The last row says why the list stops. Times are the local date and time, YYYY-MM-DD HH:MM.
    • At the cap: "Showing the newest 10,000 events."
    • When the history ends (a page shorter than 100 in the raw reply, or one that adds no event the list does not already hold): "Start of the history ()".
    • On a 422: "Older events are no longer kept."
    • On a 503, any other error, or no answer within the client's timeout: "Older events are not available right now." with Try again. A 401 signs out, as for any read.
  • When the first load returns no events, the page asks for the newest 100 (?limit=100) at once, so a quiet last hour still shows older history. Only when that also returns none does it say "No events yet."
  • When a chip or search matches none of the held events, the page says "No events among those loaded." (for search, "No events match among those loaded."), with Load older events under it while the history has not ended.
  • The last row sits below the scrolling list, outside it, so it never counts as an event row.
  • An address /activity/<id> for an event not held opens the drawer with "This event is not among those loaded. Older events load as you scroll the list, or with Load older events."
  • The Events per minute chart and its table stay above the list, as today.
flowchart LR
  A["/activity (changed)"] -->|scroll near the end| B["GET /v1/events?before=…&limit=100 (new)"]
  B -->|100 rows| A
  B -->|fewer| C[Start of the history]
  A -->|row| D["/activity/&lt;id&gt; drawer"]

If this goes wrong, Activity shows an event twice or skips some while scrolling back, or the list jumps while someone reads it.

Technical spec

Facts
# Fact Source
F1 The console loads GET /v1/events?since=1h and, after a stream reopens, the missed window ui/src/data/event-feed.ts:78, ui/src/model/events.ts:10-13
F2 mergeEvents dedups by id, sorts newest first by timestamp then seq, and keeps at most MAX_EVENTS = 10_000 ui/src/model/events.ts:10-13,46-64
F3 One EventFeed per screen; the stream feeds streamEvent ui/src/state/events.ts:30-37
F4 The feed is a virtual list (useVirtualizer) anchored to the start at the top and to the end when scrolled; it has no near-end callback ui/src/ds/feed.tsx:32-40
F5 The Events page shows "No events in the last hour." and gives Feed count, newText ("N new events") and startAt ui/src/screens/events/index.tsx:93-106
F6 Events page today: chart, filter all/leases/devices/workers/components/other in the address, payload inspector with a link docs/CONSOLE.md:451-486
F7 Waiting page today: Wait p95 tile, rows place, requester, wait, device, stage; inspector facts and per-worker rows docs/CONSOLE.md:388-415, ui/src/state/waiting.ts:22
F8 GET /v1/events?before=&limit= returns up to limit events older than the named one, oldest first; 422 HISTORY_NOT_KEPT, 503 HISTORY_UNAVAILABLE #764 In short
F9 long-lists.spec.ts measures the events feed's frame time; #730 tracks its WebKit flake e2e/console/long-lists.spec.ts, #730
F10 Drawer, Toolbar, the search field and the addresses /queue[/<id>] and /activity[/<id>] come from #765 #756 Shared values
F11 The long-lists stubs answer every /v1/events request the same, whatever the query; the frame-time case seeds 5,000 events and waits for them e2e/console/long-lists.spec.ts:27,119-127,703-751
F12 With no rows after filtering the screen draws Empty and no Feed ui/src/screens/events/index.tsx:95-99
F13 readEvent drops malformed events from a reply ui/src/model/events.ts:34-38
Modules touched

Searches: EventFeed, mergeEvents, MAX_EVENTS, Feed, useVirtualizer, WaitingScreen, EventsScreen, "Events per minute".

  • ui/src/data/event-feed.ts: loadOlder() calls before (or limit alone when nothing is held) and reports the end, 422 or an error. The first load and the gap load after a reconnect stay since.
  • ui/src/model/events.ts: mergeEvents keeps older pages, under today's 10,000 cap; the end rule (a raw page under 100, or a page adding nothing new); the search match.
  • ui/src/state/events.ts: exposes loadOlder and the list's end state.
  • ui/src/ds/feed.tsx: an onNearEnd callback when the last rendered row is within 20 of the end, and an end row.
  • ui/src/screens/events/ (renamed activity/), ui/src/screens/waiting/ (renamed queue/): table or feed, drawer, toolbar, the end rows, Load older events.
  • e2e/console/events.spec.ts (becomes activity.spec.ts), waiting.spec.ts (becomes queue.spec.ts), views.spec.ts, and long-lists.spec.ts, whose /v1/events stubs answer before= with no events, so the stubbed list ends where it does today.
  • docs/CONSOLE.md (Waiting → Queue, Events → Activity; "Event not in the last hour." goes), ui/AGENTS.md.
flowchart LR
  s["screens/activity (changed)"] --> st["state/events (changed)"]
  s --> feed["ds/feed (changed)"]
  st --> ef["data/event-feed (changed)"]
  st --> m["model/events (changed)"]
  ef --> api["GET /v1/events?before (#764)"]
Contract and event changes

None in this task (#764 adds the query).

Other code on the same state

The state is the console's list of held events. Searches: mergeEvents(, streamEvent, EventFeed. The writers are the initial load, the gap load after a reconnect, the stream, and now loadOlder.

  • Stream and loadOlder at once: both go through mergeEvents, which dedups by id and sorts, so an event appears once in its place.
  • The gap load after a reconnect adds newer events only, and loadOlder adds older ones. Neither moves what the reader is looking at when scrolled down (F4's end anchor).
  • Overview (#768) reads recent events through its own feed and is unaffected.
Failure modes
Call Outcome What happens Limit, counted from
loadOlder 100 rows appended at the bottom; may load again when near the end the client's request timeout
loadOlder fewer than 100 in the raw reply (before malformed events are dropped, F13) appended; end row "Start of the history ()"; no more loads —
loadOlder 422 end row "Older events are no longer kept."; no more loads —
loadOlder 503, 400, 403, 500, network error end row "Older events are not available right now." with Try again —
loadOlder no answer the same end row the client's 10 s request timeout, from send
loadOlder a full page that adds no new event treated as the end: "Start of the history (…)", no more loads —
loadOlder 401 signed out, as for any read —
loadOlder the list holds 10,000 no request; end row "Showing the newest 10,000 events." —
two near-end signals before the first answer — one request at a time; the second is dropped —
Rules in play
  • ADR 0013 §3: the stream and the refetch work as today; loadOlder is a read of a route.
  • ADR 0037 §2: the drawer at /activity/<id> and /queue/<id>.
  • DESIGN.md "Charts." bullet (docs/internal/DESIGN.md:208-215): the chart keeps its table twin, as today.
  • ADR 0037 is Proposed until this feature's approval; the task follows it as accepted.
Tests

Seam: the browser lane (e2e/console/events.spec.ts becomes activity.spec.ts, waiting.spec.ts becomes queue.spec.ts), with a real daemon, and with /v1/events stubbed through page.route for the history's end states, as long-lists.spec.ts stubs it. The merge, end and search rules in Node in ui/src/model/events.test.ts and ui/src/data/event-feed.test.ts.

  • Queue lists each waiting request with place, requester, device, stage, why and wait; a row opens /queue/<id> with today's inspector facts and, on a gateway, one row per worker (move waiting.spec.ts cases)
  • a request that is granted while its drawer is open shows "Request not waiting." (as today)
  • Activity lists events newest first; the chips and the search filter the list and are kept in the address (?q=); search matches part of the event name or summary, ignoring case, and not other payload values (model test)
  • a row opens /activity/<id> with every payload key and the link to its lease, worker or request
  • scrolling within 20 rows of the end loads the 100 events before the oldest held and appends them without moving the rows in view (stub: a last hour of 30 events, then pages of 100)
  • with a chip or search on, nothing loads by itself, and Load older events loads one page per press
  • an address /activity/<id> for an event not held shows "This event is not among those loaded. Older events load as you scroll the list, or with Load older events."
  • each end row shows its wording in the browser, with stubbed answers: a page of 40 gives "Start of the history ()" and no further request; 10,000 held gives "Showing the newest 10,000 events."; a 422 gives "Older events are no longer kept."; a 503 and a 500 give "Older events are not available right now.", and Try again asks again; a full page of events already held ends the list
  • a daemon with no events in the last hour but older history shows them at once (?limit=100 sent with no scrolling); an empty history shows "No events yet."
  • a chip that matches no held event shows "No events among those loaded." and Load older events, which loads one page
  • an event that arrives by the stream while older pages load appears once, at the top
  • while scrolled down, new events show " new events" and the rows in view do not move (extend the existing case)
  • mergeEvents keeps older pages in order and dedups by id across a page and the stream (extend events.test.ts)
  • the long-lists frame-time check still passes with its 5,000 seeded events, its stubs answering before= with none (long-lists.spec.ts)
  • axe passes on Queue and Activity with a drawer open, in light and dark; 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

  • Cancel and every other action (#769).

Depends on

The console tasks run one after another: #766 and this task both edit the route table, views.spec.ts's page list and the manual's Pages table.

  • #765
  • #766
  • #764

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

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. 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.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của callstackincubator/simlock

Tất cả issue của callstackincubator/simlock

Issue tương tự

Thêm issue về TypeScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.