@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,5 +1,5 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
|
-
import { Bot, ExternalLink } from "lucide-react";
|
|
2
|
+
import { Bot, CircleAlert, ExternalLink } from "lucide-react";
|
|
3
3
|
import { Link } from "react-router";
|
|
4
4
|
|
|
5
5
|
import { useConversationData } from "./queries";
|
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
} from "../format";
|
|
12
12
|
import { buildConversationMarkdown } from "../markdownExport";
|
|
13
13
|
import { Drawer } from "../components/Drawer";
|
|
14
|
+
import { EmptyTelemetry } from "../components/EmptyTelemetry";
|
|
15
|
+
import { Alert, AlertDescription, AlertTitle } from "../components/ui/alert";
|
|
14
16
|
import { SearchInput } from "../components/SearchInput";
|
|
15
17
|
import { StatusChip } from "../components/StatusChip";
|
|
16
18
|
import { subagentStatusTone } from "./ConversationChildAgents";
|
|
@@ -22,7 +24,6 @@ import {
|
|
|
22
24
|
import { Transcript } from "./TranscriptView";
|
|
23
25
|
import { TranscriptLoading } from "./TranscriptLoading";
|
|
24
26
|
import type { TranscriptViewMode } from "./transcriptRenderModel";
|
|
25
|
-
import { transcriptEmptyClass } from "./transcriptStyles";
|
|
26
27
|
|
|
27
28
|
/** One child Conversation to show, with what its parent already knows. */
|
|
28
29
|
export interface SubagentTranscriptTarget {
|
|
@@ -108,6 +109,8 @@ function SubagentTranscriptDrawerContent(props: {
|
|
|
108
109
|
</>
|
|
109
110
|
}
|
|
110
111
|
closeLabel="Close subagent transcript"
|
|
112
|
+
// The event log owns its row insets and sticky toolbar, like the page.
|
|
113
|
+
flush={view === "raw"}
|
|
111
114
|
header={
|
|
112
115
|
<>
|
|
113
116
|
<div className="flex min-w-0 items-center gap-2">
|
|
@@ -178,9 +181,19 @@ function SubagentTranscriptDrawerContent(props: {
|
|
|
178
181
|
{query.isPending ? (
|
|
179
182
|
<TranscriptLoading />
|
|
180
183
|
) : query.error && !detail ? (
|
|
181
|
-
<
|
|
182
|
-
|
|
183
|
-
|
|
184
|
+
<Alert
|
|
185
|
+
className="gap-1 px-4 py-3 has-[>svg]:gap-x-3"
|
|
186
|
+
variant="destructive"
|
|
187
|
+
>
|
|
188
|
+
<CircleAlert aria-hidden="true" />
|
|
189
|
+
<AlertTitle className="font-display text-base font-semibold leading-tight">
|
|
190
|
+
Conversation failed to load.
|
|
191
|
+
</AlertTitle>
|
|
192
|
+
<AlertDescription className="leading-relaxed">
|
|
193
|
+
Junior could not get this child conversation. Use Open conversation
|
|
194
|
+
to view it on its own page.
|
|
195
|
+
</AlertDescription>
|
|
196
|
+
</Alert>
|
|
184
197
|
) : detail ? (
|
|
185
198
|
<Transcript
|
|
186
199
|
hasPreviousPage={query.hasPreviousPage}
|
|
@@ -194,7 +207,7 @@ function SubagentTranscriptDrawerContent(props: {
|
|
|
194
207
|
view={view}
|
|
195
208
|
/>
|
|
196
209
|
) : (
|
|
197
|
-
<
|
|
210
|
+
<EmptyTelemetry>Conversation unavailable.</EmptyTelemetry>
|
|
198
211
|
)}
|
|
199
212
|
</Drawer>
|
|
200
213
|
);
|
|
@@ -209,19 +222,3 @@ function statusLabel(
|
|
|
209
222
|
}
|
|
210
223
|
return detailStatus ?? status;
|
|
211
224
|
}
|
|
212
|
-
|
|
213
|
-
function DrawerEmptyState(props: {
|
|
214
|
-
children: string;
|
|
215
|
-
tone?: "default" | "error";
|
|
216
|
-
}) {
|
|
217
|
-
const isError = props.tone === "error";
|
|
218
|
-
return (
|
|
219
|
-
<div
|
|
220
|
-
className={transcriptEmptyClass(isError ? "error" : "default")}
|
|
221
|
-
data-tone={props.tone ?? "default"}
|
|
222
|
-
role={isError ? "alert" : undefined}
|
|
223
|
-
>
|
|
224
|
-
{props.children}
|
|
225
|
-
</div>
|
|
226
|
-
);
|
|
227
|
-
}
|
|
@@ -2,6 +2,7 @@ import { Fragment, useState, type ReactNode } from "react";
|
|
|
2
2
|
import { ChevronRight } from "lucide-react";
|
|
3
3
|
|
|
4
4
|
import { ShimmerText } from "../components/ShimmerText";
|
|
5
|
+
import { Collapsible, CollapsibleContent } from "../components/ui/collapsible";
|
|
5
6
|
import {
|
|
6
7
|
Tooltip,
|
|
7
8
|
TooltipContent,
|
|
@@ -12,7 +13,7 @@ import type { RenderedTranscriptEntry } from "./transcriptRenderModel";
|
|
|
12
13
|
import { cn } from "../styles";
|
|
13
14
|
import { useTranscriptSearch } from "./transcriptSearch";
|
|
14
15
|
import { TranscriptActivityNesting } from "./TranscriptRailEvent";
|
|
15
|
-
import {
|
|
16
|
+
import { TranscriptSummaryTrigger } from "./TranscriptSummary";
|
|
16
17
|
|
|
17
18
|
function countLabel(count: number, singular: string, plural: string): string {
|
|
18
19
|
return count === 1 ? singular : `${count} ${plural}`;
|
|
@@ -172,17 +173,17 @@ export function TranscriptActivityGroup(props: {
|
|
|
172
173
|
const open = activityGroupOpen(userOpen);
|
|
173
174
|
|
|
174
175
|
return (
|
|
175
|
-
<
|
|
176
|
-
|
|
176
|
+
<Collapsible
|
|
177
|
+
className="min-w-0 py-0.5"
|
|
178
|
+
onOpenChange={setUserOpen}
|
|
179
|
+
open={open}
|
|
180
|
+
>
|
|
181
|
+
<TranscriptSummaryTrigger
|
|
177
182
|
flush
|
|
178
183
|
className={cn(
|
|
179
|
-
"flex items-center gap-1 text-
|
|
184
|
+
"group/activity-run flex items-center gap-1 text-xs leading-tight text-dashboard-text-muted",
|
|
180
185
|
live && "text-dashboard-accent-text/80",
|
|
181
186
|
)}
|
|
182
|
-
onClick={(event) => {
|
|
183
|
-
event.preventDefault();
|
|
184
|
-
setUserOpen(!open);
|
|
185
|
-
}}
|
|
186
187
|
>
|
|
187
188
|
<Tooltip>
|
|
188
189
|
<TooltipTrigger
|
|
@@ -190,24 +191,26 @@ export function TranscriptActivityGroup(props: {
|
|
|
190
191
|
<span className="inline-flex min-w-0 max-w-full items-center gap-1" />
|
|
191
192
|
}
|
|
192
193
|
>
|
|
193
|
-
<span className="min-w-0 truncate
|
|
194
|
-
<ShimmerText active={live}>
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
<ShimmerText active={live}>Hide {label}</ShimmerText>
|
|
194
|
+
<span className="min-w-0 truncate">
|
|
195
|
+
<ShimmerText active={live}>
|
|
196
|
+
{open ? `Hide ${label}` : label}
|
|
197
|
+
</ShimmerText>
|
|
198
198
|
</span>
|
|
199
199
|
<ChevronRight
|
|
200
200
|
aria-hidden="true"
|
|
201
|
-
className="size-3 shrink-0 opacity-55 transition-transform group-
|
|
201
|
+
className="size-3 shrink-0 opacity-55 transition-transform group-aria-expanded/activity-run:rotate-90"
|
|
202
202
|
strokeWidth={2.2}
|
|
203
203
|
/>
|
|
204
204
|
</TooltipTrigger>
|
|
205
205
|
<TooltipContent>{summary}</TooltipContent>
|
|
206
206
|
</Tooltip>
|
|
207
|
-
</
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
207
|
+
</TranscriptSummaryTrigger>
|
|
208
|
+
{/* Closed rows stay in the page, so browser find can open the group. */}
|
|
209
|
+
<CollapsibleContent hiddenUntilFound>
|
|
210
|
+
<TranscriptActivityNesting.Provider value>
|
|
211
|
+
<div className="mt-1.5 grid min-w-0 gap-1">{rows}</div>
|
|
212
|
+
</TranscriptActivityNesting.Provider>
|
|
213
|
+
</CollapsibleContent>
|
|
214
|
+
</Collapsible>
|
|
212
215
|
);
|
|
213
216
|
}
|
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
2
|
INPUT_IMAGE_TYPES,
|
|
3
|
+
type InputImage,
|
|
3
4
|
type MessageAttachment,
|
|
4
5
|
} from "@sentry/junior/api/schema";
|
|
5
6
|
import { FileText } from "lucide-react";
|
|
6
7
|
import { ImageAttachment } from "../components/ImageAttachment";
|
|
7
8
|
import { HighlightText, useTranscriptSearch } from "./transcriptSearch";
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
/** Build a data URL that previews an image before the server stores it. */
|
|
11
|
+
export function inputImageSrc(image: InputImage): string {
|
|
12
|
+
return `data:${image.contentType};base64,${image.data}`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Build the private read route for one stored conversation attachment. */
|
|
16
|
+
export function conversationAttachmentUrl(
|
|
17
|
+
conversationId: string,
|
|
18
|
+
attachmentId: string,
|
|
19
|
+
): string {
|
|
10
20
|
return `/api/conversations/${encodeURIComponent(conversationId)}/attachments/${encodeURIComponent(attachmentId)}`;
|
|
11
21
|
}
|
|
12
22
|
|
|
@@ -35,13 +45,38 @@ export function TranscriptAttachments(props: {
|
|
|
35
45
|
);
|
|
36
46
|
}
|
|
37
47
|
|
|
48
|
+
/** Show the images of a send before the server stores them. */
|
|
49
|
+
export function TranscriptLocalImages(props: { images: InputImage[] }) {
|
|
50
|
+
return (
|
|
51
|
+
<div className="flex min-w-0 flex-wrap items-start gap-2">
|
|
52
|
+
{props.images.map((image, index) => (
|
|
53
|
+
<ImageAttachment
|
|
54
|
+
filename={image.filename}
|
|
55
|
+
imageClassName={TRANSCRIPT_IMAGE_CLASS}
|
|
56
|
+
key={`${image.filename}:${index}`}
|
|
57
|
+
src={inputImageSrc(image)}
|
|
58
|
+
triggerClassName={TRANSCRIPT_IMAGE_TRIGGER_CLASS}
|
|
59
|
+
/>
|
|
60
|
+
))}
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const TRANSCRIPT_IMAGE_CLASS =
|
|
66
|
+
"max-h-48 w-auto max-w-full h-auto rounded-lg object-contain";
|
|
67
|
+
const TRANSCRIPT_IMAGE_TRIGGER_CLASS =
|
|
68
|
+
"block min-w-0 max-w-full flex-none rounded-lg border border-dashboard-border bg-dashboard-fill-faint transition-colors hover:border-dashboard-border-interactive hover:bg-dashboard-fill-hover focus-visible:outline-2 focus-visible:outline-dashboard-focus";
|
|
69
|
+
|
|
38
70
|
/** Render one stored user or assistant attachment using the private read route. */
|
|
39
71
|
function TranscriptAttachment(props: {
|
|
40
72
|
attachment: MessageAttachment;
|
|
41
73
|
conversationId: string;
|
|
42
74
|
}) {
|
|
43
75
|
const search = useTranscriptSearch();
|
|
44
|
-
const href =
|
|
76
|
+
const href = conversationAttachmentUrl(
|
|
77
|
+
props.conversationId,
|
|
78
|
+
props.attachment.id,
|
|
79
|
+
);
|
|
45
80
|
const size = formatAttachmentBytes(props.attachment.bytes);
|
|
46
81
|
const inline = INPUT_IMAGE_TYPES.some(
|
|
47
82
|
(type) => type === props.attachment.contentType,
|
|
@@ -53,10 +88,10 @@ function TranscriptAttachment(props: {
|
|
|
53
88
|
<ImageAttachment
|
|
54
89
|
context={meta}
|
|
55
90
|
filename={props.attachment.filename}
|
|
56
|
-
imageClassName=
|
|
91
|
+
imageClassName={TRANSCRIPT_IMAGE_CLASS}
|
|
57
92
|
loading="lazy"
|
|
58
93
|
src={href}
|
|
59
|
-
triggerClassName=
|
|
94
|
+
triggerClassName={TRANSCRIPT_IMAGE_TRIGGER_CLASS}
|
|
60
95
|
/>
|
|
61
96
|
);
|
|
62
97
|
}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { ArrowRight, ChevronRight } from "lucide-react";
|
|
2
|
-
import {
|
|
2
|
+
import { useState } from "react";
|
|
3
3
|
import type { ConversationDetailReport } from "@sentry/junior/api/schema";
|
|
4
4
|
|
|
5
5
|
import { buttonVariants } from "../components/ui/button";
|
|
6
|
+
import {
|
|
7
|
+
Collapsible,
|
|
8
|
+
CollapsibleContent,
|
|
9
|
+
CollapsibleTrigger,
|
|
10
|
+
} from "../components/ui/collapsible";
|
|
6
11
|
import { Link } from "react-router";
|
|
7
12
|
import { ObjectIcon } from "../components/ObjectIcon";
|
|
8
13
|
import { automationPath, formatRelativeTime } from "../format";
|
|
@@ -49,7 +54,6 @@ export function TranscriptAutomationTriggerView(props: {
|
|
|
49
54
|
(part) => part.type === "text" && part.redacted,
|
|
50
55
|
);
|
|
51
56
|
const [open, setOpen] = useState(false);
|
|
52
|
-
const promptId = useId();
|
|
53
57
|
const automationId = props.sourceTask.id?.trim();
|
|
54
58
|
const name = props.sourceTask.title?.trim() || "Automation";
|
|
55
59
|
const details = [
|
|
@@ -86,30 +90,21 @@ export function TranscriptAutomationTriggerView(props: {
|
|
|
86
90
|
</p>
|
|
87
91
|
) : null}
|
|
88
92
|
{text ? (
|
|
89
|
-
<
|
|
90
|
-
<
|
|
91
|
-
aria-controls={promptId}
|
|
92
|
-
aria-expanded={open}
|
|
93
|
-
className="-mx-1 inline-flex cursor-pointer items-center gap-1 rounded-sm border-0 bg-transparent px-1 py-0.5 font-sans text-xs font-medium text-dashboard-text-muted transition-colors hover:text-dashboard-text focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-dashboard-focus"
|
|
94
|
-
onClick={() => setOpen((value) => !value)}
|
|
95
|
-
type="button"
|
|
96
|
-
>
|
|
93
|
+
<Collapsible className="min-w-0" onOpenChange={setOpen} open={open}>
|
|
94
|
+
<CollapsibleTrigger className="group -mx-1 inline-flex cursor-pointer items-center gap-1 rounded-sm border-0 bg-transparent px-1 py-0.5 font-sans text-xs font-medium text-dashboard-text-muted transition-colors hover:text-dashboard-text focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-dashboard-focus">
|
|
97
95
|
<ChevronRight
|
|
98
96
|
aria-hidden="true"
|
|
99
|
-
className=
|
|
97
|
+
className="size-3 transition-transform group-aria-expanded:rotate-90 motion-reduce:transition-none"
|
|
100
98
|
strokeWidth={2.2}
|
|
101
99
|
/>
|
|
102
100
|
{open ? "Hide prompt" : "Show prompt"}
|
|
103
|
-
</
|
|
104
|
-
|
|
105
|
-
<pre
|
|
106
|
-
className="mt-2 max-h-80 overflow-auto whitespace-pre-wrap break-words rounded-lg border border-dashboard-border-subtle bg-dashboard-bg px-3 py-2 font-mono text-xs leading-relaxed text-dashboard-text-muted"
|
|
107
|
-
id={promptId}
|
|
108
|
-
>
|
|
101
|
+
</CollapsibleTrigger>
|
|
102
|
+
<CollapsibleContent>
|
|
103
|
+
<pre className="mt-2 max-h-80 overflow-auto whitespace-pre-wrap break-words rounded-lg border border-dashboard-border-subtle bg-dashboard-bg px-3 py-2 font-mono text-xs leading-relaxed text-dashboard-text-muted">
|
|
109
104
|
<HighlightText text={text} />
|
|
110
105
|
</pre>
|
|
111
|
-
|
|
112
|
-
</
|
|
106
|
+
</CollapsibleContent>
|
|
107
|
+
</Collapsible>
|
|
113
108
|
) : redacted ? (
|
|
114
109
|
<RedactedMarker />
|
|
115
110
|
) : null}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { ChevronRight } from "lucide-react";
|
|
2
|
+
import { useState } from "react";
|
|
2
3
|
|
|
4
|
+
import { Collapsible, CollapsibleContent } from "../components/ui/collapsible";
|
|
5
|
+
import { cn, dashboardDisclosureChevronClass } from "../styles";
|
|
3
6
|
import { MentionText } from "./transcriptMentions";
|
|
4
7
|
import { messageRawText } from "./transcriptRenderModel";
|
|
5
|
-
import { HighlightText } from "./transcriptSearch";
|
|
8
|
+
import { HighlightText, useTranscriptSearch } from "./transcriptSearch";
|
|
6
9
|
import { RedactedMarker } from "./TranscriptRedacted";
|
|
7
10
|
import type { TranscriptViewMessage } from "../types";
|
|
8
|
-
import {
|
|
11
|
+
import { TranscriptSummaryTrigger } from "./TranscriptSummary";
|
|
9
12
|
|
|
10
13
|
function EventTypeChip(props: { eventType: string }) {
|
|
11
14
|
return (
|
|
@@ -25,6 +28,8 @@ function batchSummary(events: readonly { label?: string }[]): string {
|
|
|
25
28
|
|
|
26
29
|
/** Render an Event Message whose heading expands its full text. */
|
|
27
30
|
export function TranscriptEventView(props: { message: TranscriptViewMessage }) {
|
|
31
|
+
const { active: searchActive } = useTranscriptSearch();
|
|
32
|
+
const [open, setOpen] = useState(false);
|
|
28
33
|
const text = messageRawText(props.message);
|
|
29
34
|
const redacted = props.message.parts.some(
|
|
30
35
|
(part) => part.type === "text" && part.redacted,
|
|
@@ -35,33 +40,38 @@ export function TranscriptEventView(props: { message: TranscriptViewMessage }) {
|
|
|
35
40
|
const summary = isBatch
|
|
36
41
|
? batchSummary(events)
|
|
37
42
|
: (props.message.trustedSummary ?? props.message.eventType ?? "");
|
|
43
|
+
// With text, the heading sits in the disclosure button, which cannot hold
|
|
44
|
+
// links.
|
|
45
|
+
const links = !text;
|
|
38
46
|
const heading = (
|
|
39
47
|
<span className="flex min-w-0 flex-col gap-1">
|
|
40
48
|
<span className="flex min-h-6 min-w-0 flex-wrap items-center gap-x-2 gap-y-1">
|
|
41
49
|
<span className="min-w-0 break-words font-display text-sm font-semibold leading-6 text-dashboard-text">
|
|
42
|
-
<MentionText mentions={mentions} text={summary} />
|
|
50
|
+
<MentionText links={links} mentions={mentions} text={summary} />
|
|
43
51
|
</span>
|
|
44
52
|
{!isBatch && props.message.eventType ? (
|
|
45
53
|
<EventTypeChip eventType={props.message.eventType} />
|
|
46
54
|
) : null}
|
|
47
55
|
</span>
|
|
48
56
|
{isBatch ? (
|
|
49
|
-
<
|
|
57
|
+
<span className="flex min-w-0 flex-col gap-1" role="list">
|
|
50
58
|
{events.map((event, index) => (
|
|
51
|
-
<
|
|
59
|
+
<span
|
|
52
60
|
key={index}
|
|
61
|
+
role="listitem"
|
|
53
62
|
className="flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1 text-xs leading-5 text-dashboard-text-muted"
|
|
54
63
|
>
|
|
55
64
|
<span className="min-w-0 break-words">
|
|
56
65
|
<MentionText
|
|
66
|
+
links={links}
|
|
57
67
|
mentions={mentions}
|
|
58
68
|
text={event.trustedSummary ?? event.eventType}
|
|
59
69
|
/>
|
|
60
70
|
</span>
|
|
61
71
|
<EventTypeChip eventType={event.eventType} />
|
|
62
|
-
</
|
|
72
|
+
</span>
|
|
63
73
|
))}
|
|
64
|
-
</
|
|
74
|
+
</span>
|
|
65
75
|
) : null}
|
|
66
76
|
</span>
|
|
67
77
|
);
|
|
@@ -69,22 +79,31 @@ export function TranscriptEventView(props: { message: TranscriptViewMessage }) {
|
|
|
69
79
|
return (
|
|
70
80
|
<div className="min-w-0 py-1">
|
|
71
81
|
{text ? (
|
|
72
|
-
<
|
|
73
|
-
|
|
82
|
+
<Collapsible
|
|
83
|
+
className="min-w-0"
|
|
84
|
+
// Search holds the text open, so the heading button is off until
|
|
85
|
+
// search ends.
|
|
86
|
+
disabled={searchActive}
|
|
87
|
+
onOpenChange={setOpen}
|
|
88
|
+
open={searchActive || open}
|
|
89
|
+
>
|
|
90
|
+
<TranscriptSummaryTrigger
|
|
74
91
|
flush
|
|
75
|
-
className="flex items-start gap-2 text-dashboard-text-muted"
|
|
92
|
+
className="group flex items-start gap-2 text-dashboard-text-muted"
|
|
76
93
|
>
|
|
77
94
|
{heading}
|
|
78
95
|
<ChevronRight
|
|
79
96
|
aria-hidden="true"
|
|
80
|
-
className="mt-1.5
|
|
97
|
+
className={cn(dashboardDisclosureChevronClass, "mt-1.5")}
|
|
81
98
|
strokeWidth={2.2}
|
|
82
99
|
/>
|
|
83
|
-
</
|
|
84
|
-
<
|
|
85
|
-
<
|
|
86
|
-
|
|
87
|
-
|
|
100
|
+
</TranscriptSummaryTrigger>
|
|
101
|
+
<CollapsibleContent hiddenUntilFound>
|
|
102
|
+
<pre className="mt-2 max-h-80 overflow-auto whitespace-pre-wrap break-words rounded-lg border border-dashboard-border bg-dashboard-surface-panel px-3 py-2 font-sans text-xs leading-relaxed text-dashboard-text-muted">
|
|
103
|
+
<HighlightText text={text} />
|
|
104
|
+
</pre>
|
|
105
|
+
</CollapsibleContent>
|
|
106
|
+
</Collapsible>
|
|
88
107
|
) : (
|
|
89
108
|
<>
|
|
90
109
|
{heading}
|
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
ConversationTurnFailureReason,
|
|
5
5
|
} from "@sentry/junior/api/schema";
|
|
6
6
|
|
|
7
|
+
import { Alert, AlertDescription, AlertTitle } from "../components/ui/alert";
|
|
7
8
|
import { formatMessageTimestamp } from "../format";
|
|
8
9
|
import {
|
|
9
10
|
transcriptFailureDescription,
|
|
@@ -35,25 +36,21 @@ export function TranscriptFailureView(props: {
|
|
|
35
36
|
) : null;
|
|
36
37
|
|
|
37
38
|
return (
|
|
38
|
-
<
|
|
39
|
-
className="
|
|
39
|
+
<Alert
|
|
40
|
+
className="min-w-0 gap-3 rounded-lg border-0 bg-rose-300/[0.1] px-4 py-3 text-rose-100 *:[svg]:row-span-1 has-[>svg]:grid-cols-[auto_minmax(0,1fr)_auto] has-[>svg]:gap-x-3 max-md:has-[>svg]:grid-cols-[auto_minmax(0,1fr)] *:[svg]:text-rose-300"
|
|
40
41
|
data-transcript-failure={props.failureCode}
|
|
41
42
|
data-transcript-failure-event-id={props.eventId}
|
|
42
43
|
data-transcript-failure-reason={props.failureReason}
|
|
43
|
-
|
|
44
|
+
variant="destructive"
|
|
44
45
|
>
|
|
45
|
-
<CircleAlert
|
|
46
|
-
aria-hidden="true"
|
|
47
|
-
className="mt-0.5 text-rose-300"
|
|
48
|
-
size={16}
|
|
49
|
-
/>
|
|
46
|
+
<CircleAlert aria-hidden="true" size={16} />
|
|
50
47
|
<div className="min-w-0">
|
|
51
|
-
<
|
|
48
|
+
<AlertTitle className="font-display text-base font-semibold leading-tight">
|
|
52
49
|
{transcriptFailureTitle(props.failureCode, props.failureReason)}
|
|
53
|
-
</
|
|
54
|
-
<
|
|
50
|
+
</AlertTitle>
|
|
51
|
+
<AlertDescription className="mt-1 leading-relaxed text-rose-100/70">
|
|
55
52
|
{transcriptFailureDescription(props.failureCode, props.failureReason)}
|
|
56
|
-
</
|
|
53
|
+
</AlertDescription>
|
|
57
54
|
{eventReference ? (
|
|
58
55
|
<div className="mt-2 text-xs leading-relaxed text-rose-100/65">
|
|
59
56
|
Reference: {eventReference}
|
|
@@ -65,6 +62,6 @@ export function TranscriptFailureView(props: {
|
|
|
65
62
|
{timestamp}
|
|
66
63
|
</span>
|
|
67
64
|
) : null}
|
|
68
|
-
</
|
|
65
|
+
</Alert>
|
|
69
66
|
);
|
|
70
67
|
}
|