@sentry/junior-dashboard 0.279.0 → 0.281.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.
Files changed (164) hide show
  1. package/dist/app.js +105 -43
  2. package/dist/client-manifest.json +1 -0
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.js +105 -43
  5. package/dist/public/chunks/AdminPage-M5RBVZFN.js +1 -0
  6. package/dist/public/chunks/AutomationPage-WALCREDT.js +3 -0
  7. package/dist/public/chunks/AutomationRunsPage-CV47E4UX.js +1 -0
  8. package/dist/public/chunks/AutomationsPage-57L3AQVJ.js +1 -0
  9. package/dist/public/chunks/CodePage-XJUYMFJH.js +1 -0
  10. package/dist/public/chunks/ConnectionsPage-3QQAGYWF.js +1 -0
  11. package/dist/public/chunks/DrawerContent-RYYS57ZH.js +1 -0
  12. package/dist/public/chunks/LocationDetailPage-4IL5HQML.js +1 -0
  13. package/dist/public/chunks/LocationsPage-D2DUQAHJ.js +1 -0
  14. package/dist/public/chunks/McpSettingsPage-3RT7JPEK.js +1 -0
  15. package/dist/public/chunks/PeoplePage-6F5GPQ7C.js +1 -0
  16. package/dist/public/chunks/PersonProfilePage-SPAYQPTD.js +1 -0
  17. package/dist/public/chunks/PersonalTokensPage-SHAUJ74M.js +1 -0
  18. package/dist/public/chunks/PluginUserPage-64FIWD7M.js +1 -0
  19. package/dist/public/chunks/RepositoryPage-L7IHOXSN.js +1 -0
  20. package/dist/public/chunks/SettingsPage-U7WG4FHE.js +1 -0
  21. package/dist/public/chunks/SystemPage-ZBC43OJH.js +1 -0
  22. package/dist/public/chunks/WorkspaceFormPage-3NVIIZ4P.js +2 -0
  23. package/dist/public/chunks/WorkspacesPage-G73HPBDD.js +1 -0
  24. package/dist/public/chunks/chunk-2BCS5AQL.js +1 -0
  25. package/dist/public/chunks/chunk-2J3LGF5Q.js +1 -0
  26. package/dist/public/chunks/chunk-2NNKHSZE.js +1 -0
  27. package/dist/public/chunks/chunk-3Y3ICT6K.js +1 -0
  28. package/dist/public/chunks/chunk-4AKUZW6R.js +1 -0
  29. package/dist/public/chunks/chunk-4TQSTCIN.js +13 -0
  30. package/dist/public/chunks/chunk-4UGZNVJM.js +1 -0
  31. package/dist/public/chunks/chunk-564V7YHG.js +1 -0
  32. package/dist/public/chunks/chunk-5ISD3QSC.js +1 -0
  33. package/dist/public/chunks/chunk-5LNGNJ3P.js +1 -0
  34. package/dist/public/chunks/chunk-5ZA674OU.js +1 -0
  35. package/dist/public/chunks/chunk-64GPEGGE.js +1 -0
  36. package/dist/public/chunks/chunk-6FHY65EQ.js +1 -0
  37. package/dist/public/chunks/chunk-6FSJ3W2W.js +1 -0
  38. package/dist/public/chunks/chunk-6PHJZPWD.js +19 -0
  39. package/dist/public/chunks/chunk-B5ZN3SWQ.js +14 -0
  40. package/dist/public/chunks/chunk-BKOACADP.js +1 -0
  41. package/dist/public/chunks/chunk-CQY6BYUB.js +1 -0
  42. package/dist/public/chunks/chunk-CR2ICLSH.js +1 -0
  43. package/dist/public/chunks/chunk-DEEO4D4N.js +1 -0
  44. package/dist/public/chunks/chunk-DZB4LPI6.js +1 -0
  45. package/dist/public/chunks/chunk-FE522UEA.js +1 -0
  46. package/dist/public/chunks/chunk-FSGVY7HB.js +1 -0
  47. package/dist/public/chunks/chunk-FVX42XAD.js +1 -0
  48. package/dist/public/chunks/chunk-G5NWYJTV.js +1 -0
  49. package/dist/public/chunks/chunk-GMZIELFU.js +1 -0
  50. package/dist/public/chunks/chunk-GOTQ4D6W.js +1 -0
  51. package/dist/public/chunks/chunk-GYRM5ZIV.js +1 -0
  52. package/dist/public/chunks/chunk-GZBMHYYU.js +1 -0
  53. package/dist/public/chunks/chunk-H2ZU34CP.js +1 -0
  54. package/dist/public/chunks/chunk-H76B43OQ.js +1 -0
  55. package/dist/public/chunks/chunk-HCLRG2EC.js +1 -0
  56. package/dist/public/chunks/chunk-II4NXLSQ.js +2 -0
  57. package/dist/public/chunks/chunk-ILH47V7O.js +1 -0
  58. package/dist/public/chunks/chunk-IZWTFLCC.js +1 -0
  59. package/dist/public/chunks/chunk-J37MXUED.js +1 -0
  60. package/dist/public/chunks/chunk-JAZABOBA.js +0 -0
  61. package/dist/public/chunks/chunk-JPL2NRWK.js +1 -0
  62. package/dist/public/chunks/chunk-JVJ5UWIK.js +1 -0
  63. package/dist/public/chunks/chunk-K4TYMAA3.js +63 -0
  64. package/dist/public/chunks/chunk-KDUTK357.js +1 -0
  65. package/dist/public/chunks/chunk-L2H3ZWZN.js +1 -0
  66. package/dist/public/chunks/chunk-LBELRO5P.js +1 -0
  67. package/dist/public/chunks/chunk-LKW7MULF.js +1 -0
  68. package/dist/public/chunks/chunk-LZYAHJVQ.js +1 -0
  69. package/dist/public/chunks/chunk-MEHLQZDG.js +3 -0
  70. package/dist/public/chunks/chunk-MKKFXRYO.js +1 -0
  71. package/dist/public/chunks/chunk-MTBUV2GJ.js +1 -0
  72. package/dist/public/chunks/chunk-NGQRNS3C.js +1 -0
  73. package/dist/public/chunks/chunk-ONDKE72P.js +1 -0
  74. package/dist/public/chunks/chunk-PG7M7L24.js +1 -0
  75. package/dist/public/chunks/chunk-PQPAPPEI.js +1 -0
  76. package/dist/public/chunks/chunk-PXHLJIOT.js +1 -0
  77. package/dist/public/chunks/chunk-QOX5RMLM.js +1 -0
  78. package/dist/public/chunks/chunk-QPBLZSNX.js +1 -0
  79. package/dist/public/chunks/chunk-QQUFROWT.js +1 -0
  80. package/dist/public/chunks/chunk-RB5FBDEY.js +1 -0
  81. package/dist/public/chunks/chunk-RGXXD4DM.js +41 -0
  82. package/dist/public/chunks/chunk-RHMZNAJX.js +1 -0
  83. package/dist/public/chunks/chunk-SIOW7OOW.js +1 -0
  84. package/dist/public/chunks/chunk-SUX4QBVF.js +1 -0
  85. package/dist/public/chunks/chunk-T4M53QQT.js +1 -0
  86. package/dist/public/chunks/chunk-TC7TU4GK.js +1 -0
  87. package/dist/public/chunks/chunk-TFJOEF3Q.js +1 -0
  88. package/dist/public/chunks/chunk-UJD3MBMB.js +1 -0
  89. package/dist/public/chunks/chunk-UK2V4UBT.js +1 -0
  90. package/dist/public/chunks/chunk-UT6HZPGL.js +1 -0
  91. package/dist/public/chunks/chunk-UZ44J2LH.js +1 -0
  92. package/dist/public/chunks/chunk-VC6IS564.js +1 -0
  93. package/dist/public/chunks/chunk-WLIOZO3W.js +1 -0
  94. package/dist/public/chunks/chunk-WRXMQB7X.js +25 -0
  95. package/dist/public/chunks/chunk-XDUSY26N.js +55 -0
  96. package/dist/public/chunks/chunk-XNR4RZEC.js +1 -0
  97. package/dist/public/chunks/chunk-YPMUHXYT.js +147 -0
  98. package/dist/public/chunks/chunk-ZIJ6SJDN.js +1 -0
  99. package/dist/public/chunks/code-highlighter-Q7WC7AEF.js +12 -0
  100. package/dist/public/client-4OAAOHF4.js +68 -0
  101. package/dist/tailwind.css +1 -1
  102. package/package.json +5 -4
  103. package/src/api/schema.ts +1 -1
  104. package/src/assets.ts +4 -1
  105. package/src/client/App.tsx +100 -23
  106. package/src/client/TracedRoutes.tsx +8 -4
  107. package/src/client/code-highlighter.ts +26 -0
  108. package/src/client/code.tsx +2 -22
  109. package/src/client/components/BottomSheet.tsx +1 -1
  110. package/src/client/components/DetailsPanel.tsx +2 -1
  111. package/src/client/components/Drawer.tsx +12 -71
  112. package/src/client/components/DrawerContent.tsx +76 -0
  113. package/src/client/components/ProfileMenu.tsx +12 -3
  114. package/src/client/components/UserInputForm.tsx +28 -5
  115. package/src/client/conversations/ConversationBrief.tsx +129 -65
  116. package/src/client/conversations/ConversationCatchUp.tsx +107 -0
  117. package/src/client/conversations/ConversationContextTags.tsx +110 -0
  118. package/src/client/conversations/ConversationDetails.tsx +13 -14
  119. package/src/client/conversations/ConversationEventLog.tsx +135 -70
  120. package/src/client/conversations/ConversationHeader.tsx +74 -65
  121. package/src/client/conversations/ConversationHeaderActions.tsx +36 -38
  122. package/src/client/conversations/ConversationHomeList.tsx +41 -3
  123. package/src/client/conversations/ConversationLinkedWork.tsx +30 -10
  124. package/src/client/conversations/ConversationMeta.tsx +21 -27
  125. package/src/client/conversations/ConversationOverflowMenu.tsx +15 -4
  126. package/src/client/conversations/ConversationPage.tsx +219 -157
  127. package/src/client/conversations/ConversationTranscript.tsx +234 -186
  128. package/src/client/conversations/ConversationUsageBreakdown.tsx +142 -64
  129. package/src/client/conversations/DetailsList.tsx +7 -1
  130. package/src/client/conversations/PendingMailboxStack.tsx +88 -44
  131. package/src/client/conversations/ShareConversationButton.tsx +5 -50
  132. package/src/client/conversations/SlackMark.tsx +16 -4
  133. package/src/client/conversations/TranscriptActivityGroup.tsx +7 -14
  134. package/src/client/conversations/TranscriptEventView.tsx +7 -3
  135. package/src/client/conversations/TranscriptReasoningView.tsx +4 -2
  136. package/src/client/conversations/TranscriptRows.tsx +61 -16
  137. package/src/client/conversations/TranscriptView.tsx +25 -13
  138. package/src/client/conversations/conversationArchive.ts +22 -0
  139. package/src/client/conversations/conversationCatchUpState.ts +96 -0
  140. package/src/client/conversations/conversationMemory.ts +8 -1
  141. package/src/client/conversations/queries.ts +85 -46
  142. package/src/client/conversations/{transcriptUnreadHistory.ts → transcriptAroundHistory.ts} +48 -42
  143. package/src/client/conversations/transcriptBottomPinning.ts +40 -8
  144. package/src/client/conversations/transcriptListRows.ts +215 -0
  145. package/src/client/conversations/transcriptReadPosition.ts +24 -2
  146. package/src/client/conversations/turnContext.ts +1 -1
  147. package/src/client/conversations/virtualRows.ts +168 -0
  148. package/src/client/http.ts +6 -5
  149. package/src/client/pages/admin/AdminPage.tsx +1 -1
  150. package/src/client/pages/admin/ServiceAccountsSection.tsx +1 -1
  151. package/src/client/pages/memory/memoryDashboard.ts +1 -1
  152. package/src/client/pages/memory/memoryRecord.ts +1 -1
  153. package/src/client/pages/settings/ConnectionsPage.tsx +1 -1
  154. package/src/client/pages/user/PluginUserPage.tsx +0 -6
  155. package/src/client/pages/user/pluginUserPageRoutes.ts +5 -0
  156. package/src/client/primaryNav.ts +1 -1
  157. package/src/client/review-desk/reviewItemFormat.ts +1 -1
  158. package/src/client/sentry.ts +53 -3
  159. package/src/conversation-cache.ts +8 -10
  160. package/src/mock-reporting/fixtures.ts +43 -8
  161. package/src/mock-reporting/routes.ts +40 -3
  162. package/src/public-assets.ts +28 -20
  163. package/src/shell.ts +12 -2
  164. package/dist/public/client-ZCZXZBTL.js +0 -460
@@ -7,6 +7,11 @@ import type {
7
7
 
8
8
  import { ObjectIcon } from "../components/ObjectIcon";
9
9
  import { Collapsible } from "../components/ui/collapsible";
10
+ import {
11
+ Tooltip,
12
+ TooltipContent,
13
+ TooltipTrigger,
14
+ } from "../components/ui/tooltip";
10
15
  import { WatchDetails, WatchDetailsRow } from "./ConversationWatches";
11
16
  import { DetailsList, DetailsRow, DetailsRowLine } from "./DetailsList";
12
17
 
@@ -88,7 +93,7 @@ export function conversationLinks(
88
93
  * Show the outside work that a Conversation links to, one row each. A row
89
94
  * that Junior also watches shows the Watch details under a chevron, so the
90
95
  * same resource does not show twice. When one row has a chevron, the other
91
- * rows keep the same space, so their statuses stay aligned.
96
+ * rows keep the same space, so all rows keep the same width.
92
97
  */
93
98
  export function ConversationLinkedWork(props: {
94
99
  links: ConversationLink[];
@@ -133,20 +138,35 @@ function ChevronSpace(props: { children: ReactNode }) {
133
138
  function LinkRow(props: { link: ConversationLink }) {
134
139
  const { link } = props;
135
140
  const status = linkStatusLabel(link.status);
141
+ const icon = (
142
+ <ObjectIcon
143
+ decorative
144
+ facts={link.facts}
145
+ objectType={link.objectType}
146
+ size={14}
147
+ status={link.status}
148
+ />
149
+ );
136
150
  return (
137
151
  <DetailsRow
138
152
  href={link.url}
139
153
  icon={
140
- // The row text names the status, so the icon stays silent.
141
- <ObjectIcon
142
- decorative
143
- facts={link.facts}
144
- objectType={link.objectType}
145
- size={14}
146
- status={link.status}
147
- />
154
+ // The icon shows the status, so the row does not repeat it in text.
155
+ status ? (
156
+ <Tooltip>
157
+ <TooltipTrigger
158
+ render={
159
+ <span aria-label={status} className="inline-flex" role="img">
160
+ {icon}
161
+ </span>
162
+ }
163
+ />
164
+ <TooltipContent size="compact">{status}</TooltipContent>
165
+ </Tooltip>
166
+ ) : (
167
+ icon
168
+ )
148
169
  }
149
- meta={status}
150
170
  title={link.label}
151
171
  tooltip={[link.label, link.plugin, status, link.description]
152
172
  .filter(Boolean)
@@ -42,7 +42,10 @@ import {
42
42
  type SidebarAnnotation,
43
43
  type SidebarAnnotationBadgeGroup,
44
44
  } from "./sidebarAnnotationBadges";
45
- import { conversationLinks, linkStatusLabel } from "./ConversationLinkedWork";
45
+ import {
46
+ linkStatusLabel,
47
+ type ConversationLink,
48
+ } from "./ConversationLinkedWork";
46
49
 
47
50
  const MOBILE_MEDIA_QUERY = "(max-width: 767px)";
48
51
 
@@ -93,13 +96,6 @@ export function ConversationPrivacyChip(props: {
93
96
  );
94
97
  }
95
98
 
96
- /** True when the conversation has at least one resource-link annotation. */
97
- export function hasConversationAnnotations(
98
- annotations: ConversationDetailReport["annotations"] | undefined,
99
- ): boolean {
100
- return Boolean(annotations?.some((annotation) => Boolean(annotation.url)));
101
- }
102
-
103
99
  /** Render plugin annotations as a newest-first stack in a conversation row. */
104
100
  export function ConversationSidebarAnnotations(props: {
105
101
  annotations: ConversationDetailReport["sidebarAnnotations"] | undefined;
@@ -401,13 +397,11 @@ function SidebarAnnotationIcon(props: {
401
397
 
402
398
  /** Render linked work as a compact strip under the conversation title. */
403
399
  export function ConversationAnnotations(props: {
404
- detail: ConversationDetailReport | undefined;
400
+ links: readonly ConversationLink[];
405
401
  }) {
406
- const links = conversationLinks(props.detail);
407
- if (links.length === 0) return null;
408
402
  return (
409
403
  <div className="flex gap-x-4 gap-y-2 overflow-x-auto">
410
- {links.map((link) => (
404
+ {props.links.map((link) => (
411
405
  <a
412
406
  className="inline-flex min-w-0 max-w-full shrink-0 items-center gap-2 rounded-md px-1 py-0.5 font-sans text-xs leading-snug text-dashboard-text no-underline transition-colors hover:text-dashboard-accent-text focus-visible:outline focus-visible:outline-2 focus-visible:outline-dashboard-focus"
413
407
  href={link.url}
@@ -489,11 +483,14 @@ export function liveModelId(
489
483
  return openTurns.size > 0 ? modelId : undefined;
490
484
  }
491
485
 
492
- /** True when runtime stats have content to show in details. */
493
- export function hasConversationStats(props: {
486
+ type ConversationStatsProps = {
494
487
  conversation: Conversation | undefined;
495
488
  detail?: ConversationDetailReport;
496
- }): boolean {
489
+ showUsageBreakdown?: boolean;
490
+ };
491
+
492
+ /** True when runtime stats have content to show in details. */
493
+ export function hasConversationStats(props: ConversationStatsProps): boolean {
497
494
  return conversationStatItems(props).length > 0;
498
495
  }
499
496
 
@@ -506,10 +503,7 @@ type ConversationStatItem = {
506
503
  };
507
504
 
508
505
  /** Render runtime, source, token, and cost metadata as a labeled list. */
509
- export function ConversationStats(props: {
510
- conversation: Conversation | undefined;
511
- detail?: ConversationDetailReport;
512
- }) {
506
+ export function ConversationStats(props: ConversationStatsProps) {
513
507
  const stats = conversationStatItems(props);
514
508
  if (stats.length === 0) return null;
515
509
  return (
@@ -582,10 +576,9 @@ export function conversationCost(
582
576
  );
583
577
  }
584
578
 
585
- function conversationStatItems(props: {
586
- conversation: Conversation | undefined;
587
- detail?: ConversationDetailReport;
588
- }): ConversationStatItem[] {
579
+ function conversationStatItems(
580
+ props: ConversationStatsProps,
581
+ ): ConversationStatItem[] {
589
582
  if (!props.conversation) return [];
590
583
  const completeDetail = props.detail?.previousCursor
591
584
  ? undefined
@@ -602,9 +595,11 @@ function conversationStatItems(props: {
602
595
  props.detail?.childAgentTotals ?? props.conversation.childAgentTotals;
603
596
  const lastActivityAt = props.conversation.lastSeenAt;
604
597
  const location = conversationLocation(props.conversation, props.detail);
605
- const cost = conversationCost(props.conversation, props.detail);
598
+ const cost = props.showUsageBreakdown
599
+ ? null
600
+ : conversationCost(props.conversation, props.detail);
606
601
  const rawStats: Array<ConversationStatItem | undefined> = [
607
- // The desktop title bar shows the location and cost. Mobile hides that bar.
602
+ // The desktop title bar shows the location. Mobile hides that bar.
608
603
  location
609
604
  ? {
610
605
  content: location,
@@ -652,7 +647,7 @@ function conversationStatItems(props: {
652
647
  label: "Runtime",
653
648
  }
654
649
  : undefined,
655
- tokenSummary
650
+ tokenSummary && !props.showUsageBreakdown
656
651
  ? {
657
652
  content: (
658
653
  <TokenMetric
@@ -679,7 +674,6 @@ function conversationStatItems(props: {
679
674
  content: cost,
680
675
  key: "cost",
681
676
  label: "Cost",
682
- mobileOnly: true,
683
677
  }
684
678
  : undefined,
685
679
  childAgentTotals
@@ -1,5 +1,11 @@
1
1
  import { Ellipsis } from "lucide-react";
2
- import { useEffect, useRef, useState, type ReactNode, type Ref } from "react";
2
+ import {
3
+ useEffect,
4
+ useRef,
5
+ useState,
6
+ type ReactNode,
7
+ type RefObject,
8
+ } from "react";
3
9
 
4
10
  import { HeaderIconButton } from "./ConversationHeaderActions";
5
11
 
@@ -9,11 +15,13 @@ import { HeaderIconButton } from "./ConversationHeaderActions";
9
15
  * menu before it acts.
10
16
  */
11
17
  export function ConversationOverflowMenu(props: {
12
- buttonRef?: Ref<HTMLButtonElement>;
18
+ buttonRef?: RefObject<HTMLButtonElement | null>;
13
19
  children(close: () => void): ReactNode;
14
20
  }) {
15
21
  const [open, setOpen] = useState(false);
16
22
  const menuRef = useRef<HTMLDivElement>(null);
23
+ const localButtonRef = useRef<HTMLButtonElement>(null);
24
+ const buttonRef = props.buttonRef ?? localButtonRef;
17
25
 
18
26
  useEffect(() => {
19
27
  if (!open) return;
@@ -28,6 +36,9 @@ export function ConversationOverflowMenu(props: {
28
36
  if (event.key !== "Escape" || event.defaultPrevented) return;
29
37
  event.preventDefault();
30
38
  setOpen(false);
39
+ if (menuRef.current?.contains(document.activeElement)) {
40
+ buttonRef.current?.focus({ preventScroll: true });
41
+ }
31
42
  }
32
43
 
33
44
  document.addEventListener("pointerdown", closeOnOutsideClick);
@@ -36,12 +47,12 @@ export function ConversationOverflowMenu(props: {
36
47
  document.removeEventListener("pointerdown", closeOnOutsideClick);
37
48
  document.removeEventListener("keydown", closeOnEscape, true);
38
49
  };
39
- }, [open]);
50
+ }, [buttonRef, open]);
40
51
 
41
52
  return (
42
53
  <div className="relative" ref={menuRef}>
43
54
  <HeaderIconButton
44
- ref={props.buttonRef}
55
+ ref={buttonRef}
45
56
  label={open ? "Close conversation menu" : "Conversation menu"}
46
57
  onClick={() => setOpen((value) => !value)}
47
58
  pressed={open}