@sentry/junior-dashboard 0.268.0 → 0.269.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +7 -105
  2. package/dist/app.js +12 -9
  3. package/dist/client.js +72 -75
  4. package/dist/index.js +12 -9
  5. package/dist/tailwind.css +1 -1
  6. package/package.json +4 -4
  7. package/src/api/schema.ts +2 -1
  8. package/src/app.ts +11 -7
  9. package/src/client/App.tsx +1 -5
  10. package/src/client/api.ts +4 -19
  11. package/src/client/components/AGENTS.md +65 -0
  12. package/src/client/components/ActorAvatar.tsx +1 -1
  13. package/src/client/components/ParticipantAvatarStack.tsx +1 -0
  14. package/src/client/components/ProfileMenu.tsx +88 -29
  15. package/src/client/components/UserInputForm.tsx +1 -1
  16. package/src/client/components/charts/AGENTS.md +15 -0
  17. package/src/client/conversations/AGENTS.md +42 -0
  18. package/src/client/conversations/ConversationPage.tsx +0 -27
  19. package/src/client/format.ts +7 -23
  20. package/src/client/pages/automations/AGENTS.md +34 -0
  21. package/src/client/pages/automations/AutomationActions.tsx +18 -20
  22. package/src/client/pages/automations/AutomationEditor.tsx +3 -4
  23. package/src/client/pages/automations/AutomationOverview.tsx +3 -3
  24. package/src/client/pages/automations/AutomationStatus.tsx +2 -2
  25. package/src/client/pages/system/AGENTS.md +12 -0
  26. package/src/client/review-desk/ConversationReviewBar.tsx +14 -8
  27. package/src/client/review-desk/ReviewDeskPage.tsx +99 -79
  28. package/src/client/review-desk/ReviewItemDetail.tsx +15 -7
  29. package/src/client/review-desk/queries.ts +25 -16
  30. package/src/mock-reporting/routes.ts +1 -1
  31. package/src/tailwind.css +1 -1
  32. package/src/client/components/README.md +0 -219
  33. package/src/client/components/charts/README.md +0 -38
  34. package/src/client/conversations/README.md +0 -159
  35. package/src/client/conversations/UserInputRequestCard.tsx +0 -39
  36. package/src/client/conversations/userInputRequest.ts +0 -56
  37. package/src/client/pages/automations/README.md +0 -97
  38. package/src/client/pages/system/README.md +0 -23
@@ -1,219 +0,0 @@
1
- # Dashboard UI kit
2
-
3
- Shared dashboard components live here. Feature pages compose these surfaces
4
- instead of copying Tailwind blocks. See `policies/frontend-components.md` for
5
- the policy. `pnpm dashboard-style:check` enforces the token rules below.
6
-
7
- ## shadcn/ui
8
-
9
- `packages/junior-dashboard/components.json` configures shadcn/ui for this package.
10
- It uses Base UI (`base-nova`), Tailwind 4, and Lucide. Add components from the
11
- repository root:
12
-
13
- ```sh
14
- pnpm --filter @sentry/junior-dashboard exec shadcn add <component>
15
- ```
16
-
17
- The CLI writes components to `src/client/components/ui/`. Its `@dashboard/*`
18
- alias points to `src/client/*`. The existing `@/*` alias still points to core.
19
- The `ui/` files join classes with the merging `cn` from
20
- `src/client/lib/utils.ts`, so a caller's `className` wins over a base class.
21
-
22
- The shadcn color tokens in `src/tailwind.css` use the dashboard tokens in both
23
- themes. The `dark:` variant follows `data-theme`. Keep the existing Tailwind
24
- radius scale. Do not apply the CLI's global border or body resets. Check each
25
- added component against the rules below before use.
26
-
27
- Each `ui/` file is shadcn source that uses dashboard tokens. Remove exports
28
- that no app code uses. Use `ui/` components directly. Do not add an app
29
- component that only renames a `ui/` component or its props. Change the `ui/`
30
- file when every caller needs the same style or variant. App components compose
31
- `ui/` source only when they add structure or behavior:
32
-
33
- | App component | shadcn source |
34
- | ------------------------------ | ----------------- |
35
- | `Drawer` | `ui/drawer` |
36
- | `BottomSheet` | `ui/sheet` |
37
- | `layout/DashboardHeader` (nav) | `ui/sheet` |
38
- | `ProfileMenu` (desktop) | `ui/popover` |
39
- | `ActorAvatar` | `ui/avatar` |
40
- | `ParticipantAvatarStack` | `ui/avatar` |
41
- | `SearchInput` | `ui/input-group` |
42
- | `PagePagination` | `ui/pagination` |
43
- | `EmptyTelemetry` | `ui/empty` |
44
- | `TimeRangeSelector` | `ui/toggle-group` |
45
- | `ThemeSwitcher` | `ui/toggle-group` |
46
- | `TranscriptViewToggle` | `ui/toggle-group` |
47
- | `FilterTabList` | `ui/tabs` |
48
- | `charts/ActivityChartTooltip` | `ui/tooltip` |
49
- | `conversations/ToolFrame` | `ui/trace` |
50
- | `TranscriptReasoningView` | `ui/trace` |
51
- | `ImageAttachment` (preview) | `ui/dialog` |
52
- | `Notice`, `InlineError` | `ui/alert` |
53
- | App banners | `ui/alert` |
54
- | Recharts activity charts | `ui/chart` |
55
-
56
- Rules for adopted components:
57
-
58
- - Use `ui/trace` for transcript activity rows. It composes `ui/collapsible`.
59
- A closed tool row unmounts its panel, so it does not run Shiki. Reasoning
60
- sets `hiddenUntilFound`, so browser find reaches closed text. Transcript
61
- search holds rows open and turns off the row button. Put only inline
62
- elements, such as `span`, inside the row button.
63
- - Use `ui/alert-dialog` for every confirmation. Do not use `window.confirm`.
64
- Keep the confirmed item in state after close, so the closing dialog keeps its
65
- text.
66
- - Use `ui/dialog` for a short task form, such as the fork message. Do not put
67
- a form in a `Drawer` or a `DetailsPanel`. On small screens the dialog sits
68
- near the top, so the on-screen keyboard does not cover its fields.
69
- - Use `useSheet` for each app `ui/dialog`, as for sheets. It shares the
70
- document scroll lock. Only the front modal closes on Escape or a backdrop
71
- tap. Mount the dialog only while it is open.
72
- - `ui/alert` sets `role="alert"`. Pass `role="status"` for a message that is
73
- not an error.
74
- - `ui/toast` has no global notification manager. Features call
75
- `useToastManager` inside the mounted `Toaster` provider.
76
- - Put a checkbox or radio inside its `<label>`. Give each `RadioGroup` an
77
- `aria-label`.
78
- - Give an icon-only control its label with `TooltipContent size="compact"`.
79
- Do not use the native `title` attribute. Tooltips open on mouse hover and
80
- keyboard focus only, so a tap still runs the control.
81
- - When a `ui/button` tooltip trigger can be disabled, set
82
- `focusableWhenDisabled`. A native disabled button can drop hover and focus,
83
- so Firefox closes the tooltip and hides pending or result labels.
84
- `ui/button` styles `data-disabled`, so both disabled modes look the same.
85
- - Build a form field from `ui/field`. Give `FieldError` the id
86
- `<control id>-error` and `FieldDescription` the id `<control id>-help`. The
87
- control sets `aria-invalid` and `aria-describedby`.
88
- - Use `Button size="menu"` for a full-width icon and label row in a mobile
89
- overflow menu. A pressed row adds `bg-dashboard-fill-strong`.
90
- - For a link that looks like a button, put `buttonVariants()` on the router
91
- `Link`. A form page has one `Button variant="primary"` for its main save
92
- action.
93
- - Use `Button variant="quiet"` for a secondary action beside the primary one,
94
- such as Dismiss. It has no border, so the primary action stays dominant.
95
- - In a form, show each choice as a whole bordered row around `RadioGroupItem`
96
- or `Checkbox`. The row shows hover and selected state. See `UserInputForm`.
97
-
98
- ## Foundations
99
-
100
- Tokens live in the `@theme` block of `src/tailwind.css`. Keep every color in a
101
- token so each theme can redefine it.
102
-
103
- - **Themes.** Dark is the default. The light theme redefines every token under
104
- `:root[data-theme="light"]`. It also mirrors the light status and chart
105
- shades (50-400) to their dark pair, so `text-rose-300` stays readable on the
106
- light canvas. The head script in `src/theme.ts` sets `data-theme` before first
107
- paint from the saved choice or the system color scheme. `ThemeSwitcher` saves
108
- the choice for this browser. Use the `light:` variant only for one-off values
109
- that no token covers, such as provider brand colors.
110
- - **Charts.** Use `var(--color-*)` for series colors, not hex values, so they
111
- follow the theme. Name series colors in the `ChartContainer` config and fill
112
- each series with `var(--color-<key>)`.
113
- - **Surfaces.** Use the surface ladder, darkest to lightest: `bg`,
114
- `bg-elevated` (drawers), `surface-panel` (sidebar, cards, bubbles),
115
- `surface-raised` (buttons, tooltips), `control`, `surface-hover`,
116
- `surface-active` (selected rows). Use `fill-*` for translucent fills and
117
- `overlay-*` for scrims. Do not use `white/*` or `black/*` fills, borders, or
118
- rings, or hex surface colors. Shadows may use black.
119
- - **Borders.** Use `border-subtle` for hairlines inside a surface,
120
- `border` for card edges, `border-strong` for shell edges, and
121
- `border-emphasis` or `border-interactive` for controls and hover.
122
- - **Text.** Brightest to dimmest: `text-solid`, `text`, `text-subtle`,
123
- `text-muted`, `text-faint`.
124
- - **Accent.** Lavender is the one brand accent. Use `accent` for icons,
125
- active markers, and tinted fills, such as `bg-dashboard-accent/10`. Use
126
- `accent-text` for links and accent text. Keep Tailwind palette colors for
127
- status (info, success, warning, error) and for categorical chart, event, and
128
- subagent colors.
129
- - **Focus.** Use `outline-dashboard-focus` for keyboard focus. Do not use other
130
- colors for focus rings.
131
- - **Type faces.** `font-sans` is the UI face for prose, controls, navigation,
132
- labels, and names. `font-display` is for headings, record titles, and large
133
- metric values. `font-mono` is for machine values: code, ids, paths, file
134
- names, tool names, and raw payloads. Show counts, times, and prices in
135
- `font-sans tabular-nums`.
136
- - **Type scale.** Use the named steps `text-2xs` through `text-4xl`. Keep
137
- `text-2xs` for compact badges and chart annotations.
138
- - **Labels.** Section, card, field, and column labels use
139
- `font-sans text-xs font-medium text-dashboard-text-muted` in sentence case.
140
- Do not use uppercase or letter spacing for labels.
141
- - **Radius.** Controls and chips use `rounded-md`. Cards, list rows, and panels
142
- use `rounded-lg`. The composer, menus, and transcript object cards use
143
- `rounded-xl`. Avatars and count badges use `rounded-full`.
144
-
145
- Shared class strings live in `src/client/styles.ts`.
146
-
147
- ## App components
148
-
149
- - **Status.** Use `StatusDot` for dense table or list markers. Use `StatusChip`
150
- when the label must stay visible. `StatusChip` is not a control.
151
- - **Messages.** Use `Notice` for compact transient messages and `FormNotice`
152
- for wrapping form recovery text.
153
- - **Disclosure.** Use `ui/collapsible` for one show-or-hide section. Put a
154
- `ChevronRight` with `dashboardDisclosureChevronClass` in a `group` trigger.
155
- Set `hiddenUntilFound` on the content when browser find must reach closed
156
- text. Closed content then keeps its box, so put margins and padding on a
157
- child. Use `ui/accordion` for a set of sections with headings.
158
- - **Details.** `DetailsPanel` docks an aside at 1280px and above, and uses a
159
- `BottomSheet` below that width. It owns Escape and the scroll frame for
160
- docked panels. Docked actions sit beside the close control, so their
161
- position does not change with the title width.
162
- - **Drawer.** `Drawer` is a right-side `ui/drawer`. A `Drawer` opened from
163
- inside another `Drawer` stacks in front of it. The parent scales back,
164
- shows a thin edge behind the child, and hides its content. Set `flush` when
165
- the content owns its insets and sticky headers, such as the event log.
166
- - **Identity.** `ObjectIcon` owns the native Ticket, Code change, Automation,
167
- Deployment, and Item icons. Do not replace it with a provider logo or a
168
- status-only icon.
169
- - **Loading.** Use `ui/skeleton` for placeholder leaves and `PageContentSkeleton`
170
- variants for page bodies. Use `PageRouteLoading` when a page keeps its real
171
- header above a body skeleton. Use a feature-owned loading component for
172
- distinct geometry, such as conversations. Use `ui/spinner` for an inline
173
- pending icon.
174
-
175
- ## Navigation
176
-
177
- The dashboard has three navigation levels. Each has its own look, so the
178
- levels stay distinct.
179
-
180
- - **App navigation** in `layout/DashboardHeader` uses pills.
181
- - **Page links** use `SegmentedNav`, through `layout/SecondaryNavigation`. They
182
- are underline tabs that sit on the header border.
183
- - **Panel switches** use `ui/tabs`. Give `TabsList` an `aria-label`. Set
184
- `activateOnFocus` so arrow keys select the tab.
185
-
186
- Keep collection filters in `FilterTabList`. It uses `TabsList variant="line"`
187
- and adds the count badges.
188
-
189
- ## Patterns
190
-
191
- - **Layout.** `layout/` holds the shell chrome, page headers, cards, and
192
- section titles. `DashboardChrome` owns the sticky header block and its one
193
- bottom border.
194
- - **Charts.** Put `role="img"` and the chart `aria-label` on the Recharts
195
- chart, so the tooltip live region stays outside the image. Day and hour
196
- charts compose the `charts/ActivityChart` axis, average line, and tooltip
197
- helpers. They do not format UTC bucket keys inline.
198
- - **Conversation mobile geometry** is a hard ownership edge:
199
- - `layout/VisualViewportShell` owns the fixed shell, visualViewport CSS
200
- variables, and body lock.
201
- - `conversations/ChatLayout` owns the scroll-above-dock frame for reply
202
- threads.
203
- - `conversations/ComposerDock` owns the reply bottom pad and dock chrome.
204
-
205
- Pages pass children only. Home and create are one landing surface, not a
206
- dock, and must not use `ComposerDock`. Do not add viewport height, offset, or
207
- bottom safe-area math in page modules.
208
-
209
- Feature surfaces stay under `conversations/` or `pages/` until two real callers
210
- share them. See [Transcript components](../conversations/README.md) for
211
- transcript ownership.
212
-
213
- ## Rules
214
-
215
- - Prefer a named component on the second real use.
216
- - Keep Tailwind classes on the owning component.
217
- - Check new or changed shared components on a real page with mock data and in
218
- the dashboard E2E screenshots.
219
- - One-off page glue may stay inline when extraction only adds indirection.
@@ -1,38 +0,0 @@
1
- # System cache reporting
2
-
3
- `InputCacheChart` owns the cache trend, summary, and largest writes.
4
- `SystemActivity` selects its time buckets with the page reporting control.
5
- `SystemMetricCharts` keeps spend and runtime beside the cache view.
6
-
7
- ## Input counters
8
-
9
- `ConversationMetricDay` comes from stored Run metrics, not Sentry spans.
10
- Its ordinary input, cached input, and cache-creation counters are disjoint.
11
- Add these three counters once to get total input. Do not include output.
12
- Sentry span input totals use a different rule and must not use this transform.
13
-
14
- `cache-input.ts` owns this calculation. Period shares use summed token counts,
15
- not the mean of bucket shares. A missing counter is not a reported zero.
16
- If an active bucket lacks a counter, omit its share and the whole-period share.
17
- Token mode can still show reported counts. Gray marks identify incomplete
18
- buckets. Empty buckets do not lower shares.
19
-
20
- Field presence is not call-level coverage. SQL sums can combine complete and
21
- incomplete Runs in one bucket. Do not describe these values as a cache hit rate
22
- or a cache failure rate.
23
-
24
- ## Investigation
25
-
26
- `CacheWrites` lists the three largest write counts in the page time window.
27
- The list and chart consume the same selected buckets. There is no local time
28
- selector or comparison window. The list is collapsed until needed.
29
-
30
- The chart fills the available width. It keeps a fixed, compact height rather
31
- than growing taller on wide screens.
32
-
33
- This report has no per-call model, release, environment, trace, or write-cost
34
- fields. Add a reporting contract before adding those filters or drilldowns.
35
- A large write alone cannot identify cache expiry, a cold start, or prefix loss.
36
-
37
- The System browser scenario covers display modes and verifies that the page
38
- time control also filters the list.
@@ -1,159 +0,0 @@
1
- # Transcript components
2
-
3
- Keep transcript layout in these feature components. Use the dashboard UI kit for
4
- shared controls and overlays.
5
-
6
- - `TranscriptRows` and `TranscriptRow` own the top-level gap, cell padding, and
7
- activity indent. Loading rows and the typing indicator use the same layout.
8
- The 4px gap and two 6px padding edges leave 16px between row content. Horizontal
9
- padding stays inside each mobile row's paint bounds so focus outlines are not
10
- clipped. Negative horizontal margins preserve the text edge.
11
- - `TranscriptMessageShell` owns the 32px avatar column and 12px message gutter.
12
- `TranscriptMessageHeading` aligns authors, timestamps, and the context action.
13
- The action stays visible on touch devices and while open. Mouse users see it
14
- on message hover; keyboard users see it on focus.
15
- - `TranscriptSummaryTrigger` owns disclosure padding, hover, and keyboard
16
- focus for a `ui/collapsible` trigger. Use `flush` when the text already sits
17
- on the transcript edge. It extends the padded control around that text. Do
18
- not repeat negative margins at call sites. The caller owns the `Collapsible`
19
- and its content. Transcript search holds event and context rows open, and
20
- shows activity group rows without the group.
21
- - Activity rows (tools, reasoning, and grouped rail events) share one
22
- layout: a 1rem icon column, an 8px gap, then the title and metadata.
23
- Tool and reasoning rows use `ui/trace`. Transcript search forces them open.
24
- Expanded content sits in `TraceCollapsibleContent` under the title.
25
- `TranscriptActivityNesting` tells a rail event that it is inside an activity
26
- group. Outside a group, the rail icon sits in the avatar column so the text
27
- lines up with message text.
28
- - `TranscriptSubagentView` renders a child agent as a card with its name,
29
- status, run time, and title. It matches the child agent rows in the details
30
- drawer and opens the child transcript.
31
- - `TranscriptAutomationTriggerView` renders the input of an Automation run as
32
- one card. The report names that message in `sourceTask.triggerMessageId`.
33
- The card shows the Automation name and a link to it. A second line shows the
34
- trigger, the run time, and whose credentials the run used. The credential
35
- part comes from the run's dispatch record, not the Automation's current
36
- setting. It is left out when that record is gone. The run input is not from
37
- a person, so it stays collapsed behind "Show prompt".
38
- - `TranscriptAttachments` owns wrapping for both message attachments and file
39
- deliveries. `ImageAttachment` owns image previews.
40
- - Display text keeps Slack tokens such as `<@U123>` and `<#C123|name>`. The
41
- API resolves the people in that text. It returns them as `mentions` next to
42
- the object that owns the text: an event, an activity preview, a Brief, or an
43
- Automation. Render this text with `TranscriptText` or `MentionText`. Both
44
- require `mentions`, so a caller cannot forget them. Do not resolve names in
45
- the dashboard, and do not rewrite tokens into links on the server.
46
- - `TranscriptTurnContextView` owns context content. A transcript with a
47
- `turnContextPanel` shows the context in the page panel. See "Page panel".
48
- Other transcripts, such as a subagent drawer, open a modal `Drawer`. Each
49
- `Transcript` sets the panel for its own rows, so a nested transcript does not
50
- use the panel of the page behind it. The panel keys context by message id,
51
- so every control for one message shows the same open state.
52
-
53
- Review these components together on the mock Conversations. Run
54
- `JUNIOR_DASHBOARD_MOCK_CONVERSATIONS=true pnpm dev` for messages, events,
55
- activity, context, typing, and attachments. Keep visual checks out of automated
56
- assertions; browser tests cover opening, closing, and keyboard interaction.
57
-
58
- ## Conversation details
59
-
60
- `ConversationPage` owns whether details are open. At 1440px and above, details
61
- open by default. An explicit choice lasts for the current Conversation. The page
62
- is keyed by the Conversation, so switching Conversations resets that choice.
63
- `ConversationHeader` toggles details and restores focus through explicit control
64
- refs after dismissal.
65
-
66
- ## Page panel
67
-
68
- The Conversation page has one panel on the right. It shows Conversation
69
- details, event details, or turn context. Only one shows at a time. Each uses
70
- `DetailsPanel`: a 400px aside at 1280px and above, and a `BottomSheet` below.
71
-
72
- - Event details and turn context show in place of Conversation details.
73
- - When you close them, Conversation details show again if they are open. The
74
- details stay open by choice or by the 1440px default.
75
- - A link that opens an event sets details to closed. When you close that
76
- event, no panel shows.
77
- - The details control closes event details and turn context, then shows or
78
- hides Conversation details.
79
- - Turn context belongs to the Conversation view. A view change closes it.
80
- Select the same context control again to close it.
81
- - Closing a panel returns focus to the row or control that opened it.
82
-
83
- `ConversationDetails` owns one set of tabs and content. It supplies its title and
84
- actions to `DetailsPanel`, which uses a 400px aside at 1280px and above. The chat
85
- and aside scroll separately.
86
- Smaller windows use `BottomSheet` with a visible title and close control. The sheet and
87
- side drawers use the shadcn Base UI `Sheet` and share the app's document
88
- scroll lock. A resize changes the frame and keeps the selected tab. Tabs stay
89
- fixed above the scrolling content in both layouts. The sheet title and close control sit above the tabs. Use the close
90
- control, tap the backdrop, or press Escape to dismiss it. Base UI owns the
91
- transition lifecycle.
92
- A pending exit cannot close a new panel or a different Conversation.
93
-
94
- ## Event log
95
-
96
- `ChatLayout` keeps the Conversation header outside the transcript scroll region.
97
- `ConversationEventLog` fills the pane without a card border or page inset. Its
98
- search toolbar and column labels stay together at the top while rows scroll.
99
- `Transcript` shares the search value with its owner, or keeps it locally when
100
- used alone. Event log search stays visible; the transcript search toggle is for
101
- the Conversation view.
102
-
103
- Rows keep time, event type, and summary in columns when the pane is at least
104
- 512px wide. Smaller panes put the summary below time and type. Model and usage
105
- metadata share one optional line. Missing model metadata is omitted from rows.
106
- Selected rows have a background and an accent edge. Up and Down select the
107
- previous or next visible row while a row has focus. Selection stops at the
108
- ends of the filtered list. The selected row stays clear of the fixed toolbar.
109
- `eventLogRows` and `filterEventLogRows` own the row text and search match.
110
- The page uses them too, so its step controls follow the same rows.
111
-
112
- The timezone toggle uses `useEventTime` to share a UTC/local preference through
113
- `@uidotdev/usehooks` and browser local storage. It applies to event row clocks
114
- and detail timestamps. Local mode follows the browser timezone. The button uses
115
- a generic zone name because a log can span standard and daylight-saving time.
116
- Detail timestamps use a readable date to the second and the zone name for each
117
- event date, in both modes. The header keeps them on one line beside the
118
- actions. Their tooltip adds milliseconds, and the `time` element keeps the
119
- original ISO value. The mode, not the timezone identifier, persists across
120
- visits and tabs. This hook belongs to the client-rendered event viewer. Raw
121
- JSON retains the original ISO values.
122
-
123
- ## Event details
124
-
125
- The URL owns the selected event in the main Conversation. `ConversationPage`
126
- places `ConversationEventDetails` beside the log in the page panel. Selecting
127
- another row changes the event and resets its scroll position and disclosures.
128
- Closing returns focus to that row. Switching Conversations removes the panel.
129
-
130
- The previous and next controls select the adjacent visible row. They form one
131
- `ui/button-group` named "Event navigation". They follow
132
- the event search, like Up and Down. They are necessary below 1280px, where the
133
- sheet covers the log. At the ends of the list, the control is disabled but
134
- keeps focus. The sheet title is the event type. The header shows the event
135
- type, then the sequence number and timestamp. The body groups fields in the
136
- same `DetailsCard` that Conversation details use. Groups inside a card, such
137
- as tool input and output, use a divider, not another card.
138
-
139
- A linked event can be older than the loaded pages. While the event loads, the
140
- panel stays open. Only its header shows placeholders, so it does not compete
141
- with the log. While the transcript loads, `ConversationEventLogLoading` shows
142
- the log toolbar, columns, and row skeletons in the event log view.
143
-
144
- Standalone transcripts, such as a subagent drawer, keep selection in
145
- `ConversationEventLog`. Their event details use a nested drawer on desktop and
146
- `BottomSheet` on smaller screens. The nested drawer stacks in front of the
147
- subagent drawer. The subagent drawer shows its event log without a body inset,
148
- so rows meet the drawer edges and the toolbar sticks to the top. This keeps the main log free of modal behavior
149
- while a nested transcript retains its parent drawer's focus rules. These event
150
- details have the same previous and next controls.
151
-
152
- `SubagentTranscriptDrawer` uses the wide `Drawer` at all widths. Below 768px
153
- the drawer fills the screen, so the long transcript gets the most room. Its
154
- header holds search, view, and copy actions. `BottomSheet` has no place for
155
- them.
156
-
157
- `ForkConversationButton` opens a `ui/dialog` form, not a drawer. The dialog
158
- stays above event details in a docked panel or a sheet. Cancel returns focus
159
- to the fork button. A pending fork blocks dismissal until the request ends.
@@ -1,39 +0,0 @@
1
- import { formatUserInputAnswer } from "@sentry/junior/api/schema";
2
-
3
- import { UserInputForm } from "../components/UserInputForm";
4
- import { TranscriptText } from "./TranscriptText";
5
- import type { OpenUserInputRequest } from "./userInputRequest";
6
-
7
- /**
8
- * Show Junior's open request above the composer. The answer goes as the
9
- * reader's next message. Typing a reply also answers it.
10
- */
11
- export function UserInputRequestCard(props: {
12
- onAnswer(answer: string): Promise<void>;
13
- request: OpenUserInputRequest;
14
- }) {
15
- return (
16
- <section
17
- aria-label="Junior asks"
18
- className="mb-2 rounded-lg border border-cyan-300/20 bg-cyan-300/[0.07] px-3 py-2.5 font-sans text-sm text-dashboard-text"
19
- >
20
- <div className="max-h-48 overflow-y-auto">
21
- <TranscriptText
22
- mentions={[]}
23
- role="assistant"
24
- text={props.request.question}
25
- />
26
- </div>
27
- {/* Above the composer, a long form scrolls so the transcript stays visible. */}
28
- <div className="max-h-96 overflow-y-auto">
29
- <UserInputForm
30
- onSubmit={(answer) =>
31
- props.onAnswer(formatUserInputAnswer(props.request, answer))
32
- }
33
- request={props.request}
34
- requestId={props.request.toolCallId}
35
- />
36
- </div>
37
- </section>
38
- );
39
- }
@@ -1,56 +0,0 @@
1
- import {
2
- userInputRequestSchema,
3
- type ConversationReportEvent,
4
- type UserInputRequest,
5
- } from "@sentry/junior/api/schema";
6
-
7
- /** Model-facing name of Junior's tool that asks a person for input. */
8
- const REQUEST_USER_INPUT_TOOL_NAME = "requestUserInput";
9
-
10
- /** A request from Junior that still waits for an answer. */
11
- export type OpenUserInputRequest = UserInputRequest & { toolCallId: string };
12
-
13
- /**
14
- * Find the latest `requestUserInput` call that no user message answers yet.
15
- * Any later user message is the answer, whether it is a submitted form or
16
- * typed text.
17
- *
18
- * Reporting splits one call over events: the assistant event has the input
19
- * and status `running`, and the later result event has status `completed`
20
- * without the input. Keep the input by tool call id until the result.
21
- */
22
- export function openUserInputRequest(
23
- events: readonly ConversationReportEvent[] | undefined,
24
- ): OpenUserInputRequest | undefined {
25
- const inputs = new Map<string, unknown>();
26
- const completed = new Set<string>();
27
- let open: OpenUserInputRequest | undefined;
28
- for (const event of events ?? []) {
29
- const data = event.data;
30
- if (data.type === "message" && data.role === "user") {
31
- open = undefined;
32
- continue;
33
- }
34
- if (data.type !== "tool_calls") continue;
35
- for (const call of data.calls) {
36
- if (call.name !== REQUEST_USER_INPUT_TOOL_NAME) continue;
37
- if (call.input !== undefined) inputs.set(call.toolCallId, call.input);
38
- if (call.status === "error" && open?.toolCallId === call.toolCallId) {
39
- open = undefined;
40
- }
41
- // Open a request once, when its result first arrives. A repeated
42
- // result must not reopen a request that a user message answered.
43
- if (call.status !== "completed" || completed.has(call.toolCallId)) {
44
- continue;
45
- }
46
- completed.add(call.toolCallId);
47
- const request = userInputRequestSchema.safeParse(
48
- inputs.get(call.toolCallId),
49
- );
50
- if (request.success) {
51
- open = { ...request.data, toolCallId: call.toolCallId };
52
- }
53
- }
54
- }
55
- return open;
56
- }
@@ -1,97 +0,0 @@
1
- # Automation editor
2
-
3
- Core owns validation, edit access, creator-only rules, revision checks,
4
- Schedule previews, and the Event catalog. Preview requests cannot save or run
5
- work. Completed scheduled Automations remain read-only.
6
-
7
- Creators and public Destination readers can edit. For a public reader, the
8
- editor shows outcomes as read-only and blocks turning on creator credential
9
- use. It warns that an instruction or event selector change switches to system
10
- credentials. Pause and resume stay creator-only.
11
-
12
- The editor sends only changed fields. Keep unsupported triggers and stored
13
- Destinations intact unless the user replaces them. Outcomes keep their order.
14
- New messages can target only the current Destination or the creator.
15
-
16
- Query refreshes must not replace an unsaved draft. After a stale save, the user
17
- can keep their changed fields or load the latest saved version. Unchanged fields
18
- come from that version; core checks its revision again on save.
19
-
20
- The data router blocks navigation with unsaved changes. Browser unload uses the
21
- native prompt. Save and Cancel return to the Automation page and keep its query
22
- string.
23
-
24
- Version history lists saved versions, newest first, and marks the active
25
- version. "Make active" uses the native confirm dialog, like delete. It then
26
- reads the latest revision and asks core to save that version again as a new
27
- version. Core applies the same edit rules, so the page
28
- shows its error when a public reader cannot make a version active.
29
-
30
- Browser behavior lives in `e2e/automation-editor.spec.ts`. API and persistence
31
- coverage lives in core's `tests/integration/api/automation-edits.test.ts`.
32
-
33
- ## Automation page
34
-
35
- Each Automation has one page at `/automations/:id`. Overview, Runs, and
36
- Versions are tabs. They use `SecondaryNavigation`, like the repository page.
37
- `/automations/:id/edit` is edit mode of the Overview tab. The old
38
- `/executions` route redirects to `/runs` and keeps the query string. List rows
39
- link to the page. There is no details slideout.
40
-
41
- The page keeps the list query string. "All automations" returns to the same
42
- list page and filters. The back link drops params that belong to one tab:
43
- `result`, `run`, and `version`. One `range` param drives the Overview numbers
44
- and the Runs chart.
45
-
46
- The header shows the name, the state, the trigger, the Destination, and the
47
- creator. `AutomationStateChip` is a live region, so Pause and Resume results
48
- are announced. `AutomationActions` owns Edit, Pause or Resume, pause help, and
49
- Delete. Lifecycle actions re-read the revision before they apply. Public
50
- readers can edit settings. Pause, Resume, and Delete stay creator-only, so
51
- other viewers do not see them. The About card names the creator-only actions.
52
- Completed Automations have no Edit action, and `/edit` returns to Overview.
53
-
54
- Overview shows `AutomationAttention` first when something needs action: a
55
- block, an unavailable trigger, or a failed last run. The notice has one main
56
- action, such as Change trigger or Open last run. While it shows, the header
57
- Edit button becomes a secondary button. The saved settings follow
58
- in the same `AutomationFormSection` rows as the editor, so edit mode changes
59
- them in place. The side column shows the next trigger, the last result, runs,
60
- failures, and spend for the range, and About. Spend is `costUsd` from the
61
- Automation summary. On small screens, status comes first and About moves below
62
- the settings.
63
-
64
- `AutomationRecentRuns` uses the existing execution-history query and cache. It
65
- shows up to three newest terminal runs, links to their Conversations when one
66
- was recorded, and displays recorded runtime and estimated cost. It omits run
67
- titles that repeat the Automation name. Its loading,
68
- empty, and retry states do not replace Automation settings. It does not infer
69
- queued or running work from terminal records.
70
-
71
- In edit mode, "Your changes" lists each changed field with the saved value, the
72
- new value, and its own Undo. It is beside the form on wide screens and below
73
- the form on small screens when there are changes. Undo remounts the fields, so fields with local state show the saved value again.
74
- Changed sections get an accent mark. Save and Cancel return to Overview.
75
-
76
- The Runs tab filters loaded runs by result through the `result` param. Rows
77
- show the version that ran and the recorded error. A row opens the run details
78
- panel. The run list scrolls on its own beside it.
79
-
80
- The Versions tab lists versions and compares the selected one with the version
81
- before it. The `version` param selects a version; run details link to it.
82
- Changed fields show the previous value. Instruction changes use a line diff.
83
-
84
- `AutomationDeleteDialog` names the Automation before deletion. It keeps errors
85
- and retry inside the dialog and blocks dismissal while the request is pending.
86
- Cancel returns focus to Delete. Successful deletion returns to the list.
87
- Success toasts confirm Save, Pause, Resume, and Delete. Their state belongs to
88
- the mounted dashboard's Toaster provider.
89
-
90
- Browser journeys for the page live in `e2e/automations.spec.ts`. Use mock
91
- reporting to review scheduled and event Automations in both themes at desktop
92
- and mobile widths. Keep layout checks in manual QA.
93
-
94
- Filters use a shadcn Popover at 768px and above and the shared BottomSheet below
95
- that width. Both edit the same URL filters immediately. Active filter chips
96
- remove one filter without clearing search, scope, or other filters. The mobile
97
- sheet fits its controls instead of taking the full screen height.
@@ -1,23 +0,0 @@
1
- # System pages
2
-
3
- ## Workspaces
4
-
5
- `/system/workspaces` lists the Workspace recipes. The URL selects one recipe:
6
- `/system/workspaces/:id` keeps the list and opens `WorkspaceDetails` in the
7
- shared `DetailsPanel`. The panel is 400px wide at 1280px and above. Smaller
8
- screens use the bottom sheet. Repository pages link to these details.
9
-
10
- The panel shows the list item at once. The detail read adds the current
11
- snapshot, because the list report does not include snapshots. Snapshot loading
12
- and errors stay in the Snapshot row. Usage shows switches for the last 30 days.
13
- Workspace switch counts are daily only.
14
-
15
- Edit and Delete are in the panel header. List rows have no actions. Edit opens
16
- the full-page editor at `/system/workspaces/:id/edit`. Save and Cancel return to
17
- the details. A new Workspace opens its details after create.
18
-
19
- Close and Escape return focus to the selected row. `WorkspaceDeleteDialog`
20
- names the recipe, keeps errors inside the dialog, and blocks dismissal while the
21
- request runs. A successful delete closes the details and shows a toast.
22
-
23
- Browser coverage lives in `e2e/system.spec.ts`.