@sentry/junior-dashboard 0.275.0 → 0.277.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 +194 -40
- package/dist/client.js +120 -92
- package/dist/index.d.ts +1 -1
- package/dist/index.js +189 -38
- package/dist/tailwind.css +1 -1
- package/package.json +5 -4
- package/src/api/schema.ts +20 -2
- package/src/app.ts +88 -15
- package/src/auth.ts +5 -1
- package/src/client/components/FormNotice.tsx +11 -14
- package/src/client/components/ProfileMenu.tsx +5 -6
- package/src/client/conversations/AutoArchiveToggle.tsx +35 -0
- package/src/client/conversations/ConversationArchiveNotices.tsx +1 -1
- package/src/client/conversations/ConversationChildAgents.tsx +2 -1
- package/src/client/conversations/ConversationComposer.tsx +42 -26
- package/src/client/conversations/ConversationDetails.tsx +66 -35
- package/src/client/conversations/ConversationHeader.tsx +19 -2
- package/src/client/conversations/ConversationHeaderActions.tsx +23 -0
- package/src/client/conversations/ConversationHomeList.tsx +1 -1
- package/src/client/conversations/ConversationListStatusIcon.tsx +16 -11
- package/src/client/conversations/ConversationMemories.tsx +114 -77
- package/src/client/conversations/ConversationMeta.tsx +47 -42
- package/src/client/conversations/ConversationPage.tsx +183 -60
- package/src/client/conversations/ConversationSidebar.tsx +80 -24
- package/src/client/conversations/ConversationTranscript.tsx +37 -8
- package/src/client/conversations/ConversationWatches.tsx +42 -26
- package/src/client/conversations/ConversationWorkspace.tsx +4 -4
- package/src/client/conversations/DetailsList.tsx +8 -14
- package/src/client/conversations/MemoryIcons.tsx +23 -0
- package/src/client/conversations/PendingMailboxStack.tsx +11 -1
- package/src/client/conversations/QuickQuestion.tsx +476 -0
- package/src/client/conversations/TelemetryMetrics.tsx +2 -1
- package/src/client/conversations/TranscriptActivityGroup.tsx +5 -0
- package/src/client/conversations/TranscriptEventView.tsx +25 -2
- package/src/client/conversations/TranscriptMemoryPopover.tsx +174 -0
- package/src/client/conversations/TranscriptMessageView.tsx +46 -16
- package/src/client/conversations/TranscriptRows.tsx +9 -2
- package/src/client/conversations/TranscriptTurnContextView.tsx +9 -5
- package/src/client/conversations/UsageCard.tsx +3 -3
- package/src/client/conversations/autoArchiveQueries.ts +53 -0
- package/src/client/conversations/conversationArchive.ts +255 -0
- package/src/client/conversations/conversationMemory.ts +139 -0
- package/src/client/conversations/conversationSections.ts +24 -18
- package/src/client/conversations/eventTranscript.ts +8 -0
- package/src/client/conversations/queries.ts +48 -238
- package/src/client/conversations/usePinConversation.ts +88 -0
- package/src/client/display-text/DisplayText.tsx +7 -2
- package/src/client/display-text/codeBlocks.ts +92 -0
- package/src/client/format.ts +3 -67
- package/src/client/pages/code/RepositoryTabs.tsx +2 -2
- package/src/client/pages/settings/AutoArchiveSettings.tsx +145 -0
- package/src/client/pages/settings/SettingsPage.tsx +2 -0
- package/src/client/review-desk/ConversationReviewItems.tsx +7 -9
- package/src/client/review-desk/ReviewItemActions.tsx +1 -1
- package/src/client/review-desk/ReviewItemChangeRow.tsx +85 -0
- package/src/client/review-desk/ReviewItemContext.tsx +41 -23
- package/src/client/review-desk/queries.ts +2 -1
- package/src/client/review-desk/reviewItemFormat.ts +16 -0
- package/src/client/sentry.ts +77 -0
- package/src/client/types.ts +7 -0
- package/src/client.tsx +3 -0
- package/src/conversation-cache.ts +1 -1
- package/src/mock-reporting/fixtures.ts +103 -27
- package/src/mock-reporting/routes.ts +47 -0
- package/src/mock-reporting/watches.ts +2 -0
- package/src/shell.ts +27 -2
- package/src/tailwind.css +8 -19
- package/src/client/components/ActiveIndicator.tsx +0 -14
|
@@ -28,6 +28,11 @@ import { TranscriptToolView } from "./TranscriptToolView";
|
|
|
28
28
|
import { TranscriptReasoningView } from "./TranscriptReasoningView";
|
|
29
29
|
import { TranscriptAttachmentsDeliveredView } from "./TranscriptAttachmentsDeliveredView";
|
|
30
30
|
import { TranscriptStructuredEventView } from "./TranscriptStructuredEventView";
|
|
31
|
+
import {
|
|
32
|
+
TranscriptCapturedMemories,
|
|
33
|
+
TranscriptRecalledMemories,
|
|
34
|
+
} from "./TranscriptMemoryPopover";
|
|
35
|
+
import { isMemoryCaptureEvent } from "./conversationMemory";
|
|
31
36
|
import { TranscriptFailureView } from "./TranscriptFailureView";
|
|
32
37
|
import {
|
|
33
38
|
structuredEventIcon,
|
|
@@ -248,16 +253,23 @@ const VisibleTranscriptEntries = memo(function VisibleTranscriptEntries(props: {
|
|
|
248
253
|
renderMessage={(entry) =>
|
|
249
254
|
props.conversation.sourceTask &&
|
|
250
255
|
isAutomationTriggerMessage(props.conversation, entry.message) ? (
|
|
251
|
-
<
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
256
|
+
<div className="grid min-w-0 gap-2">
|
|
257
|
+
<TranscriptAutomationTriggerView
|
|
258
|
+
message={entry.message}
|
|
259
|
+
sourceTask={props.conversation.sourceTask}
|
|
260
|
+
/>
|
|
261
|
+
<TranscriptRecalledMemories message={entry.message} />
|
|
262
|
+
</div>
|
|
255
263
|
) : entry.message.eventType ? (
|
|
256
264
|
<TranscriptRailEvent
|
|
257
265
|
kind="event"
|
|
258
266
|
objectType={entry.message.eventObjectType}
|
|
259
267
|
>
|
|
260
268
|
<TranscriptEventView message={entry.message} />
|
|
269
|
+
<TranscriptRecalledMemories
|
|
270
|
+
className="mt-1"
|
|
271
|
+
message={entry.message}
|
|
272
|
+
/>
|
|
261
273
|
</TranscriptRailEvent>
|
|
262
274
|
) : entry.message.context ? (
|
|
263
275
|
<TranscriptRailEvent kind="message_context">
|
|
@@ -265,6 +277,10 @@ const VisibleTranscriptEntries = memo(function VisibleTranscriptEntries(props: {
|
|
|
265
277
|
message={entry.message}
|
|
266
278
|
conversation={props.conversation}
|
|
267
279
|
/>
|
|
280
|
+
<TranscriptRecalledMemories
|
|
281
|
+
className="mt-2"
|
|
282
|
+
message={entry.message}
|
|
283
|
+
/>
|
|
268
284
|
</TranscriptRailEvent>
|
|
269
285
|
) : (
|
|
270
286
|
<TranscriptMessageView
|
|
@@ -285,10 +301,23 @@ const VisibleTranscriptEntries = memo(function VisibleTranscriptEntries(props: {
|
|
|
285
301
|
icon={structuredEventIcon(entry.part.presentation.icon)}
|
|
286
302
|
kind="structured_event"
|
|
287
303
|
>
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
304
|
+
{isMemoryCaptureEvent(entry.part) ? (
|
|
305
|
+
<TranscriptCapturedMemories
|
|
306
|
+
fallback={
|
|
307
|
+
<TranscriptStructuredEventView
|
|
308
|
+
part={entry.part}
|
|
309
|
+
timestamp={entry.timestamp}
|
|
310
|
+
/>
|
|
311
|
+
}
|
|
312
|
+
timestamp={entry.timestamp}
|
|
313
|
+
turnId={entry.part.turnId}
|
|
314
|
+
/>
|
|
315
|
+
) : (
|
|
316
|
+
<TranscriptStructuredEventView
|
|
317
|
+
part={entry.part}
|
|
318
|
+
timestamp={entry.timestamp}
|
|
319
|
+
/>
|
|
320
|
+
)}
|
|
292
321
|
</TranscriptRailEvent>
|
|
293
322
|
)}
|
|
294
323
|
renderSubagent={(entry) => (
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
Timer,
|
|
16
16
|
Users,
|
|
17
17
|
} from "lucide-react";
|
|
18
|
-
import {
|
|
18
|
+
import type { ReactNode } from "react";
|
|
19
19
|
import {
|
|
20
20
|
conversationWatchesReportSchema,
|
|
21
21
|
type ConversationWatch,
|
|
@@ -24,6 +24,12 @@ import {
|
|
|
24
24
|
import { DisplayText } from "../display-text/DisplayText";
|
|
25
25
|
import { formatTime } from "../format";
|
|
26
26
|
import { fetchDashboardJson } from "../http";
|
|
27
|
+
import { conversationSideReadQueryKey } from "./queries";
|
|
28
|
+
import {
|
|
29
|
+
Collapsible,
|
|
30
|
+
CollapsibleContent,
|
|
31
|
+
CollapsibleTrigger,
|
|
32
|
+
} from "../components/ui/collapsible";
|
|
27
33
|
import { dashboardDisclosureChevronClass } from "../styles";
|
|
28
34
|
import { DetailsList, DetailsRow } from "./DetailsList";
|
|
29
35
|
|
|
@@ -36,7 +42,7 @@ export function useConversationWatches(conversationId: string) {
|
|
|
36
42
|
`/api/conversations/${encodeURIComponent(conversationId)}/watches`,
|
|
37
43
|
signal,
|
|
38
44
|
),
|
|
39
|
-
queryKey:
|
|
45
|
+
queryKey: conversationSideReadQueryKey(conversationId, "watches"),
|
|
40
46
|
retry: false,
|
|
41
47
|
});
|
|
42
48
|
}
|
|
@@ -69,13 +75,13 @@ const resourceIcons: Partial<Record<string, LucideIcon>> = {
|
|
|
69
75
|
};
|
|
70
76
|
|
|
71
77
|
/**
|
|
72
|
-
* Show one Watch as a single line with its resource.
|
|
73
|
-
*
|
|
74
|
-
*
|
|
78
|
+
* Show one Watch as a single line with its resource. When the resource has a
|
|
79
|
+
* web page, the line opens it and a chevron shows the details. Otherwise the
|
|
80
|
+
* line itself shows why the Watch exists and which events wake the
|
|
81
|
+
* Conversation. The expiry is an internal limit, so the row does not show it.
|
|
75
82
|
*/
|
|
76
83
|
function WatchRow(props: { watch: ConversationWatch }) {
|
|
77
84
|
const { watch } = props;
|
|
78
|
-
const [expanded, setExpanded] = useState(false);
|
|
79
85
|
const Icon = watch.redacted
|
|
80
86
|
? LockKeyhole
|
|
81
87
|
: (resourceIcons[watch.resourceType] ?? Eye);
|
|
@@ -83,29 +89,39 @@ function WatchRow(props: { watch: ConversationWatch }) {
|
|
|
83
89
|
// A timer has one event, and its fire time already says when it wakes.
|
|
84
90
|
const events = watch.firesAt ? [] : watch.events;
|
|
85
91
|
const filters = Object.entries(watch.match ?? {});
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
92
|
+
const icon = <Icon aria-hidden="true" className="size-3.5" />;
|
|
93
|
+
const title = watch.label ?? `Private ${resource}`;
|
|
94
|
+
const chevron = (
|
|
95
|
+
<span className="grid size-5 place-items-center">
|
|
96
|
+
<ChevronRight
|
|
97
|
+
aria-hidden="true"
|
|
98
|
+
className={dashboardDisclosureChevronClass}
|
|
99
|
+
/>
|
|
100
|
+
</span>
|
|
101
|
+
);
|
|
102
|
+
const row = watch.url ? (
|
|
103
|
+
// The row opens the watched resource, like a linked work row. The
|
|
104
|
+
// chevron beside it shows the details.
|
|
105
|
+
<div className="flex min-w-0 items-start gap-0.5">
|
|
106
|
+
<div className="min-w-0 flex-1">
|
|
107
|
+
<DetailsRow href={watch.url} icon={icon} title={title} />
|
|
108
|
+
</div>
|
|
109
|
+
<CollapsibleTrigger
|
|
110
|
+
aria-label={`Details for ${title}`}
|
|
111
|
+
className="group grid size-8 shrink-0 place-items-center rounded-md 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"
|
|
112
|
+
>
|
|
113
|
+
{chevron}
|
|
114
|
+
</CollapsibleTrigger>
|
|
115
|
+
</div>
|
|
116
|
+
) : (
|
|
117
|
+
<DetailsRow disclosure icon={icon} meta={chevron} title={title} />
|
|
101
118
|
);
|
|
102
|
-
if (!expanded) return row;
|
|
103
119
|
|
|
104
120
|
return (
|
|
105
|
-
|
|
121
|
+
<Collapsible className="min-w-0">
|
|
106
122
|
{row}
|
|
107
123
|
{/* Indent under the title: icon column, column gap, and row padding. */}
|
|
108
|
-
<
|
|
124
|
+
<CollapsibleContent 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">
|
|
109
125
|
{watch.intent ? (
|
|
110
126
|
<p className="m-0 break-words">
|
|
111
127
|
<DisplayText inline text={watch.intent} />
|
|
@@ -144,8 +160,8 @@ function WatchRow(props: { watch: ConversationWatch }) {
|
|
|
144
160
|
</span>
|
|
145
161
|
</p>
|
|
146
162
|
) : null}
|
|
147
|
-
</
|
|
148
|
-
|
|
163
|
+
</CollapsibleContent>
|
|
164
|
+
</Collapsible>
|
|
149
165
|
);
|
|
150
166
|
}
|
|
151
167
|
|
|
@@ -11,14 +11,14 @@ import { pageCount, pageItems, PagePagination } from "../components/Pagination";
|
|
|
11
11
|
import { ConversationHomeList } from "./ConversationHomeList";
|
|
12
12
|
import { ConversationComposer } from "./ConversationComposer";
|
|
13
13
|
import {
|
|
14
|
-
useCreateConversation,
|
|
15
14
|
usePendingArchiveConversationUpdates,
|
|
16
15
|
type PendingArchiveConversationUpdate,
|
|
17
|
-
} from "./
|
|
16
|
+
} from "./conversationArchive";
|
|
17
|
+
import { useCreateConversation } from "./queries";
|
|
18
18
|
import { conversationPath, NEW_CONVERSATION_PATH } from "./conversationRoutes";
|
|
19
19
|
import {
|
|
20
20
|
attentionConversationIds,
|
|
21
|
-
|
|
21
|
+
pinnedAndAttentionFirst,
|
|
22
22
|
} from "./conversationSections";
|
|
23
23
|
import { buildConversations, getDashboardTimeZone } from "../format";
|
|
24
24
|
import { useDebouncedValue } from "../debouncedValue";
|
|
@@ -73,7 +73,7 @@ export function ConversationWorkspace() {
|
|
|
73
73
|
const pagedConversations = useMemo(
|
|
74
74
|
() =>
|
|
75
75
|
pageItems(
|
|
76
|
-
|
|
76
|
+
pinnedAndAttentionFirst(
|
|
77
77
|
conversations,
|
|
78
78
|
attentionConversationIds(
|
|
79
79
|
waitingConversationIds,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ChevronRight } from "lucide-react";
|
|
2
2
|
import { useState, type ReactNode } from "react";
|
|
3
3
|
|
|
4
|
+
import { CollapsibleTrigger } from "../components/ui/collapsible";
|
|
4
5
|
import { cn, dashboardDisclosureChevronClass } from "../styles";
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -87,21 +88,20 @@ export function DetailsList<T>(props: {
|
|
|
87
88
|
/**
|
|
88
89
|
* Lay out one details list row: an icon, a title, and short trailing text on
|
|
89
90
|
* the first line, then optional lines under the title. A row with `href`
|
|
90
|
-
* opens that link in a new tab. A
|
|
91
|
-
*
|
|
91
|
+
* opens that link in a new tab. A `disclosure` row is the trigger of the
|
|
92
|
+
* enclosing `Collapsible`, so it shows or hides the content under it.
|
|
92
93
|
*/
|
|
93
94
|
export function DetailsRow(props: {
|
|
94
95
|
children?: ReactNode;
|
|
95
|
-
|
|
96
|
+
disclosure?: boolean;
|
|
96
97
|
href?: string;
|
|
97
98
|
icon: ReactNode;
|
|
98
99
|
meta?: ReactNode;
|
|
99
|
-
onToggle?(): void;
|
|
100
100
|
title: ReactNode;
|
|
101
101
|
/** Native hover text with detail that the row does not show. */
|
|
102
102
|
tooltip?: string;
|
|
103
103
|
}) {
|
|
104
|
-
const interactive = props.href !== undefined || props.
|
|
104
|
+
const interactive = props.href !== undefined || props.disclosure === true;
|
|
105
105
|
const className = cn(
|
|
106
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
107
|
interactive &&
|
|
@@ -134,17 +134,11 @@ export function DetailsRow(props: {
|
|
|
134
134
|
</a>
|
|
135
135
|
);
|
|
136
136
|
}
|
|
137
|
-
if (props.
|
|
137
|
+
if (props.disclosure) {
|
|
138
138
|
return (
|
|
139
|
-
<
|
|
140
|
-
aria-expanded={props.expanded ?? false}
|
|
141
|
-
className={className}
|
|
142
|
-
onClick={props.onToggle}
|
|
143
|
-
title={props.tooltip}
|
|
144
|
-
type="button"
|
|
145
|
-
>
|
|
139
|
+
<CollapsibleTrigger className={className} title={props.tooltip}>
|
|
146
140
|
{content}
|
|
147
|
-
</
|
|
141
|
+
</CollapsibleTrigger>
|
|
148
142
|
);
|
|
149
143
|
}
|
|
150
144
|
return (
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ArrowUpRight, Lock } from "lucide-react";
|
|
2
|
+
|
|
3
|
+
/** Mark a memory that only its owner can see. */
|
|
4
|
+
export function PrivateMemoryIcon() {
|
|
5
|
+
return <Lock aria-label="Private" role="img" size={13} strokeWidth={1.8} />;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* End a memory row that links to the memory's page. Its parent link needs
|
|
10
|
+
* the `group` class, so the arrow follows the row hover.
|
|
11
|
+
*/
|
|
12
|
+
export function MemoryLinkIcons(props: { private: boolean }) {
|
|
13
|
+
return (
|
|
14
|
+
<span className="flex items-center gap-1.5 pt-1 text-dashboard-text-faint">
|
|
15
|
+
{props.private ? <PrivateMemoryIcon /> : null}
|
|
16
|
+
<ArrowUpRight
|
|
17
|
+
aria-hidden="true"
|
|
18
|
+
className="transition-colors group-hover:text-dashboard-text"
|
|
19
|
+
size={14}
|
|
20
|
+
/>
|
|
21
|
+
</span>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
} from "./TranscriptHeadingRow";
|
|
43
43
|
import { SlackMark } from "./SlackMark";
|
|
44
44
|
import { DisplayText } from "../display-text/DisplayText";
|
|
45
|
+
import { ReviewItemChangeLabel } from "../review-desk/ReviewItemChangeRow";
|
|
45
46
|
import { displayPlainText } from "../display-text/plainText";
|
|
46
47
|
|
|
47
48
|
// Rows are one line each, so the stack can show five before it collapses.
|
|
@@ -349,7 +350,16 @@ function PendingRow(props: {
|
|
|
349
350
|
className="m-0 min-w-0 truncate font-sans text-sm leading-snug text-dashboard-text-subtle"
|
|
350
351
|
title={displayPlainText(text, mentions)}
|
|
351
352
|
>
|
|
352
|
-
|
|
353
|
+
{props.message.reviewItemChange ? (
|
|
354
|
+
<ReviewItemChangeLabel
|
|
355
|
+
fallback={
|
|
356
|
+
<DisplayText inline mentions={mentions} text={text} />
|
|
357
|
+
}
|
|
358
|
+
record={props.message.reviewItemChange}
|
|
359
|
+
/>
|
|
360
|
+
) : (
|
|
361
|
+
<DisplayText inline mentions={mentions} text={text} />
|
|
362
|
+
)}
|
|
353
363
|
</p>
|
|
354
364
|
) : null}
|
|
355
365
|
</>
|