@agent-native/core-corpus 0.216.0 → 0.218.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/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +61 -1
- package/corpus/templates/analytics/AGENTS.md +1 -1
- package/corpus/templates/analytics/CHANGELOG.md +3 -0
- package/corpus/templates/analytics/actions/get-session-replay-summary.ts +9 -65
- package/corpus/templates/analytics/actions/list-event-catalog.ts +1 -1
- package/corpus/templates/analytics/actions/list-session-outputs.ts +40 -0
- package/corpus/templates/analytics/actions/list-session-recordings.ts +17 -4
- package/corpus/templates/analytics/actions/view-screen.ts +29 -3
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +38 -167
- package/corpus/templates/analytics/app/i18n/en-US.ts +27 -0
- package/corpus/templates/analytics/app/pages/sessions/EventCatalogPage.tsx +18 -1
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +3 -1
- package/corpus/templates/analytics/app/pages/sessions/SessionOutputs.tsx +197 -0
- package/corpus/templates/analytics/app/pages/sessions/SessionsTriagePage.tsx +114 -4
- package/corpus/templates/analytics/changelog/2026-10-15-sessions-can-find-people-who-made-a-slides-deck-but-didn-t-p.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-16-owned-and-shared-chats-appear-in-separate-history-sections.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-16-the-activation-funnel-counts-visitors-who-decline-analytics-.md +6 -0
- package/corpus/templates/analytics/server/db/schema.ts +67 -0
- package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +9 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +28 -22
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +36 -1
- package/corpus/templates/analytics/server/lib/output-outcomes.ts +712 -0
- package/corpus/templates/analytics/server/lib/replay-origins.ts +33 -0
- package/corpus/templates/analytics/server/lib/session-event-index.ts +20 -0
- package/corpus/templates/analytics/server/lib/session-performance.ts +6 -40
- package/corpus/templates/analytics/server/lib/session-recording-associations.ts +30 -1
- package/corpus/templates/analytics/server/lib/session-replay-triage.ts +99 -0
- package/corpus/templates/analytics/server/lib/session-replay.ts +45 -31
- package/corpus/templates/analytics/server/lib/sessions-triage-lab.ts +8 -2
- package/corpus/templates/analytics/server/plugins/db.ts +46 -0
- package/corpus/templates/analytics/shared/output-use.ts +205 -0
- package/corpus/templates/analytics/shared/session-events.ts +6 -0
- package/corpus/templates/assets/CHANGELOG.md +6 -0
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +51 -117
- package/corpus/templates/assets/changelog/2026-10-16-owned-and-shared-chats-appear-in-separate-history-sections.md +6 -0
- package/corpus/templates/brain/app/components/layout/Sidebar.tsx +34 -101
- package/corpus/templates/brain/app/routes/sources.tsx +1 -1
- package/corpus/templates/brain/vitest.config.ts +7 -0
- package/corpus/templates/calendar/CHANGELOG.md +12 -0
- package/corpus/templates/calendar/actions/create-event.ts +2 -4
- package/corpus/templates/calendar/actions/update-event.ts +35 -6
- package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +1 -1
- package/corpus/templates/calendar/changelog/2026-10-16-booking-links-show-localized-visibility-badges.md +6 -0
- package/corpus/templates/calendar/changelog/2026-10-21-solo-events-avoid-notification-approval.md +6 -0
- package/corpus/templates/chat/app/components/layout/Sidebar.tsx +62 -101
- package/corpus/templates/clips/CHANGELOG.md +7 -20
- package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +20 -77
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +63 -90
- package/corpus/templates/clips/app/components/sharing/share-test-support.tsx +180 -0
- package/corpus/templates/clips/app/components/sharing/share-ui.tsx +5 -584
- package/corpus/templates/clips/changelog/2026-10-16-share-dialogs-make-it-easier-to-see-who-has-access-and-manag.md +6 -0
- package/corpus/templates/clips/changelog/2026-10-21-share-panels-describe-general-access-in-a-sentence.md +6 -0
- package/corpus/templates/community/qr/package.json +1 -1
- package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +6 -3
- package/corpus/templates/content/CHANGELOG.md +10 -0
- package/corpus/templates/content/actions/_browser-document-save-attempt.ts +23 -1
- package/corpus/templates/content/actions/_builder-cms-blob-custody.ts +467 -0
- package/corpus/templates/content/actions/_builder-cms-execution-lease.ts +17 -0
- package/corpus/templates/content/actions/_builder-cms-intent-lookup.ts +5 -0
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +881 -21
- package/corpus/templates/content/actions/_builder-cms-write-adapter.ts +28 -2
- package/corpus/templates/content/actions/_builder-cms-write-client.ts +109 -11
- package/corpus/templates/content/actions/_builder-docs-client.ts +1 -0
- package/corpus/templates/content/actions/_builder-private-blob.test-fixture.ts +90 -0
- package/corpus/templates/content/actions/_builder-source-execution-guard.ts +48 -0
- package/corpus/templates/content/actions/_content-save-outcomes.ts +5 -0
- package/corpus/templates/content/actions/_database-source-utils.ts +290 -8
- package/corpus/templates/content/actions/_database-utils.ts +93 -7
- package/corpus/templates/content/actions/_database-view-setup.ts +21 -2
- package/corpus/templates/content/actions/_delete-content-space.ts +8 -1
- package/corpus/templates/content/actions/_github-source-freshness.ts +30 -4
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +23 -6
- package/corpus/templates/content/actions/cancel-prepared-builder-source-update.ts +110 -26
- package/corpus/templates/content/actions/change-content-database-source-role.ts +51 -7
- package/corpus/templates/content/actions/delete-document.ts +41 -3
- package/corpus/templates/content/actions/disconnect-content-database-source.ts +68 -2
- package/corpus/templates/content/actions/disconnect-local-folder-source.ts +33 -2
- package/corpus/templates/content/actions/execute-builder-source-execution.ts +900 -140
- package/corpus/templates/content/actions/get-document.ts +2 -0
- package/corpus/templates/content/actions/permanently-delete-document.ts +6 -0
- package/corpus/templates/content/actions/prepare-builder-source-execution.ts +155 -13
- package/corpus/templates/content/actions/prepare-builder-source-review.ts +299 -73
- package/corpus/templates/content/actions/set-live-body-switch.ts +45 -0
- package/corpus/templates/content/actions/update-document.ts +139 -20
- package/corpus/templates/content/actions/validate-builder-source-execution.ts +135 -26
- package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +119 -30
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +56 -13
- package/corpus/templates/content/app/components/editor/SuggestionText.tsx +18 -3
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +89 -22
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +23 -0
- package/corpus/templates/content/app/components/editor/database/GitHubSourceStatusLine.tsx +27 -2
- package/corpus/templates/content/app/components/editor/database/ListItemLayout.tsx +32 -8
- package/corpus/templates/content/app/components/editor/database/ListItemRow.tsx +27 -2
- package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +1 -0
- package/corpus/templates/content/app/components/editor/extensions/SuggestionHighlight.ts +383 -34
- package/corpus/templates/content/app/components/editor/suggestions/draft-session.ts +31 -0
- package/corpus/templates/content/app/components/editor/suggestions/presentation-rebase.ts +82 -4
- package/corpus/templates/content/app/global.css +31 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +40 -2
- package/corpus/templates/content/app/hooks/use-documents.ts +14 -0
- package/corpus/templates/content/app/i18n-data.ts +1 -0
- package/corpus/templates/content/changelog/2026-10-16-accepting-a-suggestion-on-a-page-that-changed-since-it-was-s.md +6 -0
- package/corpus/templates/content/changelog/2026-10-17-builder-content-avoids-retrying-a-write-when-builder-accepte.md +6 -0
- package/corpus/templates/content/changelog/2026-10-18-link-a-new-collection-to-a-github-folder-from-its-sources.md +1 -1
- package/corpus/templates/content/changelog/2026-10-20-builder-content-sync-keeps-read-and-write-status-accurate-wh.md +6 -0
- package/corpus/templates/content/changelog/2026-10-20-suggested-edits-that-add-remove-split-or-merge-paragraphs-li.md +6 -0
- package/corpus/templates/content/changelog/2026-10-21-list-rows-can-show-each-pages-first-lines.md +6 -0
- package/corpus/templates/content/changelog/2026-10-22-a-collection-linked-to-a-big-github-folder-fills-faster-and-p.md +6 -0
- package/corpus/templates/content/docs/product/capabilities/content.source.adapters.md +29 -0
- package/corpus/templates/content/parity/matrix.md +42 -42
- package/corpus/templates/content/parity/matrix.ts +3 -1
- package/corpus/templates/content/server/db/schema.ts +20 -0
- package/corpus/templates/content/server/lib/content-trash-purge.ts +15 -1
- package/corpus/templates/content/server/lib/live-body-writer.ts +138 -26
- package/corpus/templates/content/server/live-copy/binding.ts +31 -0
- package/corpus/templates/content/server/live-copy/bounded-task.d.ts +6 -0
- package/corpus/templates/content/server/live-copy/exec-db.ts +1 -0
- package/corpus/templates/content/server/live-copy/holds.ts +59 -0
- package/corpus/templates/content/server/live-copy/persist.ts +656 -0
- package/corpus/templates/content/server/live-copy/switch.ts +136 -0
- package/corpus/templates/content/server/live-copy/task-names.ts +4 -0
- package/corpus/templates/content/server/live-copy/tasks.ts +183 -0
- package/corpus/templates/content/server/live-copy/write-cause.ts +85 -0
- package/corpus/templates/content/server/live-copy/write.ts +85 -0
- package/corpus/templates/content/server/plugins/builder-private-payload-cleanup.ts +22 -0
- package/corpus/templates/content/server/plugins/collab.ts +3 -0
- package/corpus/templates/content/server/plugins/db.ts +28 -0
- package/corpus/templates/content/shared/api.ts +30 -1
- package/corpus/templates/content/shared/database-item-layout.ts +54 -22
- package/corpus/templates/content/shared/document-intent-merge.ts +16 -9
- package/corpus/templates/content/shared/og-description.ts +258 -36
- package/corpus/templates/content/shared/suggestion-diff.ts +23 -6
- package/corpus/templates/content/shared/suggestion-formatting.ts +44 -14
- package/corpus/templates/content/shared/suggestion-text.ts +20 -5
- package/corpus/templates/design/.agents/skills/design-templates/SKILL.md +5 -1
- package/corpus/templates/design/.generated/bridge/shader-runtime.generated.ts +25 -4
- package/corpus/templates/design/CHANGELOG.md +5 -0
- package/corpus/templates/design/actions/get-getting-started.ts +53 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +10 -0
- package/corpus/templates/design/app/components/design/bridge/native-shader-runtime.bridge.ts +132 -79
- package/corpus/templates/design/app/components/design/bridge/native-source-provider.ts +268 -130
- package/corpus/templates/design/app/components/design/bridge/native-worker-scene-host.ts +122 -42
- package/corpus/templates/design/app/components/design/bridge/shader-runtime.bridge.ts +41 -4
- package/corpus/templates/design/app/components/design/design-canvas/text-content-change-result.ts +46 -12
- package/corpus/templates/design/app/components/home/DesignHomeLibrary.tsx +15 -8
- package/corpus/templates/design/app/components/layout/GettingStarted.tsx +50 -0
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +3 -0
- package/corpus/templates/design/app/components/templates/DesignTemplateGrid.tsx +163 -0
- package/corpus/templates/design/app/components/templates/DesignTemplateLibrary.tsx +65 -78
- package/corpus/templates/design/app/components/templates/TemplatePreview.tsx +6 -2
- package/corpus/templates/design/app/global.css +6 -0
- package/corpus/templates/design/app/i18n/en-US.ts +17 -0
- package/corpus/templates/design/app/lib/canvas-load-outcome.ts +147 -0
- package/corpus/templates/design/app/lib/canvas-outcome-tracking.ts +531 -0
- package/corpus/templates/design/app/lib/canvas-style-kind.ts +50 -0
- package/corpus/templates/design/app/pages/DesignSystems.tsx +1 -1
- package/corpus/templates/design/app/pages/Index.tsx +28 -67
- package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +86 -29
- package/corpus/templates/design/app/pages/design-editor/commands/save-file-content.ts +38 -3
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-core.ts +9 -0
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-files-and-saving.ts +2 -0
- package/corpus/templates/design/changelog/2026-10-16-design-pages-use-localized-visibility-badges-and-a-shared-ow.md +6 -0
- package/corpus/templates/design/changelog/2026-10-21-a-getting-started-checklist-at-the-bottom-of-the-sidebar-tra.md +6 -0
- package/corpus/templates/design/changelog/2026-10-21-templates-now-open-a-read-only-preview-from-the-card-and-the.md +6 -0
- package/corpus/templates/design/changelog/2026-10-22-collapsed-shader-layers-no-longer-interrupt-other-shaders-on.md +6 -0
- package/corpus/templates/design/changelog/2026-10-22-shader-fills-keep-rendering-when-other-screen-content-cannot.md +6 -0
- package/corpus/templates/design/scripts/design-export-validation/export-baseline.json +24 -0
- package/corpus/templates/design/server/lib/getting-started.ts +267 -0
- package/corpus/templates/design/server/plugins/getting-started.ts +5 -0
- package/corpus/templates/design/shared/design-template-presets/analytics-dashboard.ts +127 -0
- package/corpus/templates/design/shared/design-template-presets/design-studio.ts +98 -0
- package/corpus/templates/design/shared/design-template-presets/messaging-app.ts +101 -0
- package/corpus/templates/design/shared/design-template-presets/project-tasks.ts +120 -0
- package/corpus/templates/design/shared/design-template-presets.ts +8 -0
- package/corpus/templates/dispatch/CHANGELOG.md +4 -0
- package/corpus/templates/dispatch/app/i18n-data.ts +75 -0
- package/corpus/templates/dispatch/changelog/2026-10-21-owned-and-shared-chats-appear-in-separate-history-sections.md +6 -0
- package/corpus/templates/factory/app/components/layout/Sidebar.tsx +34 -100
- package/corpus/templates/forms/app/pages/FormsListPage.tsx +1 -1
- package/corpus/templates/forms/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/plan/CHANGELOG.md +6 -0
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +34 -109
- package/corpus/templates/plan/changelog/2026-10-16-owned-and-shared-chats-appear-in-separate-history-sections.md +6 -0
- package/corpus/templates/slides/CHANGELOG.md +7 -0
- package/corpus/templates/slides/actions/delete-deck.ts +7 -0
- package/corpus/templates/slides/app/components/deck/DeckCard.tsx +1 -1
- package/corpus/templates/slides/app/components/design-system/DesignSystemCard.tsx +1 -1
- package/corpus/templates/slides/app/pages/Index.tsx +7 -2
- package/corpus/templates/slides/changelog/2026-10-16-deck-lists-use-the-shared-ownership-filter-and-visibility-ba.md +6 -0
- package/corpus/templates/slides/changelog/2026-10-21-connected-deck-deletion-requires-approval.md +6 -0
- package/corpus/templates/slides/scripts/edit-fidelity/client-action.ts +61 -0
- package/corpus/templates/slides/scripts/edit-fidelity/run.ts +10 -0
- package/package.json +1 -1
- package/corpus/templates/chat/app/lib/sidebar-thread-state.ts +0 -29
- package/corpus/templates/slides/app/components/deck/DeckFilterMenu.tsx +0 -83
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { appPath } from "@agent-native/core/client/api-path";
|
|
1
2
|
import {
|
|
2
3
|
AppSidebarFooter,
|
|
3
4
|
AppSidebarHeader,
|
|
@@ -96,7 +97,6 @@ function useSettledSyncVersion(version: number): number {
|
|
|
96
97
|
import {
|
|
97
98
|
navigateWithAgentChatViewTransition,
|
|
98
99
|
useChatThreads,
|
|
99
|
-
type ChatThreadSummary,
|
|
100
100
|
} from "@agent-native/core/client/agent-chat";
|
|
101
101
|
import {
|
|
102
102
|
callAction,
|
|
@@ -104,13 +104,14 @@ import {
|
|
|
104
104
|
useChangeVersions,
|
|
105
105
|
} from "@agent-native/core/client/hooks";
|
|
106
106
|
import { useT } from "@agent-native/core/client/i18n";
|
|
107
|
+
import {
|
|
108
|
+
OwnershipChatHistoryRail,
|
|
109
|
+
useOwnershipChatHistory,
|
|
110
|
+
ownDraftRows,
|
|
111
|
+
} from "@agent-native/toolkit/app/chat/ownership-history";
|
|
107
112
|
import { DevDatabaseLink } from "@agent-native/toolkit/app/db-admin";
|
|
108
113
|
import { FeedbackButton } from "@agent-native/toolkit/app/feedback";
|
|
109
114
|
import { OrgSwitcher } from "@agent-native/toolkit/app/org";
|
|
110
|
-
import {
|
|
111
|
-
ChatHistoryRail,
|
|
112
|
-
type ChatHistoryItem,
|
|
113
|
-
} from "@agent-native/toolkit/chat-history";
|
|
114
115
|
import {
|
|
115
116
|
analyticsAskThreadIdFromPath,
|
|
116
117
|
analyticsAskThreadPath,
|
|
@@ -333,10 +334,6 @@ function applyOrder<T extends { id: string }>(
|
|
|
333
334
|
return ordered;
|
|
334
335
|
}
|
|
335
336
|
|
|
336
|
-
function isVisibility(value: unknown): value is Visibility {
|
|
337
|
-
return value === "private" || value === "org" || value === "public";
|
|
338
|
-
}
|
|
339
|
-
|
|
340
337
|
export function matchesVisibilityFilter(
|
|
341
338
|
item: { visibility?: Visibility; ownerEmail?: string | null },
|
|
342
339
|
filter: SidebarVisibilityFilter,
|
|
@@ -345,23 +342,6 @@ export function matchesVisibilityFilter(
|
|
|
345
342
|
return matchesDashboardVisibilityFilter(item, filter, currentUserEmail);
|
|
346
343
|
}
|
|
347
344
|
|
|
348
|
-
export function threadMatchesVisibilityFilter(
|
|
349
|
-
thread: ChatThreadSummary,
|
|
350
|
-
filter: SidebarVisibilityFilter,
|
|
351
|
-
): boolean {
|
|
352
|
-
const runtimeThread = thread as ChatThreadSummary & {
|
|
353
|
-
visibility?: unknown;
|
|
354
|
-
};
|
|
355
|
-
return matchesVisibilityFilter(
|
|
356
|
-
{
|
|
357
|
-
visibility: isVisibility(runtimeThread.visibility)
|
|
358
|
-
? runtimeThread.visibility
|
|
359
|
-
: "private",
|
|
360
|
-
},
|
|
361
|
-
filter,
|
|
362
|
-
);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
345
|
function SidebarSectionSettingsPopover({
|
|
366
346
|
label,
|
|
367
347
|
sortMode,
|
|
@@ -1368,110 +1348,44 @@ export function prefetchSqlDashboard(
|
|
|
1368
1348
|
});
|
|
1369
1349
|
}
|
|
1370
1350
|
|
|
1371
|
-
function formatThreadAge(updatedAt: number) {
|
|
1372
|
-
const diffMs = Math.max(0, Date.now() - updatedAt);
|
|
1373
|
-
const minutes = Math.floor(diffMs / 60_000);
|
|
1374
|
-
if (minutes < 1) return "now";
|
|
1375
|
-
if (minutes < 60) return `${minutes}m`;
|
|
1376
|
-
const hours = Math.floor(minutes / 60);
|
|
1377
|
-
if (hours < 24) return `${hours}h`;
|
|
1378
|
-
const days = Math.floor(hours / 24);
|
|
1379
|
-
if (days < 7) return `${days}d`;
|
|
1380
|
-
return new Date(updatedAt).toLocaleDateString([], {
|
|
1381
|
-
month: "short",
|
|
1382
|
-
day: "numeric",
|
|
1383
|
-
});
|
|
1384
|
-
}
|
|
1385
|
-
|
|
1386
|
-
function threadTitle(thread: ChatThreadSummary, untitledLabel: string) {
|
|
1387
|
-
return thread.title || thread.preview || untitledLabel;
|
|
1388
|
-
}
|
|
1389
|
-
|
|
1390
|
-
function threadUpdatedAt(thread: ChatThreadSummary) {
|
|
1391
|
-
return Number.isFinite(thread.updatedAt)
|
|
1392
|
-
? thread.updatedAt
|
|
1393
|
-
: Number.isFinite(thread.createdAt)
|
|
1394
|
-
? thread.createdAt
|
|
1395
|
-
: 0;
|
|
1396
|
-
}
|
|
1397
|
-
|
|
1398
|
-
function compareThreads(a: ChatThreadSummary, b: ChatThreadSummary) {
|
|
1399
|
-
const aPinned = a.pinnedAt ?? 0;
|
|
1400
|
-
const bPinned = b.pinnedAt ?? 0;
|
|
1401
|
-
if (aPinned || bPinned) return bPinned - aPinned;
|
|
1402
|
-
return threadUpdatedAt(b) - threadUpdatedAt(a);
|
|
1403
|
-
}
|
|
1404
|
-
|
|
1405
1351
|
function AnalyticsChatsSection({
|
|
1406
1352
|
askThreadId,
|
|
1407
1353
|
open,
|
|
1408
|
-
visibilityFilter,
|
|
1409
1354
|
}: {
|
|
1410
1355
|
/** The saved thread open on /ask/:threadId; null on the blank /ask page. */
|
|
1411
1356
|
askThreadId: string | null;
|
|
1412
1357
|
open: boolean;
|
|
1413
|
-
visibilityFilter: SidebarVisibilityFilter;
|
|
1414
1358
|
}) {
|
|
1415
1359
|
const navigate = useNavigate();
|
|
1416
1360
|
const t = useT();
|
|
1417
|
-
const {
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
refreshThreads,
|
|
1424
|
-
} = useChatThreads(undefined, ANALYTICS_CHAT_STORAGE_KEY, undefined, {
|
|
1425
|
-
autoCreate: false,
|
|
1426
|
-
restoreActiveThread: false,
|
|
1427
|
-
});
|
|
1428
|
-
|
|
1429
|
-
const visibleThreads = useMemo(
|
|
1430
|
-
() =>
|
|
1431
|
-
threads
|
|
1432
|
-
.filter(
|
|
1433
|
-
(thread) =>
|
|
1434
|
-
thread.messageCount > 0 &&
|
|
1435
|
-
!thread.archivedAt &&
|
|
1436
|
-
threadMatchesVisibilityFilter(thread, visibilityFilter),
|
|
1437
|
-
)
|
|
1438
|
-
.sort(compareThreads)
|
|
1439
|
-
.slice(0, 15),
|
|
1440
|
-
[threads, visibilityFilter],
|
|
1441
|
-
);
|
|
1442
|
-
const chatItems = useMemo<ChatHistoryItem[]>(
|
|
1443
|
-
() =>
|
|
1444
|
-
visibleThreads.map((thread) => ({
|
|
1445
|
-
id: thread.id,
|
|
1446
|
-
title: threadTitle(thread, t("chat.untitledChat")),
|
|
1447
|
-
titleText: threadTitle(thread, t("chat.untitledChat")),
|
|
1448
|
-
timestamp:
|
|
1449
|
-
thread.id === askThreadId
|
|
1450
|
-
? undefined
|
|
1451
|
-
: formatThreadAge(threadUpdatedAt(thread)),
|
|
1452
|
-
pinned: Boolean(thread.pinnedAt),
|
|
1453
|
-
})),
|
|
1454
|
-
[askThreadId, t, visibleThreads],
|
|
1455
|
-
);
|
|
1361
|
+
const { threads, pinThread, archiveThread, renameThread, isNewThread } =
|
|
1362
|
+
useChatThreads(undefined, ANALYTICS_CHAT_STORAGE_KEY, undefined, {
|
|
1363
|
+
ownership: "mine",
|
|
1364
|
+
autoCreate: false,
|
|
1365
|
+
restoreActiveThread: false,
|
|
1366
|
+
});
|
|
1456
1367
|
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1368
|
+
const history = useOwnershipChatHistory({
|
|
1369
|
+
getThreadUrl: (threadId) => appPath(analyticsAskThreadPath(threadId)),
|
|
1370
|
+
activeId: askThreadId,
|
|
1371
|
+
localMineRows: ownDraftRows({ threads, isNewThread }),
|
|
1372
|
+
mutations: {
|
|
1373
|
+
pin: pinThread,
|
|
1374
|
+
rename: renameThread,
|
|
1375
|
+
archive: archiveThread,
|
|
1376
|
+
},
|
|
1377
|
+
onMutationFailed: (kind) => {
|
|
1378
|
+
toast.error(
|
|
1379
|
+
t(
|
|
1380
|
+
kind === "archive"
|
|
1381
|
+
? "chat.archiveFailed"
|
|
1382
|
+
: kind === "rename"
|
|
1383
|
+
? "chat.renameFailed"
|
|
1384
|
+
: "agentChat.common.saveFailed",
|
|
1385
|
+
),
|
|
1386
|
+
);
|
|
1387
|
+
},
|
|
1388
|
+
});
|
|
1475
1389
|
|
|
1476
1390
|
function openThread(threadId: string) {
|
|
1477
1391
|
navigateWithAgentChatViewTransition(
|
|
@@ -1494,18 +1408,10 @@ function AnalyticsChatsSection({
|
|
|
1494
1408
|
|
|
1495
1409
|
async function handleArchiveThread(threadId: string) {
|
|
1496
1410
|
const wasActive = threadId === askThreadId;
|
|
1497
|
-
const archived = await
|
|
1498
|
-
if (!archived)
|
|
1499
|
-
toast.error(t("chat.archiveFailed"));
|
|
1500
|
-
return;
|
|
1501
|
-
}
|
|
1411
|
+
const archived = await history.listProps.onDelete!(threadId);
|
|
1412
|
+
if (!archived) return false;
|
|
1502
1413
|
if (wasActive) handleNewChat();
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
function handleRenameThread(threadId: string, title: string) {
|
|
1506
|
-
void renameThread(threadId, title).then((renamed) => {
|
|
1507
|
-
if (!renamed) toast.error(t("chat.renameFailed"));
|
|
1508
|
-
});
|
|
1414
|
+
return true;
|
|
1509
1415
|
}
|
|
1510
1416
|
|
|
1511
1417
|
return (
|
|
@@ -1515,43 +1421,15 @@ function AnalyticsChatsSection({
|
|
|
1515
1421
|
aria-hidden={!open}
|
|
1516
1422
|
>
|
|
1517
1423
|
<div className="ms-4 min-w-0 space-y-0.5">
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
Array.from({ length: 3 }).map((_, i) => (
|
|
1521
|
-
<div
|
|
1522
|
-
key={`chat-skeleton-${i}`}
|
|
1523
|
-
className="flex items-center gap-2 px-3 py-1"
|
|
1524
|
-
>
|
|
1525
|
-
<Skeleton
|
|
1526
|
-
className={cn(
|
|
1527
|
-
"h-3.5 w-3.5 shrink-0 rounded-sm",
|
|
1528
|
-
SIDEBAR_SKELETON_CLASS,
|
|
1529
|
-
)}
|
|
1530
|
-
/>
|
|
1531
|
-
<Skeleton
|
|
1532
|
-
className={cn("h-3 rounded", SIDEBAR_SKELETON_CLASS)}
|
|
1533
|
-
style={{ width: `${60 + ((i * 17) % 30)}%` }}
|
|
1534
|
-
/>
|
|
1535
|
-
</div>
|
|
1536
|
-
))}
|
|
1537
|
-
<ChatHistoryRail
|
|
1538
|
-
items={chatItems}
|
|
1424
|
+
<OwnershipChatHistoryRail
|
|
1425
|
+
{...history}
|
|
1539
1426
|
activeId={askThreadId}
|
|
1540
1427
|
onSelect={(threadId) => openThread(threadId)}
|
|
1541
1428
|
onNewChat={handleNewChat}
|
|
1542
1429
|
railLabels={{
|
|
1543
1430
|
newChat: t("chat.newChat"),
|
|
1544
|
-
showMore: t("sidebar.showMore", {
|
|
1545
|
-
count: Math.max(0, visibleThreads.length - SIDEBAR_PREVIEW_COUNT),
|
|
1546
|
-
}),
|
|
1547
|
-
showLess: t("sidebar.showLess"),
|
|
1548
1431
|
}}
|
|
1549
1432
|
renameMaxLength={160}
|
|
1550
|
-
onTogglePin={(threadId) => {
|
|
1551
|
-
const thread = visibleThreads.find((item) => item.id === threadId);
|
|
1552
|
-
if (thread) void pinThread(threadId, !thread.pinnedAt);
|
|
1553
|
-
}}
|
|
1554
|
-
onRename={handleRenameThread}
|
|
1555
1433
|
onDelete={(threadId) => void handleArchiveThread(threadId)}
|
|
1556
1434
|
labels={{
|
|
1557
1435
|
options: (item) =>
|
|
@@ -1639,7 +1517,6 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
1639
1517
|
const [askOpen, setAskOpen] = useState(
|
|
1640
1518
|
() => getStoredBooleanPreference(ASK_OPEN_KEY) ?? isAskRoute,
|
|
1641
1519
|
);
|
|
1642
|
-
const [askFilter, setAskFilter] = useState<SidebarVisibilityFilter>("all");
|
|
1643
1520
|
const [dashOpen, setDashOpen] = useState(
|
|
1644
1521
|
() =>
|
|
1645
1522
|
getStoredBooleanPreference(DASHBOARDS_OPEN_KEY) ??
|
|
@@ -2511,11 +2388,6 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
2511
2388
|
{t("navigation.ask")}
|
|
2512
2389
|
</span>
|
|
2513
2390
|
</Link>
|
|
2514
|
-
<SidebarSectionSettingsPopover
|
|
2515
|
-
label={t("navigation.ask")}
|
|
2516
|
-
visibilityFilter={askFilter}
|
|
2517
|
-
onVisibilityFilterChange={setAskFilter}
|
|
2518
|
-
/>
|
|
2519
2391
|
<button
|
|
2520
2392
|
type="button"
|
|
2521
2393
|
onClick={toggleAskOpen}
|
|
@@ -2538,7 +2410,6 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
2538
2410
|
<AnalyticsChatsSection
|
|
2539
2411
|
askThreadId={askThreadId}
|
|
2540
2412
|
open={askOpen}
|
|
2541
|
-
visibilityFilter={askFilter}
|
|
2542
2413
|
/>
|
|
2543
2414
|
</div>
|
|
2544
2415
|
|
|
@@ -1790,6 +1790,10 @@ export default {
|
|
|
1790
1790
|
catalogOpenSessions: "Show sessions with {{event}}",
|
|
1791
1791
|
catalogAutomatic: "Automatic",
|
|
1792
1792
|
catalogStoppedFiring: "Stopped firing",
|
|
1793
|
+
catalogMadeIt: "Made it",
|
|
1794
|
+
catalogUsedIt: "Used it",
|
|
1795
|
+
catalogNoUsedIt:
|
|
1796
|
+
"“Made it, didn't use it” can't check outputs from {{apps}} because no “used it” event is defined.",
|
|
1793
1797
|
catalogPropertyKeys: "Property keys",
|
|
1794
1798
|
catalogMoreKeys: "+{{count}} more",
|
|
1795
1799
|
catalogTruncated: "Showing only the {{count}} most recently seen events.",
|
|
@@ -1803,6 +1807,29 @@ export default {
|
|
|
1803
1807
|
speedCoverageStarting: "Speed is measured for page views from now on.",
|
|
1804
1808
|
speedFilterNeedsLab:
|
|
1805
1809
|
"This link has a speed filter. Turn on the Sessions triage Lab in Settings to apply it.",
|
|
1810
|
+
unusedOutputs: "Made it, didn't use it",
|
|
1811
|
+
anyOutcome: "Any session",
|
|
1812
|
+
unusedSlidesDecks: "Unused Slides decks",
|
|
1813
|
+
unusedSlidesRule:
|
|
1814
|
+
"Decks made at least {{days}} days ago that weren't presented past the first slide for {{seconds}} s or more, or exported, within {{days}} days. Opening a deck doesn't count.",
|
|
1815
|
+
unusedFilterNeedsLab:
|
|
1816
|
+
"This link has a “made it, didn't use it” filter. Turn on the Sessions triage Lab in Settings to apply it.",
|
|
1817
|
+
outputCoverageSince:
|
|
1818
|
+
"Outputs tracked since {{date}}; unused ones show {{days}} days after they're made.",
|
|
1819
|
+
outputCoverageStarting:
|
|
1820
|
+
"Outputs are tracked from now on; unused ones show {{days}} days after they're made.",
|
|
1821
|
+
openDeck: "Open deck",
|
|
1822
|
+
moreOutputs: "+{{count}} more",
|
|
1823
|
+
deckCount: "{{count}} decks",
|
|
1824
|
+
deckCountSingular: "{{count}} deck",
|
|
1825
|
+
deckMadeOn: "Deck made {{date}}",
|
|
1826
|
+
outputPresentedOn: "Presented {{date}}",
|
|
1827
|
+
outputExportedOn: "Exported {{date}}",
|
|
1828
|
+
outputUsedOn: "Used {{date}}",
|
|
1829
|
+
outputUnused: "Not used within {{days}} days",
|
|
1830
|
+
outputOpen: "Not used yet; counts as unused after {{date}}",
|
|
1831
|
+
outputUnmeasured: "Not measured: some events failed to save",
|
|
1832
|
+
outputsUnavailable: "Couldn't load outputs.",
|
|
1806
1833
|
slowRequestCount: "{{count}} slow requests",
|
|
1807
1834
|
slowRequestCountSingular: "{{count}} slow request",
|
|
1808
1835
|
speedIncomplete: "Speed data incomplete",
|
|
@@ -82,6 +82,9 @@ export default function EventCatalogPage() {
|
|
|
82
82
|
const automaticOnlyApps = (data?.apps ?? []).filter(
|
|
83
83
|
(item) => item.onlyAutomaticEvents,
|
|
84
84
|
);
|
|
85
|
+
const noUsedItApps = (data?.apps ?? [])
|
|
86
|
+
.filter((item) => item.makesOutputs && !item.usedItEvents.length)
|
|
87
|
+
.map((item) => item.app || t("sessions.unknownApp"));
|
|
85
88
|
const sessionsHref = `/sessions${
|
|
86
89
|
range !== "30d" || app
|
|
87
90
|
? `?${new URLSearchParams({
|
|
@@ -190,7 +193,7 @@ export default function EventCatalogPage() {
|
|
|
190
193
|
</Button>
|
|
191
194
|
</div>
|
|
192
195
|
|
|
193
|
-
{automaticOnlyApps.length ? (
|
|
196
|
+
{automaticOnlyApps.length || noUsedItApps.length ? (
|
|
194
197
|
<Alert role="status">
|
|
195
198
|
<IconInfoCircle />
|
|
196
199
|
<AlertDescription>
|
|
@@ -201,6 +204,13 @@ export default function EventCatalogPage() {
|
|
|
201
204
|
})}
|
|
202
205
|
</p>
|
|
203
206
|
))}
|
|
207
|
+
{noUsedItApps.length ? (
|
|
208
|
+
<p>
|
|
209
|
+
{t("sessions.catalogNoUsedIt", {
|
|
210
|
+
apps: noUsedItApps.join(", "),
|
|
211
|
+
})}
|
|
212
|
+
</p>
|
|
213
|
+
) : null}
|
|
204
214
|
</AlertDescription>
|
|
205
215
|
</Alert>
|
|
206
216
|
) : null}
|
|
@@ -283,6 +293,13 @@ function CatalogRow({
|
|
|
283
293
|
{t("sessions.catalogStoppedFiring")}
|
|
284
294
|
</Badge>
|
|
285
295
|
) : null}
|
|
296
|
+
{entry.outputRole ? (
|
|
297
|
+
<Badge variant="outline">
|
|
298
|
+
{entry.outputRole === "made"
|
|
299
|
+
? t("sessions.catalogMadeIt")
|
|
300
|
+
: t("sessions.catalogUsedIt")}
|
|
301
|
+
</Badge>
|
|
302
|
+
) : null}
|
|
286
303
|
</span>
|
|
287
304
|
{entry.description ? (
|
|
288
305
|
<span className="line-clamp-2 block text-xs text-muted-foreground">
|
|
@@ -128,6 +128,7 @@ import {
|
|
|
128
128
|
SessionDevToolsPanel,
|
|
129
129
|
} from "./SessionDevToolsPanel";
|
|
130
130
|
import { SessionFrictionPanel } from "./SessionFriction";
|
|
131
|
+
import { SessionOutputsButton } from "./SessionOutputs";
|
|
131
132
|
import { SessionStartTime } from "./SessionStartTime";
|
|
132
133
|
|
|
133
134
|
export {
|
|
@@ -343,7 +344,8 @@ export default function SessionDetailPage() {
|
|
|
343
344
|
</div>
|
|
344
345
|
{recording ? (
|
|
345
346
|
<TooltipProvider>
|
|
346
|
-
<div className="flex shrink-0 items-center gap-2">
|
|
347
|
+
<div className="flex shrink-0 flex-wrap items-center gap-2">
|
|
348
|
+
<SessionOutputsButton recordingId={recording.id} />
|
|
347
349
|
<CopySessionForAgentButton recordingId={recording.id} />
|
|
348
350
|
<AskSessionPopover recording={recording} />
|
|
349
351
|
<AgentToggleButton />
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { useActionQuery } from "@agent-native/core/client/hooks";
|
|
2
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
3
|
+
import { useLab } from "@agent-native/core/client/labs";
|
|
4
|
+
import {
|
|
5
|
+
IconExternalLink,
|
|
6
|
+
IconPackage,
|
|
7
|
+
IconRefresh,
|
|
8
|
+
} from "@tabler/icons-react";
|
|
9
|
+
|
|
10
|
+
import { Button } from "@/components/ui/button";
|
|
11
|
+
import {
|
|
12
|
+
Popover,
|
|
13
|
+
PopoverContent,
|
|
14
|
+
PopoverTrigger,
|
|
15
|
+
} from "@/components/ui/popover";
|
|
16
|
+
import { cn } from "@/lib/utils";
|
|
17
|
+
|
|
18
|
+
import { ANALYTICS_SESSIONS_TRIAGE_LAB } from "../../../shared/labs";
|
|
19
|
+
import {
|
|
20
|
+
MIN_PRESENTATION_MS,
|
|
21
|
+
OUTPUT_USE_WINDOW_DAYS,
|
|
22
|
+
type OutputUseApp,
|
|
23
|
+
type SessionOutput,
|
|
24
|
+
type SessionRecordingOutputs,
|
|
25
|
+
} from "../../../shared/output-use";
|
|
26
|
+
|
|
27
|
+
type T = ReturnType<typeof useT>;
|
|
28
|
+
|
|
29
|
+
export function unusedFilterLabel(app: OutputUseApp, t: T): string {
|
|
30
|
+
switch (app) {
|
|
31
|
+
case "slides":
|
|
32
|
+
return t("sessions.unusedSlidesDecks");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function unusedRuleText(app: OutputUseApp, t: T): string {
|
|
37
|
+
switch (app) {
|
|
38
|
+
case "slides":
|
|
39
|
+
return t("sessions.unusedSlidesRule", {
|
|
40
|
+
days: String(OUTPUT_USE_WINDOW_DAYS),
|
|
41
|
+
seconds: String(MIN_PRESENTATION_MS / 1000),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function openOutputLabel(output: SessionOutput, t: T): string {
|
|
47
|
+
switch (output.app) {
|
|
48
|
+
case "slides":
|
|
49
|
+
return t("sessions.openDeck");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function outputTitle(output: SessionOutput, t: T): string {
|
|
54
|
+
const date = new Date(output.madeAt).toLocaleDateString();
|
|
55
|
+
switch (output.app) {
|
|
56
|
+
case "slides":
|
|
57
|
+
return t("sessions.deckMadeOn", { date });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function outputStatusText(output: SessionOutput, t: T): string {
|
|
62
|
+
switch (output.status) {
|
|
63
|
+
case "used": {
|
|
64
|
+
const date = output.usedAt
|
|
65
|
+
? new Date(output.usedAt).toLocaleDateString()
|
|
66
|
+
: "";
|
|
67
|
+
if (output.usedEvent === "presentation_ended") {
|
|
68
|
+
return t("sessions.outputPresentedOn", { date });
|
|
69
|
+
}
|
|
70
|
+
if (output.usedEvent === "deck_exported") {
|
|
71
|
+
return t("sessions.outputExportedOn", { date });
|
|
72
|
+
}
|
|
73
|
+
return t("sessions.outputUsedOn", { date });
|
|
74
|
+
}
|
|
75
|
+
case "unused":
|
|
76
|
+
return t("sessions.outputUnused", {
|
|
77
|
+
days: String(OUTPUT_USE_WINDOW_DAYS),
|
|
78
|
+
});
|
|
79
|
+
case "open":
|
|
80
|
+
return t("sessions.outputOpen", {
|
|
81
|
+
date: new Date(output.useBy).toLocaleDateString(),
|
|
82
|
+
});
|
|
83
|
+
case "unmeasured":
|
|
84
|
+
return t("sessions.outputUnmeasured");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function OutputLink({ output }: { output: SessionOutput }) {
|
|
89
|
+
const t = useT();
|
|
90
|
+
if (!output.url) return null;
|
|
91
|
+
return (
|
|
92
|
+
<Button asChild variant="ghost" size="xs" className="shrink-0">
|
|
93
|
+
<a href={output.url} target="_blank" rel="noreferrer">
|
|
94
|
+
{openOutputLabel(output, t)}
|
|
95
|
+
<IconExternalLink />
|
|
96
|
+
</a>
|
|
97
|
+
</Button>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// A link cannot nest inside the row's replay link, so this sits beside it.
|
|
102
|
+
export function UnusedOutputLink({
|
|
103
|
+
outputs,
|
|
104
|
+
}: {
|
|
105
|
+
outputs?: SessionOutput[] | null;
|
|
106
|
+
}) {
|
|
107
|
+
const t = useT();
|
|
108
|
+
const unusedOutputs = (outputs ?? []).filter(
|
|
109
|
+
(output) => output.status === "unused",
|
|
110
|
+
);
|
|
111
|
+
const linked = unusedOutputs.find((output) => output.url);
|
|
112
|
+
if (!linked) return null;
|
|
113
|
+
return (
|
|
114
|
+
<div className="flex shrink-0 items-center gap-1 px-3">
|
|
115
|
+
<OutputLink output={linked} />
|
|
116
|
+
{unusedOutputs.length > 1 ? (
|
|
117
|
+
<span className="text-xs text-muted-foreground">
|
|
118
|
+
{t("sessions.moreOutputs", {
|
|
119
|
+
count: String(unusedOutputs.length - 1),
|
|
120
|
+
})}
|
|
121
|
+
</span>
|
|
122
|
+
) : null}
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** The outputs a replay's session made, and whether each was used in time. */
|
|
128
|
+
export function SessionOutputsButton({ recordingId }: { recordingId: string }) {
|
|
129
|
+
const t = useT();
|
|
130
|
+
const lab = useLab(ANALYTICS_SESSIONS_TRIAGE_LAB);
|
|
131
|
+
const query = useActionQuery<SessionRecordingOutputs>(
|
|
132
|
+
"list-session-outputs",
|
|
133
|
+
{ recordingIds: [recordingId] },
|
|
134
|
+
{ enabled: lab, staleTime: 30_000 },
|
|
135
|
+
);
|
|
136
|
+
if (!lab) return null;
|
|
137
|
+
if (query.isError && !query.data) {
|
|
138
|
+
return (
|
|
139
|
+
<Button
|
|
140
|
+
variant="ghost"
|
|
141
|
+
size="sm"
|
|
142
|
+
onClick={() => void query.refetch()}
|
|
143
|
+
disabled={query.isFetching}
|
|
144
|
+
>
|
|
145
|
+
<IconRefresh className={cn(query.isFetching && "animate-spin")} />
|
|
146
|
+
{t("sessions.outputsUnavailable")}
|
|
147
|
+
</Button>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
const outputs = query.data?.outputs[recordingId];
|
|
151
|
+
if (!outputs?.length) return null;
|
|
152
|
+
const omitted = query.data?.omittedOutputs[recordingId] ?? 0;
|
|
153
|
+
const total = outputs.length + omitted;
|
|
154
|
+
return (
|
|
155
|
+
<Popover>
|
|
156
|
+
<PopoverTrigger asChild>
|
|
157
|
+
<Button variant="outline">
|
|
158
|
+
<IconPackage />
|
|
159
|
+
{t(
|
|
160
|
+
total === 1 ? "sessions.deckCountSingular" : "sessions.deckCount",
|
|
161
|
+
{ count: String(total) },
|
|
162
|
+
)}
|
|
163
|
+
</Button>
|
|
164
|
+
</PopoverTrigger>
|
|
165
|
+
<PopoverContent align="end" className="w-80">
|
|
166
|
+
<ul className="space-y-3">
|
|
167
|
+
{outputs.map((output) => (
|
|
168
|
+
<li
|
|
169
|
+
key={`${output.app}:${output.outputId}`}
|
|
170
|
+
className="flex items-start justify-between gap-3"
|
|
171
|
+
>
|
|
172
|
+
<span className="min-w-0 text-sm">
|
|
173
|
+
<span className="block truncate font-medium">
|
|
174
|
+
{outputTitle(output, t)}
|
|
175
|
+
</span>
|
|
176
|
+
<span
|
|
177
|
+
className={cn(
|
|
178
|
+
"block text-xs text-muted-foreground",
|
|
179
|
+
output.status === "unused" && "text-foreground",
|
|
180
|
+
)}
|
|
181
|
+
>
|
|
182
|
+
{outputStatusText(output, t)}
|
|
183
|
+
</span>
|
|
184
|
+
</span>
|
|
185
|
+
<OutputLink output={output} />
|
|
186
|
+
</li>
|
|
187
|
+
))}
|
|
188
|
+
</ul>
|
|
189
|
+
{omitted ? (
|
|
190
|
+
<p className="mt-3 text-xs text-muted-foreground">
|
|
191
|
+
{t("sessions.moreOutputs", { count: String(omitted) })}
|
|
192
|
+
</p>
|
|
193
|
+
) : null}
|
|
194
|
+
</PopoverContent>
|
|
195
|
+
</Popover>
|
|
196
|
+
);
|
|
197
|
+
}
|