@sentry/junior-dashboard 0.265.0 → 0.266.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/dist/app.js +2 -2
- package/dist/client.js +48 -48
- package/dist/index.js +2 -2
- package/dist/tailwind.css +1 -1
- package/package.json +3 -3
- package/src/client/components/ActorAvatar.tsx +10 -22
- package/src/client/components/ConnectionBanner.tsx +4 -3
- package/src/client/components/CopyButton.tsx +3 -4
- package/src/client/components/EmptyTelemetry.tsx +5 -3
- package/src/client/components/ImageAttachment.tsx +49 -63
- package/src/client/components/InlineError.tsx +8 -4
- package/src/client/components/Notice.tsx +19 -26
- package/src/client/components/Pagination.tsx +26 -26
- package/src/client/components/ParticipantAvatarStack.tsx +10 -10
- package/src/client/components/README.md +17 -1
- package/src/client/components/SearchInput.tsx +51 -41
- package/src/client/components/VersionDriftBanner.tsx +9 -7
- package/src/client/components/charts/CacheWrites.tsx +52 -43
- package/src/client/components/ui/alert.tsx +64 -0
- package/src/client/components/ui/avatar.tsx +53 -0
- package/src/client/components/ui/button.tsx +2 -1
- package/src/client/components/ui/dialog.tsx +66 -0
- package/src/client/components/ui/empty.tsx +32 -0
- package/src/client/components/ui/input-group.tsx +96 -0
- package/src/client/components/ui/pagination.tsx +60 -0
- package/src/client/components/ui/spinner.tsx +21 -0
- package/src/client/components/ui/table.tsx +22 -1
- package/src/client/components/ui/tooltip.tsx +1 -1
- package/src/client/conversations/ConversationChildAgents.tsx +5 -5
- package/src/client/conversations/ConversationHeader.tsx +5 -4
- package/src/client/conversations/ConversationHeaderActions.tsx +7 -11
- package/src/client/conversations/ConversationSidebar.tsx +5 -4
- package/src/client/conversations/ConversationUsageBreakdown.tsx +108 -65
- package/src/client/conversations/ConversationWatches.tsx +67 -59
- package/src/client/conversations/DetailsList.tsx +44 -29
- package/src/client/conversations/EventUsage.tsx +99 -74
- package/src/client/conversations/PendingMailboxStack.tsx +5 -10
- package/src/client/conversations/README.md +3 -0
- package/src/client/conversations/ShareConversationButton.tsx +3 -4
- package/src/client/conversations/TranscriptEventView.tsx +35 -16
- package/src/client/conversations/TranscriptMessageContextView.tsx +31 -20
- package/src/client/conversations/TranscriptStructuredEventView.tsx +25 -15
- package/src/client/conversations/TranscriptSummary.tsx +34 -2
- package/src/client/conversations/TranscriptTurnContextView.tsx +45 -38
- package/src/client/conversations/eventLog.ts +1 -0
- package/src/client/conversations/transcriptMentions.tsx +18 -5
- package/src/mock-reporting/watches.ts +1 -1
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { Collapsible, CollapsibleContent } from "../components/ui/collapsible";
|
|
1
2
|
import { formatMessageTimestamp } from "../format";
|
|
2
3
|
import type { TranscriptViewStructuredEventPart } from "../types";
|
|
3
4
|
import { MentionText } from "./transcriptMentions";
|
|
4
5
|
import { HighlightText, useTranscriptSearch } from "./transcriptSearch";
|
|
5
|
-
import {
|
|
6
|
+
import { TranscriptSummaryTrigger } from "./TranscriptSummary";
|
|
6
7
|
|
|
7
8
|
type TranscriptPresentationEventPart = TranscriptViewStructuredEventPart;
|
|
8
9
|
|
|
@@ -58,27 +59,34 @@ export function TranscriptStructuredEventView(props: {
|
|
|
58
59
|
))}
|
|
59
60
|
</div>
|
|
60
61
|
) : null;
|
|
62
|
+
const collapsible = details.length > 0 && !search.active;
|
|
63
|
+
// The header can sit inside the row button, so it uses only inline elements
|
|
64
|
+
// and no links.
|
|
61
65
|
const header = (
|
|
62
|
-
<
|
|
63
|
-
<
|
|
64
|
-
<
|
|
66
|
+
<span className="grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-start gap-2 max-md:grid-cols-[minmax(0,1fr)]">
|
|
67
|
+
<span className="min-w-0">
|
|
68
|
+
<span className="block text-sm font-medium leading-6 text-dashboard-text">
|
|
65
69
|
<HighlightText text={presentation.title} />
|
|
66
|
-
</
|
|
70
|
+
</span>
|
|
67
71
|
{presentation.preview ? (
|
|
68
|
-
<
|
|
69
|
-
<MentionText
|
|
70
|
-
|
|
72
|
+
<span className="mt-0.5 block truncate text-xs text-dashboard-text-muted">
|
|
73
|
+
<MentionText
|
|
74
|
+
links={!collapsible}
|
|
75
|
+
mentions={mentions}
|
|
76
|
+
text={presentation.preview}
|
|
77
|
+
/>
|
|
78
|
+
</span>
|
|
71
79
|
) : null}
|
|
72
|
-
</
|
|
80
|
+
</span>
|
|
73
81
|
{timestamp ? (
|
|
74
82
|
<span className="text-xs leading-6 tabular-nums text-dashboard-text-muted max-md:hidden">
|
|
75
83
|
{timestamp}
|
|
76
84
|
</span>
|
|
77
85
|
) : null}
|
|
78
|
-
</
|
|
86
|
+
</span>
|
|
79
87
|
);
|
|
80
88
|
|
|
81
|
-
if (
|
|
89
|
+
if (!collapsible) {
|
|
82
90
|
return (
|
|
83
91
|
<div className={surfaceClass}>
|
|
84
92
|
{header}
|
|
@@ -87,9 +95,11 @@ export function TranscriptStructuredEventView(props: {
|
|
|
87
95
|
);
|
|
88
96
|
}
|
|
89
97
|
return (
|
|
90
|
-
<
|
|
91
|
-
<
|
|
92
|
-
|
|
93
|
-
|
|
98
|
+
<Collapsible className={surfaceClass}>
|
|
99
|
+
<TranscriptSummaryTrigger flush className="block">
|
|
100
|
+
{header}
|
|
101
|
+
</TranscriptSummaryTrigger>
|
|
102
|
+
<CollapsibleContent hiddenUntilFound>{body}</CollapsibleContent>
|
|
103
|
+
</Collapsible>
|
|
94
104
|
);
|
|
95
105
|
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import type { ComponentPropsWithoutRef } from "react";
|
|
1
|
+
import type { ComponentProps, ComponentPropsWithoutRef } from "react";
|
|
2
2
|
|
|
3
|
+
import { CollapsibleTrigger } from "../components/ui/collapsible";
|
|
3
4
|
import { cn } from "../styles";
|
|
4
5
|
|
|
6
|
+
const summaryClass =
|
|
7
|
+
"cursor-pointer rounded-md px-2 py-1.5 transition-colors hover:bg-dashboard-fill-hover focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-dashboard-focus";
|
|
8
|
+
|
|
5
9
|
/** Keep hover and keyboard focus around a padded transcript cell. */
|
|
6
10
|
export function TranscriptSummary({
|
|
7
11
|
className,
|
|
@@ -15,10 +19,38 @@ export function TranscriptSummary({
|
|
|
15
19
|
<summary
|
|
16
20
|
{...props}
|
|
17
21
|
className={cn(
|
|
18
|
-
|
|
22
|
+
summaryClass,
|
|
23
|
+
"list-none [&::-webkit-details-marker]:hidden",
|
|
19
24
|
flush && "-mx-2 -my-1.5",
|
|
20
25
|
className,
|
|
21
26
|
)}
|
|
22
27
|
/>
|
|
23
28
|
);
|
|
24
29
|
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Give a `Collapsible` trigger the same padding, hover, and focus as
|
|
33
|
+
* `TranscriptSummary`. The caller sets the display. Put only inline elements,
|
|
34
|
+
* such as `span`, inside the trigger.
|
|
35
|
+
*/
|
|
36
|
+
export function TranscriptSummaryTrigger({
|
|
37
|
+
className,
|
|
38
|
+
flush = false,
|
|
39
|
+
...props
|
|
40
|
+
}: Omit<ComponentProps<typeof CollapsibleTrigger>, "className"> & {
|
|
41
|
+
className?: string;
|
|
42
|
+
/** Extend padding around text that already sits on the transcript edge. */
|
|
43
|
+
flush?: boolean;
|
|
44
|
+
}) {
|
|
45
|
+
return (
|
|
46
|
+
<CollapsibleTrigger
|
|
47
|
+
{...props}
|
|
48
|
+
className={cn(
|
|
49
|
+
summaryClass,
|
|
50
|
+
"text-left disabled:cursor-default disabled:hover:bg-transparent",
|
|
51
|
+
flush ? "-mx-2 -my-1.5 w-[calc(100%+1rem)]" : "w-full",
|
|
52
|
+
className,
|
|
53
|
+
)}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -9,13 +9,14 @@ import {
|
|
|
9
9
|
import { createPortal } from "react-dom";
|
|
10
10
|
|
|
11
11
|
import { DetailsPanel } from "../components/DetailsPanel";
|
|
12
|
+
import { Collapsible, CollapsibleContent } from "../components/ui/collapsible";
|
|
12
13
|
import { Drawer } from "../components/Drawer";
|
|
13
14
|
import type { TranscriptViewTurnContext } from "../types";
|
|
14
15
|
import { formatMessageTimestamp, formatTime } from "../format";
|
|
15
16
|
import { memoryRecallContent, type MemoryRecallContent } from "./turnContext";
|
|
16
|
-
import { cn } from "../styles";
|
|
17
|
+
import { cn, dashboardDisclosureChevronClass } from "../styles";
|
|
17
18
|
import { HighlightText } from "./transcriptSearch";
|
|
18
|
-
import {
|
|
19
|
+
import { TranscriptSummaryTrigger } from "./TranscriptSummary";
|
|
19
20
|
|
|
20
21
|
/** The turn context that a page panel shows, keyed by its message. */
|
|
21
22
|
export type TurnContextSelection = {
|
|
@@ -189,15 +190,17 @@ function MemoryRecall(props: {
|
|
|
189
190
|
return (
|
|
190
191
|
<div className="overflow-hidden rounded-lg border border-dashboard-border-strong">
|
|
191
192
|
{props.memories.map((memory, index) => (
|
|
192
|
-
<
|
|
193
|
-
className="
|
|
193
|
+
<Collapsible
|
|
194
|
+
className="border-t border-dashboard-border-strong first:border-t-0"
|
|
194
195
|
key={memory.id}
|
|
195
196
|
>
|
|
196
|
-
<
|
|
197
|
+
<TranscriptSummaryTrigger className="group flex items-start gap-2.5">
|
|
197
198
|
<ChevronRight
|
|
198
199
|
aria-hidden="true"
|
|
199
|
-
className=
|
|
200
|
-
|
|
200
|
+
className={cn(
|
|
201
|
+
dashboardDisclosureChevronClass,
|
|
202
|
+
"mt-0.5 text-dashboard-text-muted",
|
|
203
|
+
)}
|
|
201
204
|
/>
|
|
202
205
|
<span className="min-w-0 flex-1">
|
|
203
206
|
<span className="flex items-center justify-between gap-3">
|
|
@@ -212,39 +215,43 @@ function MemoryRecall(props: {
|
|
|
212
215
|
<HighlightText text={memory.content} />
|
|
213
216
|
</span>
|
|
214
217
|
</span>
|
|
215
|
-
</
|
|
216
|
-
|
|
217
|
-
<div className="border-t border-dashboard-border bg-dashboard-fill-faint px-4 py-4">
|
|
218
|
-
<div className="whitespace-pre-wrap text-sm leading-6 text-dashboard-text">
|
|
219
|
-
<HighlightText text={memory.content} />
|
|
220
|
-
</div>
|
|
218
|
+
</TranscriptSummaryTrigger>
|
|
221
219
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
<
|
|
226
|
-
<HighlightText text={memory.id} />
|
|
227
|
-
</dd>
|
|
228
|
-
</div>
|
|
229
|
-
<div className="grid grid-cols-[5rem_minmax(0,1fr)] items-start gap-3">
|
|
230
|
-
<dt className="text-dashboard-text-muted">Observed</dt>
|
|
231
|
-
<dd className="m-0 text-dashboard-text-muted">
|
|
232
|
-
{formatTime(new Date(memory.observedAtMs).toISOString())}
|
|
233
|
-
</dd>
|
|
234
|
-
</div>
|
|
235
|
-
<div className="grid grid-cols-[5rem_minmax(0,1fr)] items-start gap-3">
|
|
236
|
-
<dt className="text-dashboard-text-muted">Scope</dt>
|
|
237
|
-
<dd className="m-0 text-dashboard-text-muted">
|
|
238
|
-
{memory.scope}
|
|
239
|
-
</dd>
|
|
240
|
-
</div>
|
|
241
|
-
<div className="grid grid-cols-[5rem_minmax(0,1fr)] items-start gap-3">
|
|
242
|
-
<dt className="text-dashboard-text-muted">Kind</dt>
|
|
243
|
-
<dd className="m-0 text-dashboard-text-muted">{memory.kind}</dd>
|
|
220
|
+
<CollapsibleContent hiddenUntilFound>
|
|
221
|
+
<div className="border-t border-dashboard-border bg-dashboard-fill-faint px-4 py-4">
|
|
222
|
+
<div className="whitespace-pre-wrap text-sm leading-6 text-dashboard-text">
|
|
223
|
+
<HighlightText text={memory.content} />
|
|
244
224
|
</div>
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
225
|
+
|
|
226
|
+
<dl className="mt-4 grid gap-2 text-xs">
|
|
227
|
+
<div className="grid grid-cols-[5rem_minmax(0,1fr)] items-start gap-3">
|
|
228
|
+
<dt className="text-dashboard-text-muted">Memory ID</dt>
|
|
229
|
+
<dd className="m-0 break-all font-mono text-dashboard-text-muted">
|
|
230
|
+
<HighlightText text={memory.id} />
|
|
231
|
+
</dd>
|
|
232
|
+
</div>
|
|
233
|
+
<div className="grid grid-cols-[5rem_minmax(0,1fr)] items-start gap-3">
|
|
234
|
+
<dt className="text-dashboard-text-muted">Observed</dt>
|
|
235
|
+
<dd className="m-0 text-dashboard-text-muted">
|
|
236
|
+
{formatTime(new Date(memory.observedAtMs).toISOString())}
|
|
237
|
+
</dd>
|
|
238
|
+
</div>
|
|
239
|
+
<div className="grid grid-cols-[5rem_minmax(0,1fr)] items-start gap-3">
|
|
240
|
+
<dt className="text-dashboard-text-muted">Scope</dt>
|
|
241
|
+
<dd className="m-0 text-dashboard-text-muted">
|
|
242
|
+
{memory.scope}
|
|
243
|
+
</dd>
|
|
244
|
+
</div>
|
|
245
|
+
<div className="grid grid-cols-[5rem_minmax(0,1fr)] items-start gap-3">
|
|
246
|
+
<dt className="text-dashboard-text-muted">Kind</dt>
|
|
247
|
+
<dd className="m-0 text-dashboard-text-muted">
|
|
248
|
+
{memory.kind}
|
|
249
|
+
</dd>
|
|
250
|
+
</div>
|
|
251
|
+
</dl>
|
|
252
|
+
</div>
|
|
253
|
+
</CollapsibleContent>
|
|
254
|
+
</Collapsible>
|
|
248
255
|
))}
|
|
249
256
|
<p className="m-0 border-t border-dashboard-border-strong px-3 py-2 text-xs text-dashboard-text-muted">
|
|
250
257
|
{props.memories.length}{" "}
|
|
@@ -111,6 +111,7 @@ export function eventLogTone(data: ConversationReportEventData): string {
|
|
|
111
111
|
}
|
|
112
112
|
if (
|
|
113
113
|
(data.type === "guardian_action_reviewed" && data.decision === "ask") ||
|
|
114
|
+
(data.type === "turn_lifecycle" && data.state === "blocked") ||
|
|
114
115
|
(data.type === "subagent" &&
|
|
115
116
|
(data.status === "aborted" || data.status === "blocked"))
|
|
116
117
|
) {
|
|
@@ -43,12 +43,17 @@ export function MentionPeopleProvider(props: {
|
|
|
43
43
|
|
|
44
44
|
/** Render one line of display text with the people the API resolved for it. */
|
|
45
45
|
export function MentionText(props: {
|
|
46
|
+
/**
|
|
47
|
+
* Link people to their page. Set false inside a button, which cannot hold
|
|
48
|
+
* a link.
|
|
49
|
+
*/
|
|
50
|
+
links?: boolean;
|
|
46
51
|
mentions: readonly ActorIdentity[];
|
|
47
52
|
text: string;
|
|
48
53
|
}) {
|
|
49
54
|
return (
|
|
50
55
|
<MentionPeopleProvider mentions={props.mentions}>
|
|
51
|
-
{renderMentionText(props.text, "mention-text")}
|
|
56
|
+
{renderMentionText(props.text, "mention-text", props.links)}
|
|
52
57
|
</MentionPeopleProvider>
|
|
53
58
|
);
|
|
54
59
|
}
|
|
@@ -57,7 +62,11 @@ export function MentionText(props: {
|
|
|
57
62
|
* Render text with Slack `<@U123>` and `<#C123|name>` tokens as readable
|
|
58
63
|
* mentions. It reads people from the nearest `MentionPeopleProvider`.
|
|
59
64
|
*/
|
|
60
|
-
export function renderMentionText(
|
|
65
|
+
export function renderMentionText(
|
|
66
|
+
text: string,
|
|
67
|
+
keyBase: string,
|
|
68
|
+
links = true,
|
|
69
|
+
): ReactNode[] {
|
|
61
70
|
const nodes: ReactNode[] = [];
|
|
62
71
|
let cursor = 0;
|
|
63
72
|
for (const mention of findMentions(text)) {
|
|
@@ -70,7 +79,11 @@ export function renderMentionText(text: string, keyBase: string): ReactNode[] {
|
|
|
70
79
|
);
|
|
71
80
|
}
|
|
72
81
|
nodes.push(
|
|
73
|
-
<MentionView
|
|
82
|
+
<MentionView
|
|
83
|
+
key={`${keyBase}-m-${mention.start}`}
|
|
84
|
+
links={links}
|
|
85
|
+
mention={mention}
|
|
86
|
+
/>,
|
|
74
87
|
);
|
|
75
88
|
cursor = mention.end;
|
|
76
89
|
}
|
|
@@ -95,13 +108,13 @@ function findMentions(text: string): TranscriptMention[] {
|
|
|
95
108
|
}));
|
|
96
109
|
}
|
|
97
110
|
|
|
98
|
-
function MentionView(props: { mention: TranscriptMention }) {
|
|
111
|
+
function MentionView(props: { links: boolean; mention: TranscriptMention }) {
|
|
99
112
|
const people = useContext(TranscriptMentionPeople);
|
|
100
113
|
const { id, label, sigil } = props.mention;
|
|
101
114
|
const person = sigil === "@" ? people.get(id) : undefined;
|
|
102
115
|
const name = person?.fullName ?? person?.slackUserName ?? label ?? id;
|
|
103
116
|
const text = <HighlightText text={`${sigil}${name.replace(/^[@#]/, "")}`} />;
|
|
104
|
-
if (person?.email) {
|
|
117
|
+
if (props.links && person?.email) {
|
|
105
118
|
return (
|
|
106
119
|
<Link
|
|
107
120
|
// Previews sit in cards that disable pointer events on their text.
|
|
@@ -8,7 +8,7 @@ const HOUR_MS = 60 * 60_000;
|
|
|
8
8
|
const DAY_MS = 24 * HOUR_MS;
|
|
9
9
|
|
|
10
10
|
// Watch times are relative to the real clock, not the fixed fixture time, so
|
|
11
|
-
// time
|
|
11
|
+
// the timer fire time stays in the future.
|
|
12
12
|
function iso(offsetMs: number): string {
|
|
13
13
|
return new Date(Date.now() + offsetMs).toISOString();
|
|
14
14
|
}
|