@sentry/junior-dashboard 0.265.0 → 0.267.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 +49 -12
- package/dist/client.js +94 -63
- package/dist/index.js +49 -12
- package/dist/tailwind.css +1 -1
- package/package.json +11 -5
- package/src/app.ts +0 -2
- package/src/auth.ts +4 -7
- package/src/client/App.tsx +35 -53
- 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/DetailsPanel.tsx +12 -13
- package/src/client/components/Drawer.tsx +46 -23
- 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 +13 -10
- package/src/client/components/README.md +28 -3
- 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-group.tsx +59 -0
- package/src/client/components/ui/button.tsx +2 -1
- package/src/client/components/ui/dialog.tsx +60 -0
- package/src/client/components/ui/drawer.tsx +140 -0
- package/src/client/components/ui/empty.tsx +61 -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/separator.tsx +22 -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/components/ui/useSheet.ts +5 -1
- package/src/client/conversations/ComposerImages.tsx +66 -14
- package/src/client/conversations/ConversationChildAgents.tsx +5 -5
- package/src/client/conversations/ConversationComposer.tsx +84 -12
- package/src/client/conversations/ConversationDetails.tsx +3 -27
- package/src/client/conversations/ConversationEventDetails.tsx +26 -10
- package/src/client/conversations/ConversationHeader.tsx +5 -4
- package/src/client/conversations/ConversationHeaderActions.tsx +7 -11
- package/src/client/conversations/ConversationPage.tsx +156 -2
- package/src/client/conversations/ConversationSidebar.tsx +5 -4
- package/src/client/conversations/ConversationTranscript.tsx +48 -16
- package/src/client/conversations/ConversationUsageBreakdown.tsx +108 -65
- package/src/client/conversations/ConversationWatches.tsx +67 -59
- package/src/client/conversations/DetailsList.tsx +77 -29
- package/src/client/conversations/EventDetails.tsx +46 -19
- package/src/client/conversations/EventUsage.tsx +99 -74
- package/src/client/conversations/ForkConversationButton.tsx +79 -73
- package/src/client/conversations/PendingMailboxStack.tsx +312 -119
- package/src/client/conversations/README.md +30 -10
- package/src/client/conversations/ShareConversationButton.tsx +3 -4
- package/src/client/conversations/SubagentTranscriptDrawer.tsx +19 -22
- package/src/client/conversations/TranscriptActivityGroup.tsx +22 -19
- package/src/client/conversations/TranscriptAttachment.tsx +39 -4
- package/src/client/conversations/TranscriptAutomationTriggerView.tsx +14 -19
- package/src/client/conversations/TranscriptEventView.tsx +35 -16
- package/src/client/conversations/TranscriptFailureView.tsx +10 -13
- package/src/client/conversations/TranscriptMarkdown.tsx +232 -436
- package/src/client/conversations/TranscriptMessageContextView.tsx +31 -20
- package/src/client/conversations/TranscriptMessageView.tsx +7 -1
- package/src/client/conversations/TranscriptStructuredEventView.tsx +25 -15
- package/src/client/conversations/TranscriptSummary.tsx +13 -7
- package/src/client/conversations/TranscriptTurnContextView.tsx +78 -56
- package/src/client/conversations/TranscriptView.tsx +7 -3
- package/src/client/conversations/UserInputRequestCard.tsx +244 -0
- package/src/client/conversations/conversationOutbox.ts +46 -0
- package/src/client/conversations/eventLog.ts +1 -0
- package/src/client/conversations/eventTime.ts +13 -1
- package/src/client/conversations/eventTranscript.ts +12 -5
- package/src/client/conversations/queries.ts +127 -26
- package/src/client/conversations/transcriptMarkdownLinks.ts +5 -367
- package/src/client/conversations/transcriptMentions.tsx +18 -5
- package/src/client/conversations/userInputRequest.ts +56 -0
- package/src/client/format.ts +10 -3
- package/src/client/pages/automations/{AutomationLifecycle.tsx → AutomationActions.tsx} +60 -69
- package/src/client/pages/automations/AutomationDraftChanges.tsx +171 -0
- package/src/client/pages/automations/AutomationEditor.tsx +182 -156
- package/src/client/pages/automations/AutomationEventFields.tsx +119 -45
- package/src/client/pages/automations/AutomationExecutionStatusChart.tsx +1 -1
- package/src/client/pages/automations/AutomationFormSection.tsx +20 -2
- package/src/client/pages/automations/AutomationOutcomeFields.tsx +1 -1
- package/src/client/pages/automations/AutomationOverview.tsx +238 -0
- package/src/client/pages/automations/AutomationPage.tsx +343 -0
- package/src/client/pages/automations/AutomationRecentRuns.tsx +3 -2
- package/src/client/pages/automations/AutomationRow.tsx +11 -13
- package/src/client/pages/automations/AutomationRunDetails.tsx +4 -2
- package/src/client/pages/automations/{AutomationExecutionsPage.tsx → AutomationRunsTab.tsx} +94 -103
- package/src/client/pages/automations/AutomationStatus.tsx +164 -108
- package/src/client/pages/automations/AutomationVersionsTab.tsx +518 -0
- package/src/client/pages/automations/AutomationsPage.tsx +10 -98
- package/src/client/pages/automations/AutomationsPageLayout.tsx +5 -23
- package/src/client/pages/automations/README.md +56 -46
- package/src/client/types.ts +3 -0
- package/src/mock-reporting/fixtures.ts +44 -2
- package/src/mock-reporting/watches.ts +1 -1
- package/src/client/conversations/transcriptStyles.ts +0 -10
- package/src/client/pages/automations/AutomationDetails.tsx +0 -193
- package/src/client/pages/automations/AutomationEditPage.tsx +0 -176
- package/src/client/pages/automations/AutomationVersionsPage.tsx +0 -390
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useQuery } from "@tanstack/react-query";
|
|
2
2
|
import {
|
|
3
3
|
Bot,
|
|
4
|
+
ChevronRight,
|
|
4
5
|
CircleDot,
|
|
5
6
|
Eye,
|
|
6
7
|
FolderGit2,
|
|
@@ -14,7 +15,7 @@ import {
|
|
|
14
15
|
Timer,
|
|
15
16
|
Users,
|
|
16
17
|
} from "lucide-react";
|
|
17
|
-
import type
|
|
18
|
+
import { useState, type ReactNode } from "react";
|
|
18
19
|
import {
|
|
19
20
|
conversationWatchesReportSchema,
|
|
20
21
|
type ConversationWatch,
|
|
@@ -22,7 +23,8 @@ import {
|
|
|
22
23
|
|
|
23
24
|
import { formatTime } from "../format";
|
|
24
25
|
import { fetchDashboardJson } from "../http";
|
|
25
|
-
import {
|
|
26
|
+
import { dashboardDisclosureChevronClass } from "../styles";
|
|
27
|
+
import { DetailsList, DetailsRow } from "./DetailsList";
|
|
26
28
|
|
|
27
29
|
/** Load the active Watches that one Conversation owns. */
|
|
28
30
|
export function useConversationWatches(conversationId: string) {
|
|
@@ -39,8 +41,8 @@ export function useConversationWatches(conversationId: string) {
|
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
/**
|
|
42
|
-
* Show what can wake this Conversation:
|
|
43
|
-
* the reason
|
|
44
|
+
* Show what can wake this Conversation: one line per active Watch. A line
|
|
45
|
+
* expands to show the reason and the event types that deliver to it.
|
|
44
46
|
*/
|
|
45
47
|
export function ConversationWatches(props: { watches: ConversationWatch[] }) {
|
|
46
48
|
return (
|
|
@@ -66,65 +68,81 @@ const resourceIcons: Partial<Record<string, LucideIcon>> = {
|
|
|
66
68
|
};
|
|
67
69
|
|
|
68
70
|
/**
|
|
69
|
-
* Show one Watch
|
|
70
|
-
*
|
|
71
|
+
* Show one Watch as a single line with its resource. Clicking the line shows
|
|
72
|
+
* why the Watch exists and which events wake the Conversation. The expiry is
|
|
73
|
+
* an internal limit, so the row does not show it.
|
|
71
74
|
*/
|
|
72
75
|
function WatchRow(props: { watch: ConversationWatch }) {
|
|
73
76
|
const { watch } = props;
|
|
77
|
+
const [expanded, setExpanded] = useState(false);
|
|
74
78
|
const Icon = watch.redacted
|
|
75
79
|
? LockKeyhole
|
|
76
80
|
: (resourceIcons[watch.resourceType] ?? Eye);
|
|
77
|
-
const isTimer = watch.firesAt !== undefined;
|
|
78
|
-
const until = watch.firesAt ?? watch.expiresAt;
|
|
79
81
|
const resource = `${watch.namespace} ${watch.resourceType.replaceAll("_", " ")}`;
|
|
80
|
-
// A timer has one event, and
|
|
81
|
-
const events =
|
|
82
|
+
// A timer has one event, and its fire time already says when it wakes.
|
|
83
|
+
const events = watch.firesAt ? [] : watch.events;
|
|
82
84
|
const filters = Object.entries(watch.match ?? {});
|
|
83
|
-
|
|
84
|
-
return (
|
|
85
|
+
const row = (
|
|
85
86
|
<DetailsRow
|
|
87
|
+
expanded={expanded}
|
|
86
88
|
icon={<Icon aria-hidden="true" className="size-3.5" />}
|
|
87
89
|
meta={
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
<span className="grid size-5 place-items-center">
|
|
91
|
+
<ChevronRight
|
|
92
|
+
aria-hidden="true"
|
|
93
|
+
className={dashboardDisclosureChevronClass}
|
|
94
|
+
/>
|
|
95
|
+
</span>
|
|
93
96
|
}
|
|
97
|
+
onToggle={() => setExpanded((value) => !value)}
|
|
94
98
|
title={watch.label ?? `Private ${resource}`}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
</
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
99
|
+
/>
|
|
100
|
+
);
|
|
101
|
+
if (!expanded) return row;
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<>
|
|
105
|
+
{row}
|
|
106
|
+
{/* Indent under the title: icon column, column gap, and row padding. */}
|
|
107
|
+
<div className="grid min-w-0 gap-1.5 pb-2 pl-9 pr-1.5 pt-0.5 text-xs leading-4 text-dashboard-text-muted">
|
|
108
|
+
{watch.intent ? (
|
|
109
|
+
<p className="m-0 break-words">{watch.intent}</p>
|
|
110
|
+
) : null}
|
|
111
|
+
{watch.firesAt ? (
|
|
112
|
+
<p className="m-0">
|
|
113
|
+
Fires{" "}
|
|
114
|
+
<time dateTime={watch.firesAt}>
|
|
115
|
+
{formatTime(watch.firesAt, {
|
|
116
|
+
dateStyle: "medium",
|
|
117
|
+
timeStyle: "short",
|
|
118
|
+
})}
|
|
119
|
+
</time>
|
|
120
|
+
</p>
|
|
121
|
+
) : null}
|
|
122
|
+
{events.length > 0 || filters.length > 0 ? (
|
|
123
|
+
<div className="flex flex-wrap items-center gap-1">
|
|
124
|
+
{events.map((event) => (
|
|
125
|
+
<WatchChip key={event}>
|
|
126
|
+
{watchEventLabel(event, watch.resourceType)}
|
|
127
|
+
</WatchChip>
|
|
128
|
+
))}
|
|
129
|
+
{filters.map(([key, value]) => (
|
|
130
|
+
<WatchChip filter key={`match:${key}`}>
|
|
131
|
+
{key.replaceAll("_", " ")}: {[value].flat().join(", ")}
|
|
132
|
+
</WatchChip>
|
|
133
|
+
))}
|
|
134
|
+
</div>
|
|
135
|
+
) : null}
|
|
136
|
+
{watch.childAgent ? (
|
|
137
|
+
<p className="m-0 flex min-w-0 items-center gap-1">
|
|
138
|
+
<Bot aria-hidden="true" className="size-3 shrink-0" />
|
|
139
|
+
<span className="truncate">
|
|
140
|
+
via {watch.childAgent.name ?? "subagent"}
|
|
123
141
|
</span>
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
142
|
+
</p>
|
|
143
|
+
) : null}
|
|
144
|
+
</div>
|
|
145
|
+
</>
|
|
128
146
|
);
|
|
129
147
|
}
|
|
130
148
|
|
|
@@ -153,13 +171,3 @@ function watchEventLabel(event: string, resourceType: string): string {
|
|
|
153
171
|
parts[0] === resourceType && parts.length > 1 ? parts.slice(1) : parts;
|
|
154
172
|
return rest.join(" ").replaceAll("_", " ");
|
|
155
173
|
}
|
|
156
|
-
|
|
157
|
-
/** Format the time until a Watch fires or expires as one compact unit. */
|
|
158
|
-
function formatRemaining(value: string): string {
|
|
159
|
-
const ms = Math.max(0, Date.parse(value) - Date.now());
|
|
160
|
-
const minutes = Math.round(ms / 60_000);
|
|
161
|
-
if (minutes < 60) return `${Math.max(1, minutes)}m`;
|
|
162
|
-
const hours = Math.round(minutes / 60);
|
|
163
|
-
if (hours < 48) return `${hours}h`;
|
|
164
|
-
return `${Math.round(hours / 24)}d`;
|
|
165
|
-
}
|
|
@@ -3,12 +3,45 @@ import { useState, type ReactNode } from "react";
|
|
|
3
3
|
|
|
4
4
|
import { cn, dashboardDisclosureChevronClass } from "../styles";
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Group one kind of detail in a compact card. Conversation details and event
|
|
8
|
+
* details share it, so both panels read the same way. A `label` names the
|
|
9
|
+
* card as a region.
|
|
10
|
+
*/
|
|
11
|
+
export function DetailsCard(props: {
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
count?: number;
|
|
14
|
+
label?: string;
|
|
15
|
+
title?: string;
|
|
16
|
+
}) {
|
|
17
|
+
return (
|
|
18
|
+
<section
|
|
19
|
+
aria-label={props.label}
|
|
20
|
+
className="grid min-w-0 gap-2.5 rounded-lg border border-dashboard-border-subtle bg-dashboard-surface-panel p-3"
|
|
21
|
+
>
|
|
22
|
+
{props.title ? (
|
|
23
|
+
<h3 className="m-0 flex min-w-0 items-center gap-1.5 break-words font-sans text-xs font-medium text-dashboard-text-muted">
|
|
24
|
+
{props.title}
|
|
25
|
+
{props.count ? (
|
|
26
|
+
<span className="tabular-nums text-dashboard-text-faint">
|
|
27
|
+
{props.count.toLocaleString("en-US")}
|
|
28
|
+
</span>
|
|
29
|
+
) : null}
|
|
30
|
+
</h3>
|
|
31
|
+
) : null}
|
|
32
|
+
<div className="min-w-0 break-words font-sans text-xs leading-relaxed text-dashboard-text-muted">
|
|
33
|
+
{props.children}
|
|
34
|
+
</div>
|
|
35
|
+
</section>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
6
39
|
/** Rows a details list shows before the reader asks for the rest. */
|
|
7
40
|
const COLLAPSED_ROW_COUNT = 3;
|
|
8
41
|
|
|
9
42
|
/**
|
|
10
|
-
* Show rows in a details card.
|
|
11
|
-
*
|
|
43
|
+
* Show rows in a details card. A list with more than three rows shows the
|
|
44
|
+
* first three and a row that shows the rest.
|
|
12
45
|
*/
|
|
13
46
|
export function DetailsList<T>(props: {
|
|
14
47
|
items: readonly T[];
|
|
@@ -23,26 +56,21 @@ export function DetailsList<T>(props: {
|
|
|
23
56
|
: props.items.slice(0, COLLAPSED_ROW_COUNT);
|
|
24
57
|
|
|
25
58
|
return (
|
|
26
|
-
// Rows own their padding, so hover
|
|
27
|
-
//
|
|
28
|
-
<ul className="-
|
|
59
|
+
// Rows own their padding, so a hover fill sits inside the card with an
|
|
60
|
+
// even inset. The negative margins keep row text on the card padding.
|
|
61
|
+
<ul className="-mx-1.5 -mb-1.5 -mt-1 grid list-none gap-0.5 p-0">
|
|
29
62
|
{visible.map((item) => (
|
|
30
|
-
<li
|
|
31
|
-
className="border-t border-dashboard-border-subtle first:border-t-0"
|
|
32
|
-
key={props.itemKey(item)}
|
|
33
|
-
>
|
|
34
|
-
{props.renderItem(item)}
|
|
35
|
-
</li>
|
|
63
|
+
<li key={props.itemKey(item)}>{props.renderItem(item)}</li>
|
|
36
64
|
))}
|
|
37
65
|
{hidden > 0 ? (
|
|
38
|
-
<li
|
|
66
|
+
<li>
|
|
39
67
|
<button
|
|
40
68
|
aria-expanded={expanded}
|
|
41
|
-
className="group
|
|
69
|
+
className="group flex min-h-8 w-full items-center gap-2.5 rounded-md px-1.5 py-1.5 text-left text-xs font-medium leading-4 text-dashboard-text-muted transition-colors hover:bg-dashboard-surface-hover hover:text-dashboard-text focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-dashboard-focus"
|
|
42
70
|
onClick={() => setExpanded((value) => !value)}
|
|
43
71
|
type="button"
|
|
44
72
|
>
|
|
45
|
-
<span className="grid size-
|
|
73
|
+
<span className="grid size-5 shrink-0 place-items-center">
|
|
46
74
|
<ChevronRight
|
|
47
75
|
aria-hidden="true"
|
|
48
76
|
className={dashboardDisclosureChevronClass}
|
|
@@ -59,20 +87,24 @@ export function DetailsList<T>(props: {
|
|
|
59
87
|
/**
|
|
60
88
|
* Lay out one details list row: an icon, a title, and short trailing text on
|
|
61
89
|
* the first line, then optional lines under the title. A row with `href`
|
|
62
|
-
* opens that link in a new tab.
|
|
90
|
+
* opens that link in a new tab. A row with `onToggle` is a disclosure button
|
|
91
|
+
* that shows or hides content the caller renders under it.
|
|
63
92
|
*/
|
|
64
93
|
export function DetailsRow(props: {
|
|
65
94
|
children?: ReactNode;
|
|
95
|
+
expanded?: boolean;
|
|
66
96
|
href?: string;
|
|
67
97
|
icon: ReactNode;
|
|
68
98
|
meta?: ReactNode;
|
|
99
|
+
onToggle?(): void;
|
|
69
100
|
title: ReactNode;
|
|
70
101
|
/** Native hover text with detail that the row does not show. */
|
|
71
102
|
tooltip?: string;
|
|
72
103
|
}) {
|
|
104
|
+
const interactive = props.href !== undefined || props.onToggle !== undefined;
|
|
73
105
|
const className = cn(
|
|
74
|
-
"-
|
|
75
|
-
|
|
106
|
+
"grid w-full min-w-0 grid-cols-[auto_minmax(0,1fr)_auto] items-start gap-x-2.5 gap-y-1 rounded-md px-1.5 py-1.5 text-left text-inherit no-underline",
|
|
107
|
+
interactive &&
|
|
76
108
|
"group transition-colors hover:bg-dashboard-surface-hover focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-dashboard-focus",
|
|
77
109
|
);
|
|
78
110
|
const content = (
|
|
@@ -80,7 +112,7 @@ export function DetailsRow(props: {
|
|
|
80
112
|
<span className="grid size-5 shrink-0 place-items-center text-dashboard-text-muted">
|
|
81
113
|
{props.icon}
|
|
82
114
|
</span>
|
|
83
|
-
<span className="min-w-0 truncate text-sm font-medium leading-5 text-dashboard-text
|
|
115
|
+
<span className="min-w-0 truncate text-sm font-medium leading-5 text-dashboard-text">
|
|
84
116
|
{props.title}
|
|
85
117
|
</span>
|
|
86
118
|
<span className="shrink-0 text-xs leading-5 tabular-nums text-dashboard-text-muted">
|
|
@@ -89,17 +121,33 @@ export function DetailsRow(props: {
|
|
|
89
121
|
{props.children}
|
|
90
122
|
</>
|
|
91
123
|
);
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
124
|
+
if (props.href) {
|
|
125
|
+
return (
|
|
126
|
+
<a
|
|
127
|
+
className={className}
|
|
128
|
+
href={props.href}
|
|
129
|
+
rel="noreferrer"
|
|
130
|
+
target="_blank"
|
|
131
|
+
title={props.tooltip}
|
|
132
|
+
>
|
|
133
|
+
{content}
|
|
134
|
+
</a>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
if (props.onToggle) {
|
|
138
|
+
return (
|
|
139
|
+
<button
|
|
140
|
+
aria-expanded={props.expanded ?? false}
|
|
141
|
+
className={className}
|
|
142
|
+
onClick={props.onToggle}
|
|
143
|
+
title={props.tooltip}
|
|
144
|
+
type="button"
|
|
145
|
+
>
|
|
146
|
+
{content}
|
|
147
|
+
</button>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
return (
|
|
103
151
|
<div className={className} title={props.tooltip}>
|
|
104
152
|
{content}
|
|
105
153
|
</div>
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import { dashboardDisclosureChevronClass } from "../styles";
|
|
13
13
|
|
|
14
14
|
import { RedactedMarker } from "./TranscriptRedacted";
|
|
15
|
+
import { DetailsCard } from "./DetailsList";
|
|
15
16
|
import { TranscriptText } from "./TranscriptText";
|
|
16
17
|
import { eventLogModel } from "./eventLog";
|
|
17
18
|
import { formatCostBreakdown } from "../format";
|
|
@@ -61,7 +62,9 @@ export function EventDetails({ event }: { event: ConversationReportEvent }) {
|
|
|
61
62
|
content = (
|
|
62
63
|
<>
|
|
63
64
|
{Object.keys(metadata).length > 0 ? (
|
|
64
|
-
<
|
|
65
|
+
<DetailSection>
|
|
66
|
+
<DetailValue value={metadata} />
|
|
67
|
+
</DetailSection>
|
|
65
68
|
) : null}
|
|
66
69
|
{summary ? (
|
|
67
70
|
<DetailSection title="Continuation summary">
|
|
@@ -76,7 +79,9 @@ export function EventDetails({ event }: { event: ConversationReportEvent }) {
|
|
|
76
79
|
const { type: _, text, redacted, ...metadata } = data;
|
|
77
80
|
content = (
|
|
78
81
|
<>
|
|
79
|
-
<
|
|
82
|
+
<DetailSection>
|
|
83
|
+
<DetailValue value={metadata} />
|
|
84
|
+
</DetailSection>
|
|
80
85
|
<DetailSection title="Message">
|
|
81
86
|
{redacted ? (
|
|
82
87
|
<RedactedMarker />
|
|
@@ -97,14 +102,14 @@ export function EventDetails({ event }: { event: ConversationReportEvent }) {
|
|
|
97
102
|
<DetailSection key={call.toolCallId} title={name}>
|
|
98
103
|
<DetailValue value={metadata} />
|
|
99
104
|
{input !== undefined ? (
|
|
100
|
-
<
|
|
105
|
+
<DetailSubsection title="Input">
|
|
101
106
|
<DetailValue value={input} />
|
|
102
|
-
</
|
|
107
|
+
</DetailSubsection>
|
|
103
108
|
) : null}
|
|
104
109
|
{output !== undefined ? (
|
|
105
|
-
<
|
|
110
|
+
<DetailSubsection title="Output">
|
|
106
111
|
<DetailValue value={output} />
|
|
107
|
-
</
|
|
112
|
+
</DetailSubsection>
|
|
108
113
|
) : null}
|
|
109
114
|
</DetailSection>
|
|
110
115
|
);
|
|
@@ -132,13 +137,15 @@ export function EventDetails({ event }: { event: ConversationReportEvent }) {
|
|
|
132
137
|
const { type: _, presentation, ...metadata } = data;
|
|
133
138
|
content = (
|
|
134
139
|
<>
|
|
135
|
-
<
|
|
140
|
+
<DetailSection>
|
|
141
|
+
<DetailValue value={metadata} />
|
|
142
|
+
</DetailSection>
|
|
136
143
|
<DetailSection title={presentation.title}>
|
|
137
144
|
{presentation.preview ? (
|
|
138
145
|
<TranscriptText mentions={mentions} text={presentation.preview} />
|
|
139
146
|
) : null}
|
|
140
147
|
{presentation.details?.map((detail, index) => (
|
|
141
|
-
<
|
|
148
|
+
<DetailSubsection key={index} title={detail.title}>
|
|
142
149
|
{detail.description ? (
|
|
143
150
|
<TranscriptText
|
|
144
151
|
mentions={mentions}
|
|
@@ -149,7 +156,7 @@ export function EventDetails({ event }: { event: ConversationReportEvent }) {
|
|
|
149
156
|
{detail.metadata ? (
|
|
150
157
|
<DetailValue value={detail.metadata} />
|
|
151
158
|
) : null}
|
|
152
|
-
</
|
|
159
|
+
</DetailSubsection>
|
|
153
160
|
))}
|
|
154
161
|
</DetailSection>
|
|
155
162
|
</>
|
|
@@ -158,12 +165,16 @@ export function EventDetails({ event }: { event: ConversationReportEvent }) {
|
|
|
158
165
|
}
|
|
159
166
|
default: {
|
|
160
167
|
const { type: _, ...fields } = data;
|
|
161
|
-
content =
|
|
168
|
+
content = (
|
|
169
|
+
<DetailSection>
|
|
170
|
+
<DetailValue value={fields} />
|
|
171
|
+
</DetailSection>
|
|
172
|
+
);
|
|
162
173
|
}
|
|
163
174
|
}
|
|
164
175
|
|
|
165
176
|
return (
|
|
166
|
-
<div className="@container grid min-w-0 gap-
|
|
177
|
+
<div className="@container grid min-w-0 gap-3">
|
|
167
178
|
<DetailSection
|
|
168
179
|
title={
|
|
169
180
|
data.type === "handoff" ? "Target configuration" : "Configuration"
|
|
@@ -197,7 +208,7 @@ function RawEventJson({ event }: { event: ConversationReportEvent }) {
|
|
|
197
208
|
const [open, setOpen] = useState(false);
|
|
198
209
|
const json = open ? JSON.stringify(event, null, 2) : "";
|
|
199
210
|
return (
|
|
200
|
-
<div className="relative min-w-0
|
|
211
|
+
<div className="relative min-w-0">
|
|
201
212
|
<Collapsible onOpenChange={setOpen} open={open}>
|
|
202
213
|
<CollapsibleTrigger className="group flex min-h-9 cursor-pointer items-center gap-1 pr-12 text-xs text-dashboard-text-muted hover:text-dashboard-text focus-visible:outline-2 focus-visible:outline-dashboard-focus">
|
|
203
214
|
<ChevronRight
|
|
@@ -207,7 +218,7 @@ function RawEventJson({ event }: { event: ConversationReportEvent }) {
|
|
|
207
218
|
Raw JSON
|
|
208
219
|
</CollapsibleTrigger>
|
|
209
220
|
<CollapsibleContent>
|
|
210
|
-
<div className="absolute right-0 top-
|
|
221
|
+
<div className="absolute right-0 top-0">
|
|
211
222
|
<CopyButton getText={() => json} label="Copy JSON" />
|
|
212
223
|
</div>
|
|
213
224
|
<div
|
|
@@ -224,12 +235,28 @@ function RawEventJson({ event }: { event: ConversationReportEvent }) {
|
|
|
224
235
|
);
|
|
225
236
|
}
|
|
226
237
|
|
|
227
|
-
|
|
238
|
+
// Top-level groups use the conversation details card. A titled card is a
|
|
239
|
+
// region, so readers can jump to a section such as "Message".
|
|
240
|
+
function DetailSection(props: { title?: string; children: ReactNode }) {
|
|
241
|
+
return (
|
|
242
|
+
<DetailsCard label={props.title} title={props.title}>
|
|
243
|
+
<div className="grid min-w-0 gap-3 text-sm text-dashboard-text">
|
|
244
|
+
{props.children}
|
|
245
|
+
</div>
|
|
246
|
+
</DetailsCard>
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// A group inside a card, such as a tool input. It does not nest another card.
|
|
251
|
+
function DetailSubsection(props: { title: string; children: ReactNode }) {
|
|
228
252
|
return (
|
|
229
|
-
<section
|
|
230
|
-
|
|
253
|
+
<section
|
|
254
|
+
aria-label={props.title}
|
|
255
|
+
className="grid min-w-0 gap-1.5 border-t border-dashboard-border-subtle pt-3"
|
|
256
|
+
>
|
|
257
|
+
<h4 className="m-0 font-sans text-xs font-medium text-dashboard-text-muted">
|
|
231
258
|
{props.title}
|
|
232
|
-
</
|
|
259
|
+
</h4>
|
|
233
260
|
{props.children}
|
|
234
261
|
</section>
|
|
235
262
|
);
|
|
@@ -275,8 +302,8 @@ function DetailValue({ value }: { value: unknown }) {
|
|
|
275
302
|
key={key}
|
|
276
303
|
className={
|
|
277
304
|
nested
|
|
278
|
-
? "grid min-w-0 gap-2 py-2"
|
|
279
|
-
: "grid min-w-0 grid-cols-[minmax(0,7rem)_minmax(0,1fr)] items-baseline gap-x-4 py-2 @min-[30rem]:grid-cols-[minmax(0,10rem)_minmax(0,1fr)]"
|
|
305
|
+
? "grid min-w-0 gap-2 py-2 first:pt-0 last:pb-0"
|
|
306
|
+
: "grid min-w-0 grid-cols-[minmax(0,7rem)_minmax(0,1fr)] items-baseline gap-x-4 py-2 first:pt-0 last:pb-0 @min-[30rem]:grid-cols-[minmax(0,10rem)_minmax(0,1fr)]"
|
|
280
307
|
}
|
|
281
308
|
>
|
|
282
309
|
<dt className="break-words text-xs leading-relaxed text-dashboard-text-muted">
|