@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.
- package/README.md +7 -105
- package/dist/app.js +12 -9
- package/dist/client.js +72 -75
- package/dist/index.js +12 -9
- package/dist/tailwind.css +1 -1
- package/package.json +4 -4
- package/src/api/schema.ts +2 -1
- package/src/app.ts +11 -7
- package/src/client/App.tsx +1 -5
- package/src/client/api.ts +4 -19
- package/src/client/components/AGENTS.md +65 -0
- package/src/client/components/ActorAvatar.tsx +1 -1
- package/src/client/components/ParticipantAvatarStack.tsx +1 -0
- package/src/client/components/ProfileMenu.tsx +88 -29
- package/src/client/components/UserInputForm.tsx +1 -1
- package/src/client/components/charts/AGENTS.md +15 -0
- package/src/client/conversations/AGENTS.md +42 -0
- package/src/client/conversations/ConversationPage.tsx +0 -27
- package/src/client/format.ts +7 -23
- package/src/client/pages/automations/AGENTS.md +34 -0
- package/src/client/pages/automations/AutomationActions.tsx +18 -20
- package/src/client/pages/automations/AutomationEditor.tsx +3 -4
- package/src/client/pages/automations/AutomationOverview.tsx +3 -3
- package/src/client/pages/automations/AutomationStatus.tsx +2 -2
- package/src/client/pages/system/AGENTS.md +12 -0
- package/src/client/review-desk/ConversationReviewBar.tsx +14 -8
- package/src/client/review-desk/ReviewDeskPage.tsx +99 -79
- package/src/client/review-desk/ReviewItemDetail.tsx +15 -7
- package/src/client/review-desk/queries.ts +25 -16
- package/src/mock-reporting/routes.ts +1 -1
- package/src/tailwind.css +1 -1
- package/src/client/components/README.md +0 -219
- package/src/client/components/charts/README.md +0 -38
- package/src/client/conversations/README.md +0 -159
- package/src/client/conversations/UserInputRequestCard.tsx +0 -39
- package/src/client/conversations/userInputRequest.ts +0 -56
- package/src/client/pages/automations/README.md +0 -97
- 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`.
|