@agent-native/core 0.154.5 → 0.157.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/account-health/SKILL.md +76 -0
- package/corpus/templates/analytics/.agents/skills/bigquery/SKILL.md +3 -0
- package/corpus/templates/analytics/.agents/skills/cross-source-analysis/SKILL.md +2 -1
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +6 -5
- package/corpus/templates/analytics/AGENTS.md +3 -0
- package/corpus/templates/analytics/actions/account-deep-dive.ts +3 -2
- package/corpus/templates/analytics/actions/bigquery.ts +1 -1
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +4 -1
- package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +1 -0
- package/corpus/templates/analytics/app/pages/adhoc/explorer/components/PropertyCombobox.tsx +12 -4
- package/corpus/templates/analytics/app/pages/adhoc/explorer/components/PropertyValueCombobox.tsx +5 -2
- package/corpus/templates/analytics/app/pages/adhoc/explorer/property-label.ts +32 -0
- package/corpus/templates/analytics/changelog/2026-08-13-account-health-readouts-verify-customer-scope-and-contract-metrics.md +7 -0
- package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +43 -17
- package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +17 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +4 -0
- package/corpus/templates/assets/app/components/asset/AssetPreviewDialog.tsx +3 -1
- package/corpus/templates/assets/app/i18n-data.ts +21 -1
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +17 -13
- package/corpus/templates/calendar/AGENTS.md +2 -0
- package/corpus/templates/calendar/DEVELOPING.md +4 -4
- package/corpus/templates/calendar/actions/get-settings.ts +4 -11
- package/corpus/templates/calendar/actions/update-availability.ts +15 -4
- package/corpus/templates/calendar/actions/update-settings.ts +15 -4
- package/corpus/templates/calendar/app/components/booking/DatePicker.tsx +9 -3
- package/corpus/templates/calendar/app/components/calendar/CreateEventDialog.tsx +21 -19
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +9 -6
- package/corpus/templates/calendar/app/components/calendar/FindTimePanel.tsx +25 -3
- package/corpus/templates/calendar/app/components/calendar/InlineEventPickers.tsx +10 -3
- package/corpus/templates/calendar/app/components/calendar/MonthView.tsx +9 -9
- package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +11 -3
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +10 -4
- package/corpus/templates/calendar/app/i18n-data.ts +30 -0
- package/corpus/templates/calendar/app/lib/availability-schedule.ts +53 -0
- package/corpus/templates/calendar/app/lib/event-form-utils.ts +5 -0
- package/corpus/templates/calendar/app/pages/AvailabilitySettings.tsx +90 -28
- package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +135 -61
- package/corpus/templates/calendar/app/pages/BookingPage.tsx +2 -0
- package/corpus/templates/calendar/app/pages/CalendarView.tsx +30 -15
- package/corpus/templates/calendar/app/pages/Settings.tsx +60 -1
- package/corpus/templates/calendar/changelog/2026-08-13-find-a-time-now-closes-from-a-clear-header-action.md +6 -0
- package/corpus/templates/calendar/server/handlers/bookings.ts +2 -1
- package/corpus/templates/calendar/server/handlers/settings.ts +12 -16
- package/corpus/templates/calendar/shared/api.ts +1 -0
- package/corpus/templates/calendar/shared/availability-schedule.ts +64 -0
- package/corpus/templates/calendar/shared/calendar-week.ts +21 -0
- package/corpus/templates/calendar/shared/settings.ts +44 -0
- package/corpus/templates/clips/AGENTS.md +2 -0
- package/corpus/templates/clips/actions/add-comment.ts +5 -2
- package/corpus/templates/clips/actions/finalize-recording.ts +31 -1
- package/corpus/templates/clips/actions/get-recording-player-data.ts +9 -0
- package/corpus/templates/clips/actions/lib/ensure-seekable-video.ts +21 -1
- package/corpus/templates/clips/actions/reply-to-comment.ts +5 -2
- package/corpus/templates/clips/actions/update-comment.ts +9 -2
- package/corpus/templates/clips/app/components/library/search-bar.tsx +26 -13
- package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +135 -3
- package/corpus/templates/clips/app/components/player/comments-panel.tsx +5 -99
- package/corpus/templates/clips/app/components/player/playback-comment-overlay.tsx +7 -3
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +102 -59
- package/corpus/templates/clips/app/components/player/video-player.tsx +84 -24
- package/corpus/templates/clips/app/components/workspace/notifications-list.tsx +11 -3
- package/corpus/templates/clips/app/i18n/en-US.ts +12 -0
- package/corpus/templates/clips/app/lib/public-meeting.ts +11 -3
- package/corpus/templates/clips/app/lib/search-focus.ts +15 -0
- package/corpus/templates/clips/app/root.tsx +2 -1
- package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +94 -26
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +24 -7
- package/corpus/templates/clips/app/routes/embed.$shareId.tsx +8 -4
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +29 -8
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +24 -6
- package/corpus/templates/clips/app/routes/share.meeting.$meetingId.tsx +72 -26
- package/corpus/templates/clips/changelog/2026-08-13-inline-markdown-comments.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-13-private-meeting-agent-links.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +116 -19
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +13 -29
- package/corpus/templates/clips/desktop/src/lib/recording-request.ts +39 -0
- package/corpus/templates/clips/desktop/src/lib/settings-navigation.ts +11 -0
- package/corpus/templates/clips/desktop/src/lib/whisper-model-picker.ts +7 -0
- package/corpus/templates/clips/desktop/src/styles.css +117 -0
- package/corpus/templates/clips/server/db/index.ts +10 -0
- package/corpus/templates/clips/server/db/schema.ts +1 -0
- package/corpus/templates/clips/server/lib/recordings.ts +3 -1
- package/corpus/templates/clips/server/lib/seekable-media-state.ts +90 -0
- package/corpus/templates/clips/server/plugins/db.ts +5 -0
- package/corpus/templates/clips/server/routes/api/public-meeting.get.ts +37 -4
- package/corpus/templates/clips/server/routes/api/public-recording.get.ts +16 -5
- package/corpus/templates/clips/shared/clips-ai-prefs.ts +3 -0
- package/corpus/templates/clips/shared/meeting-agent-access.ts +5 -0
- package/corpus/templates/content/actions/add-comment.ts +2 -1
- package/corpus/templates/content/actions/update-comment.ts +1 -1
- package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +24 -15
- package/corpus/templates/design/actions/generate-design.ts +10 -7
- package/corpus/templates/design/actions/present-design-variants.ts +35 -6
- package/corpus/templates/design/actions/run-design-audit.ts +33 -0
- package/corpus/templates/design/changelog/2026-08-13-the-design-audit-now-catches-a-screen-that-renders-behind-an.md +6 -0
- package/corpus/templates/design/shared/design-review.ts +1 -0
- package/corpus/templates/design/shared/html-integrity.ts +66 -0
- package/corpus/templates/dispatch/.env.example +5 -0
- package/corpus/templates/dispatch/AGENTS.md +24 -19
- package/corpus/templates/dispatch/app/i18n-data.ts +20 -0
- package/corpus/templates/dispatch/server/lib/identity-sso.ts +21 -90
- package/corpus/templates/dispatch/server/plugins/identity-sso.ts +3 -12
- package/corpus/templates/dispatch/shared/feature-flags.ts +4 -0
- package/corpus/templates/factory/AGENTS.md +5 -1
- package/corpus/templates/factory/README.md +23 -0
- package/corpus/templates/factory/actions/view-screen.ts +17 -0
- package/corpus/templates/factory/app/components/factory/FactoryAgentsView.tsx +239 -0
- package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +2 -0
- package/corpus/templates/factory/app/components/factory/FactoryInspector.tsx +130 -7
- package/corpus/templates/factory/app/i18n/en-US.ts +20 -0
- package/corpus/templates/factory/app/routes/factory.tsx +41 -0
- package/corpus/templates/factory/package.json +1 -0
- package/corpus/templates/factory/server/factory-graph/contracts.ts +2 -0
- package/corpus/templates/factory/server/plugins/agent-chat.ts +9 -0
- package/corpus/templates/factory/server/plugins/dispatch-db.ts +1 -0
- package/corpus/templates/factory/server/plugins/setup-dispatch.ts +3 -0
- package/corpus/templates/mail/app/lib/native-mcp-exclusions.ts +3 -0
- package/corpus/templates/mail/vite.config.ts +7 -0
- package/corpus/templates/plan/actions/reply-to-plan-comment.ts +7 -2
- package/corpus/templates/plan/actions/resolve-plan-comment.ts +2 -2
- package/corpus/templates/plan/actions/update-visual-plan.ts +1 -1
- package/corpus/templates/plan/app/pages/PlansPage.tsx +29 -20
- package/corpus/templates/slides/actions/add-slide-comment.ts +1 -1
- package/corpus/templates/slides/actions/update-slide-comment.ts +1 -1
- package/corpus/templates/slides/app/components/comments/SlideCommentsPanel.tsx +9 -6
- package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +98 -29
- package/corpus/templates/slides/app/components/editor/EditorActionCluster.tsx +45 -91
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +94 -2
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +17 -29
- package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +1 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +42 -2
- package/corpus/templates/slides/app/global.css +7 -40
- package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +130 -45
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/production-agent.d.ts +30 -0
- package/dist/agent/production-agent.js +105 -9
- package/dist/agent/thread-data-builder.js +17 -1
- package/dist/agent/types.d.ts +9 -0
- package/dist/cli/skills-content/help.js +6 -4
- package/dist/cli/skills.js +17 -2
- package/dist/cli/workspacify.d.ts +5 -0
- package/dist/cli/workspacify.js +65 -8
- package/dist/client/AgentPanel.d.ts +5 -0
- package/dist/client/AgentPanel.js +32 -13
- package/dist/client/AssistantChat.d.ts +36 -1
- package/dist/client/AssistantChat.js +175 -110
- package/dist/client/MultiTabAssistantChat.js +44 -27
- package/dist/client/active-run-state.d.ts +14 -1
- package/dist/client/active-run-state.js +0 -0
- package/dist/client/agent-chat-adapter.js +107 -5
- package/dist/client/analytics.js +9 -2
- package/dist/client/chat/markdown-renderer.js +4 -2
- package/dist/client/chat/message-components.d.ts +2 -2
- package/dist/client/chat/message-components.js +69 -35
- package/dist/client/chat/run-recovery.d.ts +4 -1
- package/dist/client/chat/run-recovery.js +62 -30
- package/dist/client/chat/tool-call-display.d.ts +12 -3
- package/dist/client/chat/tool-call-display.js +79 -40
- package/dist/client/chat/widgets/DataChartRenderer.js +3 -1
- package/dist/client/chat/widgets/DataChartWidget.js +8 -2
- package/dist/client/chat/widgets/DataInsightsWidget.js +3 -1
- package/dist/client/chat/widgets/DataTableWidget.js +23 -9
- package/dist/client/chat/widgets/builtin-tool-renderers.js +3 -1
- package/dist/client/chat-first/apps-rail.js +9 -4
- package/dist/client/chat-first/primary-nav.d.ts +2 -1
- package/dist/client/chat-first/primary-nav.js +3 -3
- package/dist/client/chat-first/types.d.ts +5 -1
- package/dist/client/components/ui/message-scroller.d.ts +1 -1
- package/dist/client/components/ui/message-scroller.js +7 -3
- package/dist/client/composer/runtime-adapters.js +3 -2
- package/dist/client/context-xray/ContextMeter.js +5 -1
- package/dist/client/context-xray/ContextXRayPanel.js +5 -5
- package/dist/client/error-format.d.ts +4 -0
- package/dist/client/error-format.js +93 -5
- package/dist/client/i18n.js +83 -17
- package/dist/client/markdown/InlineMarkdown.d.ts +23 -0
- package/dist/client/markdown/InlineMarkdown.js +65 -0
- package/dist/client/markdown/index.d.ts +1 -0
- package/dist/client/markdown/index.js +1 -0
- package/dist/client/observability/ThumbsFeedback.js +10 -8
- package/dist/client/review/ReviewThreadPanel.js +2 -1
- package/dist/client/run-stream-ownership.d.ts +39 -0
- package/dist/client/run-stream-ownership.js +65 -0
- package/dist/client/sharing/ShareButton.js +160 -54
- package/dist/coding-tools/run-code.js +2 -1
- package/dist/coding-tools/sandbox/background.d.ts +1 -0
- package/dist/coding-tools/sandbox/background.js +8 -1
- package/dist/coding-tools/sandbox/executions-store.d.ts +2 -0
- package/dist/coding-tools/sandbox/executions-store.js +41 -3
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/feature-flags/index.d.ts +1 -1
- package/dist/feature-flags/index.js +1 -1
- package/dist/feature-flags/store.d.ts +10 -0
- package/dist/feature-flags/store.js +112 -1
- package/dist/guards/no-env-credentials.js +4 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/integrations/adapters/slack.js +5 -1
- package/dist/localization/core-messages/ar-SA.d.ts +3 -0
- package/dist/localization/core-messages/ar-SA.js +541 -0
- package/dist/localization/core-messages/de-DE.d.ts +3 -0
- package/dist/localization/core-messages/de-DE.js +513 -0
- package/dist/localization/core-messages/en-US.d.ts +513 -0
- package/dist/localization/core-messages/en-US.js +513 -0
- package/dist/localization/core-messages/es-ES.d.ts +3 -0
- package/dist/localization/core-messages/es-ES.js +520 -0
- package/dist/localization/core-messages/fr-FR.d.ts +3 -0
- package/dist/localization/core-messages/fr-FR.js +520 -0
- package/dist/localization/core-messages/hi-IN.d.ts +3 -0
- package/dist/localization/core-messages/hi-IN.js +513 -0
- package/dist/localization/core-messages/ja-JP.d.ts +3 -0
- package/dist/localization/core-messages/ja-JP.js +506 -0
- package/dist/localization/core-messages/ko-KR.d.ts +3 -0
- package/dist/localization/core-messages/ko-KR.js +506 -0
- package/dist/localization/core-messages/pt-BR.d.ts +3 -0
- package/dist/localization/core-messages/pt-BR.js +520 -0
- package/dist/localization/core-messages/zh-CN.d.ts +3 -0
- package/dist/localization/core-messages/zh-CN.js +506 -0
- package/dist/localization/core-messages/zh-TW.d.ts +3 -0
- package/dist/localization/core-messages/zh-TW.js +506 -0
- package/dist/localization/core-messages.d.ts +524 -0
- package/dist/localization/core-messages.js +124 -0
- package/dist/localization/default-messages.d.ts +3 -0
- package/dist/localization/default-messages.js +3 -0
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +2 -2
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
- package/dist/provider-api/actions/provider-api.d.ts +15 -15
- package/dist/resources/agents.js +40 -5
- package/dist/resources/metadata.d.ts +10 -0
- package/dist/resources/metadata.js +7 -3
- package/dist/review/actions/create-review-comment.js +1 -1
- package/dist/review/actions/reply-review-comment.js +1 -1
- package/dist/review/actions/resolve-review-thread.js +1 -1
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/action-routes.js +32 -6
- package/dist/server/agent-chat/plugin-options.d.ts +7 -2
- package/dist/server/agent-chat-plugin.d.ts +10 -0
- package/dist/server/agent-chat-plugin.js +144 -41
- package/dist/server/agent-discovery.js +14 -3
- package/dist/server/agent-run-context.d.ts +7 -1
- package/dist/server/agent-run-context.js +9 -2
- package/dist/server/agent-teams-run-queue.d.ts +3 -0
- package/dist/server/agent-teams.js +38 -9
- package/dist/server/core-routes-plugin.js +1 -1
- package/dist/server/identity-sso-migrations.d.ts +7 -0
- package/dist/server/identity-sso-migrations.js +36 -0
- package/dist/server/identity-sso-store.d.ts +3 -2
- package/dist/server/identity-sso-store.js +8 -3
- package/dist/server/index.d.ts +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/release-migrations.js +4 -0
- package/dist/server/request-context.d.ts +7 -0
- package/dist/server/request-context.js +15 -0
- package/dist/tracking/providers.js +13 -3
- package/dist/workspace-files/tool.js +1 -1
- package/docs/content/agent-surfaces.mdx +30 -0
- package/package.json +3 -2
|
@@ -54,6 +54,7 @@ import {
|
|
|
54
54
|
import { Toaster } from "@/components/ui/sonner";
|
|
55
55
|
import { AppToolkitProvider } from "@/components/ui/toolkit-provider";
|
|
56
56
|
import { useNavigationState } from "@/hooks/use-navigation-state";
|
|
57
|
+
import { SEARCH_FOCUS_PATH } from "@/lib/search-focus";
|
|
57
58
|
|
|
58
59
|
import { i18nCatalog, loadI18nMessages } from "./i18n";
|
|
59
60
|
|
|
@@ -374,7 +375,7 @@ function AppContent() {
|
|
|
374
375
|
<IconHierarchy2 size={16} />
|
|
375
376
|
{t("root.openAgent")}
|
|
376
377
|
</CommandMenu.Item>
|
|
377
|
-
<CommandMenu.Item onSelect={() =>
|
|
378
|
+
<CommandMenu.Item onSelect={() => navigate(SEARCH_FOCUS_PATH)}>
|
|
378
379
|
{t("root.commandSearch")}
|
|
379
380
|
</CommandMenu.Item>
|
|
380
381
|
</CommandMenu.Group>
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
IconNotes,
|
|
13
13
|
IconPlugConnected,
|
|
14
14
|
IconPlugOff,
|
|
15
|
+
IconPlus,
|
|
15
16
|
IconSearch,
|
|
16
17
|
IconSettings,
|
|
17
18
|
IconX,
|
|
@@ -530,17 +531,11 @@ function CalendarAccountMenu({
|
|
|
530
531
|
const [disconnectTarget, setDisconnectTarget] =
|
|
531
532
|
useState<CalendarAccount | null>(null);
|
|
532
533
|
|
|
533
|
-
const
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
? "Disconnected"
|
|
537
|
-
: primaryAccount?.status === "needs-reauth"
|
|
538
|
-
? "Needs reconnect"
|
|
539
|
-
: primaryAccount
|
|
540
|
-
? "Connected"
|
|
541
|
-
: "Not connected";
|
|
534
|
+
const hasNeedsReconnect = accounts.some(
|
|
535
|
+
(account) => account.status === "needs-reauth",
|
|
536
|
+
);
|
|
542
537
|
|
|
543
|
-
const
|
|
538
|
+
const handleConnect = () => {
|
|
544
539
|
setConnectPending(true);
|
|
545
540
|
startCalendarOAuth()
|
|
546
541
|
.then(() => onConnected?.())
|
|
@@ -586,48 +581,121 @@ function CalendarAccountMenu({
|
|
|
586
581
|
aria-label={t("meetingsRoute.calendarSettings")}
|
|
587
582
|
>
|
|
588
583
|
<IconSettings className="h-4 w-4" />
|
|
589
|
-
|
|
584
|
+
{t("meetingsRoute.calendarAccountsButton", {
|
|
585
|
+
defaultValue: "Calendars",
|
|
586
|
+
})}
|
|
590
587
|
</Button>
|
|
591
588
|
</DropdownMenuTrigger>
|
|
592
589
|
<DropdownMenuContent align="end" className="w-72">
|
|
593
590
|
<DropdownMenuLabel className="flex items-center gap-2">
|
|
594
|
-
{
|
|
591
|
+
{accounts.length > 0 ? (
|
|
595
592
|
<IconPlugConnected className="h-4 w-4 text-muted-foreground" />
|
|
596
593
|
) : (
|
|
597
594
|
<IconPlugOff className="h-4 w-4 text-muted-foreground" />
|
|
598
595
|
)}
|
|
599
596
|
Google Calendar
|
|
600
597
|
</DropdownMenuLabel>
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
598
|
+
{accounts.length > 0 ? (
|
|
599
|
+
<div className="space-y-1.5 px-2 pb-1">
|
|
600
|
+
<div className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
|
|
601
|
+
{t("meetingsRoute.connectedAccounts", {
|
|
602
|
+
defaultValue: "Connected accounts",
|
|
603
|
+
})}
|
|
604
|
+
</div>
|
|
605
|
+
{accounts.map((account) => (
|
|
606
|
+
<div
|
|
607
|
+
key={account.id}
|
|
608
|
+
className="flex min-w-0 items-center gap-2 text-xs"
|
|
609
|
+
>
|
|
610
|
+
{account.status === "needs-reauth" ? (
|
|
611
|
+
<IconAlertTriangle className="h-3.5 w-3.5 shrink-0 text-destructive" />
|
|
612
|
+
) : account.status === "disconnected" ? (
|
|
613
|
+
<IconPlugOff className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
|
|
614
|
+
) : (
|
|
615
|
+
<IconPlugConnected className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
|
|
616
|
+
)}
|
|
617
|
+
<span className="min-w-0 flex-1 truncate">
|
|
618
|
+
{calendarAccountLabel(account)}
|
|
619
|
+
</span>
|
|
620
|
+
<span
|
|
621
|
+
className={
|
|
622
|
+
account.status === "needs-reauth" ||
|
|
623
|
+
account.status === "disconnected"
|
|
624
|
+
? "shrink-0 text-[11px] text-destructive"
|
|
625
|
+
: "shrink-0 text-[11px] text-muted-foreground"
|
|
626
|
+
}
|
|
627
|
+
>
|
|
628
|
+
{account.status === "needs-reauth"
|
|
629
|
+
? t("meetingsRoute.calendarNeedsReconnectLabel", {
|
|
630
|
+
defaultValue: "Needs reconnect",
|
|
631
|
+
})
|
|
632
|
+
: account.status === "disconnected"
|
|
633
|
+
? t("meetingsRoute.calendarDisconnectedLabel", {
|
|
634
|
+
defaultValue: "Disconnected",
|
|
635
|
+
})
|
|
636
|
+
: account.status && account.status !== "connected"
|
|
637
|
+
? t("meetingsRoute.calendarStatusUnavailable", {
|
|
638
|
+
defaultValue: "Status unavailable",
|
|
639
|
+
})
|
|
640
|
+
: t("meetingsRoute.calendarConnectedLabel", {
|
|
641
|
+
defaultValue: "Connected",
|
|
642
|
+
})}
|
|
643
|
+
</span>
|
|
606
644
|
</div>
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
645
|
+
))}
|
|
646
|
+
</div>
|
|
647
|
+
) : (
|
|
648
|
+
<div className="px-2 pb-1 text-xs text-muted-foreground">
|
|
649
|
+
{t("meetingsRoute.connectCalendarReminder")}
|
|
650
|
+
</div>
|
|
651
|
+
)}
|
|
613
652
|
<DropdownMenuSeparator />
|
|
653
|
+
{hasNeedsReconnect && (
|
|
654
|
+
<DropdownMenuItem
|
|
655
|
+
onSelect={(event) => {
|
|
656
|
+
event.preventDefault();
|
|
657
|
+
handleConnect();
|
|
658
|
+
}}
|
|
659
|
+
disabled={connectPending}
|
|
660
|
+
>
|
|
661
|
+
{connectPending ? (
|
|
662
|
+
<IconLoader2 className="me-2 h-4 w-4 animate-spin" />
|
|
663
|
+
) : (
|
|
664
|
+
<IconExternalLink className="me-2 h-4 w-4" />
|
|
665
|
+
)}
|
|
666
|
+
{t("meetingsRoute.reconnectCalendar", {
|
|
667
|
+
defaultValue: "Reconnect calendar",
|
|
668
|
+
})}
|
|
669
|
+
</DropdownMenuItem>
|
|
670
|
+
)}
|
|
614
671
|
<DropdownMenuItem
|
|
615
672
|
onSelect={(event) => {
|
|
616
673
|
event.preventDefault();
|
|
617
|
-
|
|
674
|
+
handleConnect();
|
|
618
675
|
}}
|
|
619
676
|
disabled={connectPending}
|
|
620
677
|
>
|
|
621
678
|
{connectPending ? (
|
|
622
679
|
<IconLoader2 className="me-2 h-4 w-4 animate-spin" />
|
|
623
680
|
) : (
|
|
624
|
-
<
|
|
681
|
+
<IconPlus className="me-2 h-4 w-4" />
|
|
625
682
|
)}
|
|
626
|
-
{
|
|
683
|
+
{accounts.length > 0
|
|
684
|
+
? t("meetingsRoute.addAnotherCalendarAccount", {
|
|
685
|
+
defaultValue: "Add another account",
|
|
686
|
+
})
|
|
687
|
+
: t("meetingsRoute.connectCalendar", {
|
|
688
|
+
defaultValue: "Connect calendar",
|
|
689
|
+
})}
|
|
627
690
|
</DropdownMenuItem>
|
|
628
691
|
{accounts.length > 0 && (
|
|
629
692
|
<>
|
|
630
693
|
<DropdownMenuSeparator />
|
|
694
|
+
<DropdownMenuLabel className="text-[11px] text-muted-foreground">
|
|
695
|
+
{t("meetingsRoute.disconnectCalendarAccount", {
|
|
696
|
+
defaultValue: "Disconnect an account",
|
|
697
|
+
})}
|
|
698
|
+
</DropdownMenuLabel>
|
|
631
699
|
{accounts.map((account) => (
|
|
632
700
|
<DropdownMenuItem
|
|
633
701
|
key={account.id}
|
|
@@ -12,8 +12,11 @@ import {
|
|
|
12
12
|
useBuilderStatus,
|
|
13
13
|
type SettingsSearchEntry,
|
|
14
14
|
} from "@agent-native/core/client/settings";
|
|
15
|
-
import
|
|
16
|
-
|
|
15
|
+
import {
|
|
16
|
+
DEFAULT_CLIPS_RECORDING_VISIBILITY,
|
|
17
|
+
type ClipsDefaultVisibility,
|
|
18
|
+
} from "@shared/clips-ai-prefs";
|
|
19
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
17
20
|
import { toast } from "sonner";
|
|
18
21
|
|
|
19
22
|
import { PageHeader } from "@/components/library/page-header";
|
|
@@ -101,22 +104,34 @@ export default function SettingsIndexRoute() {
|
|
|
101
104
|
const storageStatus = useVideoStorageStatus();
|
|
102
105
|
const secrets = useSecretStatus();
|
|
103
106
|
const builderStatus = useBuilderStatus();
|
|
107
|
+
const connectRequestedRef = useRef(false);
|
|
104
108
|
const builderConnect = useBuilderConnectFlow({
|
|
105
109
|
popupUrl:
|
|
106
110
|
builderStatus.status?.cliAuthUrl ?? builderStatus.status?.connectUrl,
|
|
107
111
|
trackingSource: "clips_settings",
|
|
108
112
|
trackingFlow: "clips_setup",
|
|
109
113
|
onConnected: async () => {
|
|
114
|
+
const shouldShowConnectedToast = connectRequestedRef.current;
|
|
115
|
+
connectRequestedRef.current = false;
|
|
110
116
|
await Promise.all([storageStatus.refetch(), builderStatus.refetch()]);
|
|
111
|
-
|
|
117
|
+
if (shouldShowConnectedToast) {
|
|
118
|
+
toast.success(t("settings.builderConnectedToast"));
|
|
119
|
+
}
|
|
112
120
|
},
|
|
113
121
|
});
|
|
122
|
+
const startBuilderConnect = useCallback(
|
|
123
|
+
(options?: Parameters<typeof builderConnect.start>[0]) => {
|
|
124
|
+
connectRequestedRef.current = true;
|
|
125
|
+
builderConnect.start(options);
|
|
126
|
+
},
|
|
127
|
+
[builderConnect.start],
|
|
128
|
+
);
|
|
114
129
|
const [loading, setLoading] = useState(true);
|
|
115
130
|
const [saving, setSaving] = useState(false);
|
|
116
131
|
const [defaultSpeed, setDefaultSpeed] = useState("1.2");
|
|
117
132
|
const [emailNotifications, setEmailNotifications] = useState(true);
|
|
118
133
|
const [defaultVisibility, setDefaultVisibility] =
|
|
119
|
-
useState<ClipsDefaultVisibility>(
|
|
134
|
+
useState<ClipsDefaultVisibility>(DEFAULT_CLIPS_RECORDING_VISIBILITY);
|
|
120
135
|
const [transcriptCleanupEnabled, setTranscriptCleanupEnabled] =
|
|
121
136
|
useState(true);
|
|
122
137
|
|
|
@@ -126,7 +141,9 @@ export default function SettingsIndexRoute() {
|
|
|
126
141
|
if (cancelled) return;
|
|
127
142
|
setDefaultSpeed(v.defaultPlaybackSpeed ?? "1.2");
|
|
128
143
|
setEmailNotifications(v.emailNotifications ?? true);
|
|
129
|
-
setDefaultVisibility(
|
|
144
|
+
setDefaultVisibility(
|
|
145
|
+
v.defaultRecordingVisibility ?? DEFAULT_CLIPS_RECORDING_VISIBILITY,
|
|
146
|
+
);
|
|
130
147
|
setTranscriptCleanupEnabled(v.transcriptCleanupEnabled !== false);
|
|
131
148
|
setLoading(false);
|
|
132
149
|
});
|
|
@@ -151,9 +168,9 @@ export default function SettingsIndexRoute() {
|
|
|
151
168
|
!builderConnect.hasFetchedStatus,
|
|
152
169
|
connecting: builderConnect.connecting,
|
|
153
170
|
orgName: builderConnect.orgName ?? builderStatus.status?.orgName ?? null,
|
|
154
|
-
start:
|
|
171
|
+
start: startBuilderConnect,
|
|
155
172
|
}),
|
|
156
|
-
[builderConnect, builderStatus, storageStatus],
|
|
173
|
+
[builderConnect, builderStatus, startBuilderConnect, storageStatus],
|
|
157
174
|
);
|
|
158
175
|
|
|
159
176
|
async function handleUploadWorkspaceChange(organizationId: string) {
|
|
@@ -132,11 +132,16 @@ export default function EmbedRoute() {
|
|
|
132
132
|
readyMediaPollRef.current = null;
|
|
133
133
|
return 2000;
|
|
134
134
|
}
|
|
135
|
+
if (rec.seekableRepairPending === true) {
|
|
136
|
+
readyMediaPollRef.current = null;
|
|
137
|
+
return READY_MEDIA_SETTLE_POLL_INTERVAL_MS;
|
|
138
|
+
}
|
|
135
139
|
const mediaKey = [
|
|
136
140
|
rec.id,
|
|
137
141
|
rec.durationMs ?? "",
|
|
138
142
|
rec.videoSizeBytes ?? "",
|
|
139
143
|
rec.videoFormat ?? "",
|
|
144
|
+
rec.updatedAt ?? "",
|
|
140
145
|
].join(":");
|
|
141
146
|
const now = Date.now();
|
|
142
147
|
if (readyMediaPollRef.current?.key !== mediaKey) {
|
|
@@ -225,10 +230,9 @@ export default function EmbedRoute() {
|
|
|
225
230
|
onVideoElementChange={setTrackedVideoEl}
|
|
226
231
|
recordingId={recording.id}
|
|
227
232
|
videoUrl={recording.videoUrl}
|
|
228
|
-
mediaVersion={
|
|
229
|
-
recording.videoSizeBytes ??
|
|
230
|
-
|
|
231
|
-
].join(":")}
|
|
233
|
+
mediaVersion={
|
|
234
|
+
recording.mediaUpdatedAt ?? recording.videoSizeBytes ?? null
|
|
235
|
+
}
|
|
232
236
|
videoFormat={recording.videoFormat}
|
|
233
237
|
embedProvider={isLoomEmbedBacked ? "loom" : null}
|
|
234
238
|
durationMs={recording.durationMs}
|
|
@@ -310,6 +310,10 @@ export default function RecordingPage() {
|
|
|
310
310
|
readyMediaPollRef.current = null;
|
|
311
311
|
return 1000;
|
|
312
312
|
}
|
|
313
|
+
if (rec.seekableRepairPending === true) {
|
|
314
|
+
readyMediaPollRef.current = null;
|
|
315
|
+
return READY_MEDIA_SETTLE_POLL_INTERVAL_MS;
|
|
316
|
+
}
|
|
313
317
|
// Fresh streaming uploads can become `ready` before the background
|
|
314
318
|
// seekable/faststart repair swaps in the final player URL. Keep polling
|
|
315
319
|
// briefly so the first post-recording page catches that URL update
|
|
@@ -319,6 +323,7 @@ export default function RecordingPage() {
|
|
|
319
323
|
rec.durationMs ?? "",
|
|
320
324
|
rec.videoSizeBytes ?? "",
|
|
321
325
|
rec.videoFormat ?? "",
|
|
326
|
+
rec.updatedAt ?? "",
|
|
322
327
|
].join(":");
|
|
323
328
|
const now = Date.now();
|
|
324
329
|
if (readyMediaPollRef.current?.key !== mediaKey) {
|
|
@@ -524,6 +529,18 @@ export default function RecordingPage() {
|
|
|
524
529
|
const canDownloadRecording = Boolean(
|
|
525
530
|
recording?.enableDownloads && recording.videoUrl && !isLoomEmbedBacked,
|
|
526
531
|
);
|
|
532
|
+
// Mirrors the /share/:shareId reshare restriction (same public/org scope):
|
|
533
|
+
// a plain viewer of a public or org clip must not trigger
|
|
534
|
+
// `list-resource-shares` (any read access is enough to call it, and its
|
|
535
|
+
// response includes every individually-shared principal's email) or see a
|
|
536
|
+
// raw video download/open action independent of `enableDownloads`.
|
|
537
|
+
const viewerReshareOnly =
|
|
538
|
+
(role === "viewer" || role === "commenter") &&
|
|
539
|
+
(recording?.visibility === "public" || recording?.visibility === "org");
|
|
540
|
+
const shareVideoUrl =
|
|
541
|
+
canDownloadRecording || isLoomEmbedBacked
|
|
542
|
+
? (recording?.videoUrl ?? null)
|
|
543
|
+
: null;
|
|
527
544
|
const downloadRecording = useCallback(async () => {
|
|
528
545
|
if (!recording?.videoUrl) return;
|
|
529
546
|
setDownloading(true);
|
|
@@ -962,7 +979,7 @@ export default function RecordingPage() {
|
|
|
962
979
|
variant="ghost"
|
|
963
980
|
size="icon"
|
|
964
981
|
className="shrink-0"
|
|
965
|
-
aria-label={t("recordingPage.
|
|
982
|
+
aria-label={t("recordingPage.backToLibrary")}
|
|
966
983
|
>
|
|
967
984
|
<Link to="/library" replace>
|
|
968
985
|
<IconArrowLeft className="h-4 w-4 rtl:-scale-x-100" />
|
|
@@ -983,6 +1000,7 @@ export default function RecordingPage() {
|
|
|
983
1000
|
initialVisibility={recording.visibility}
|
|
984
1001
|
initialRole={role}
|
|
985
1002
|
hasPassword={Boolean(recording.hasPassword)}
|
|
1003
|
+
viewerReshareOnly={viewerReshareOnly}
|
|
986
1004
|
>
|
|
987
1005
|
<Button className="shrink-0 gap-1.5" size="sm">
|
|
988
1006
|
{recording.visibility !== "public" ? (
|
|
@@ -1305,11 +1323,14 @@ export default function RecordingPage() {
|
|
|
1305
1323
|
asChild
|
|
1306
1324
|
variant="ghost"
|
|
1307
1325
|
size="icon"
|
|
1308
|
-
className="shrink-0"
|
|
1309
|
-
aria-label={t("recordingPage.
|
|
1326
|
+
className="shrink-0 sm:w-auto sm:px-2"
|
|
1327
|
+
aria-label={t("recordingPage.backToLibrary")}
|
|
1310
1328
|
>
|
|
1311
1329
|
<Link to="/library" replace>
|
|
1312
1330
|
<IconArrowLeft className="h-4 w-4 rtl:-scale-x-100" />
|
|
1331
|
+
<span className="hidden sm:inline">
|
|
1332
|
+
{t("recordingPage.backToLibrary")}
|
|
1333
|
+
</span>
|
|
1313
1334
|
</Link>
|
|
1314
1335
|
</Button>
|
|
1315
1336
|
<div className="flex-1 min-w-0">
|
|
@@ -1542,11 +1563,12 @@ export default function RecordingPage() {
|
|
|
1542
1563
|
recordingTitle={recording.title}
|
|
1543
1564
|
initialVisibility={recording.visibility}
|
|
1544
1565
|
initialRole={role}
|
|
1545
|
-
videoUrl={
|
|
1566
|
+
videoUrl={shareVideoUrl}
|
|
1546
1567
|
thumbnailUrl={recording.thumbnailUrl}
|
|
1547
1568
|
animatedThumbnailUrl={recording.animatedThumbnailUrl}
|
|
1548
1569
|
isLoomRecording={isLoomEmbedBacked}
|
|
1549
1570
|
hasPassword={Boolean(recording.hasPassword)}
|
|
1571
|
+
viewerReshareOnly={viewerReshareOnly}
|
|
1550
1572
|
>
|
|
1551
1573
|
<Button
|
|
1552
1574
|
className="shrink-0 gap-1.5 bg-primary text-primary-foreground hover:bg-primary/90"
|
|
@@ -1592,10 +1614,9 @@ export default function RecordingPage() {
|
|
|
1592
1614
|
onVideoElementChange={setTrackedVideoEl}
|
|
1593
1615
|
recordingId={recording.id}
|
|
1594
1616
|
videoUrl={recording.videoUrl}
|
|
1595
|
-
mediaVersion={
|
|
1596
|
-
recording.videoSizeBytes ??
|
|
1597
|
-
|
|
1598
|
-
].join(":")}
|
|
1617
|
+
mediaVersion={
|
|
1618
|
+
recording.mediaUpdatedAt ?? recording.videoSizeBytes ?? null
|
|
1619
|
+
}
|
|
1599
1620
|
videoFormat={recording.videoFormat}
|
|
1600
1621
|
embedProvider={isLoomEmbedBacked ? "loom" : null}
|
|
1601
1622
|
durationMs={recording.durationMs}
|
|
@@ -470,11 +470,16 @@ export default function ShareRoute() {
|
|
|
470
470
|
readyMediaPollRef.current = null;
|
|
471
471
|
return 2000;
|
|
472
472
|
}
|
|
473
|
+
if (rec.seekableRepairPending === true) {
|
|
474
|
+
readyMediaPollRef.current = null;
|
|
475
|
+
return READY_MEDIA_SETTLE_POLL_INTERVAL_MS;
|
|
476
|
+
}
|
|
473
477
|
const mediaKey = [
|
|
474
478
|
rec.id,
|
|
475
479
|
rec.durationMs ?? "",
|
|
476
480
|
rec.videoSizeBytes ?? "",
|
|
477
481
|
rec.videoFormat ?? "",
|
|
482
|
+
rec.updatedAt ?? "",
|
|
478
483
|
].join(":");
|
|
479
484
|
const now = Date.now();
|
|
480
485
|
if (readyMediaPollRef.current?.key !== mediaKey) {
|
|
@@ -532,6 +537,15 @@ export default function ShareRoute() {
|
|
|
532
537
|
viewerRole === "editor" ||
|
|
533
538
|
viewerRole === "commenter";
|
|
534
539
|
const viewerIsOwner = Boolean(dataQ.data?.data?.viewer?.isOwner);
|
|
540
|
+
const canReshareLink =
|
|
541
|
+
(viewerRole === "viewer" || viewerRole === "commenter") &&
|
|
542
|
+
(recording?.visibility === "public" || recording?.visibility === "org");
|
|
543
|
+
// A plain viewer only gets a copy-link control: it must not trigger
|
|
544
|
+
// `list-resource-shares` (any read access is enough to call it, and its
|
|
545
|
+
// response includes every individually-shared principal's email) and must
|
|
546
|
+
// not surface the raw video download/open action independent of
|
|
547
|
+
// `enableDownloads`.
|
|
548
|
+
const viewerReshareOnly = canReshareLink && !viewerCanEdit;
|
|
535
549
|
const viewerCanOpenDashboard = Boolean(
|
|
536
550
|
dataQ.data?.data?.viewer?.canOpenDashboard,
|
|
537
551
|
);
|
|
@@ -894,6 +908,10 @@ export default function ShareRoute() {
|
|
|
894
908
|
const canDownloadRecording = Boolean(
|
|
895
909
|
recording.enableDownloads && recording.videoUrl && !isLoomEmbedBacked,
|
|
896
910
|
);
|
|
911
|
+
// Loom-backed clips only ever get an "open player" link (not a raw
|
|
912
|
+
// download), so they're exempt from the enableDownloads gate here.
|
|
913
|
+
const shareVideoUrl =
|
|
914
|
+
canDownloadRecording || isLoomEmbedBacked ? recording.videoUrl : null;
|
|
897
915
|
|
|
898
916
|
return (
|
|
899
917
|
<div className="flex min-h-screen max-w-full flex-col overflow-x-hidden bg-background text-foreground lg:h-screen lg:flex-row lg:overflow-hidden">
|
|
@@ -990,17 +1008,18 @@ export default function ShareRoute() {
|
|
|
990
1008
|
onDeleted={() => navigate("/library", { replace: true })}
|
|
991
1009
|
/>
|
|
992
1010
|
) : null}
|
|
993
|
-
{viewerCanEdit ? (
|
|
1011
|
+
{viewerCanEdit || canReshareLink ? (
|
|
994
1012
|
<ShareRecordingPopover
|
|
995
1013
|
recordingId={recording.id}
|
|
996
1014
|
recordingTitle={recording.title}
|
|
997
1015
|
initialVisibility={recording.visibility}
|
|
998
1016
|
initialRole={viewerIsOwner ? "owner" : undefined}
|
|
999
|
-
videoUrl={
|
|
1017
|
+
videoUrl={shareVideoUrl}
|
|
1000
1018
|
thumbnailUrl={recording.thumbnailUrl}
|
|
1001
1019
|
animatedThumbnailUrl={recording.animatedThumbnailUrl}
|
|
1002
1020
|
isLoomRecording={isLoomEmbedBacked}
|
|
1003
1021
|
hasPassword={Boolean(recording.hasPassword)}
|
|
1022
|
+
viewerReshareOnly={viewerReshareOnly}
|
|
1004
1023
|
>
|
|
1005
1024
|
<Button size="sm" className="shrink-0 gap-1.5">
|
|
1006
1025
|
{recording.visibility !== "public" ? (
|
|
@@ -1020,10 +1039,9 @@ export default function ShareRoute() {
|
|
|
1020
1039
|
onVideoElementChange={setTrackedVideoEl}
|
|
1021
1040
|
recordingId={recording.id}
|
|
1022
1041
|
videoUrl={recording.videoUrl}
|
|
1023
|
-
mediaVersion={
|
|
1024
|
-
recording.videoSizeBytes ??
|
|
1025
|
-
|
|
1026
|
-
].join(":")}
|
|
1042
|
+
mediaVersion={
|
|
1043
|
+
recording.mediaUpdatedAt ?? recording.videoSizeBytes ?? null
|
|
1044
|
+
}
|
|
1027
1045
|
videoFormat={recording.videoFormat}
|
|
1028
1046
|
embedProvider={isLoomEmbedBacked ? "loom" : null}
|
|
1029
1047
|
durationMs={recording.durationMs}
|
|
@@ -2,7 +2,10 @@ import { appPath } from "@agent-native/core/client/api-path";
|
|
|
2
2
|
import { useSession } from "@agent-native/core/client/hooks";
|
|
3
3
|
import { useT } from "@agent-native/core/client/i18n";
|
|
4
4
|
import { PoweredByBadge } from "@agent-native/core/client/ui";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
AGENT_ACCESS_PARAM,
|
|
7
|
+
normalizeDocumentTitle,
|
|
8
|
+
} from "@agent-native/core/shared";
|
|
6
9
|
import {
|
|
7
10
|
IconCalendar,
|
|
8
11
|
IconCheck,
|
|
@@ -16,8 +19,12 @@ import {
|
|
|
16
19
|
import { useQuery } from "@tanstack/react-query";
|
|
17
20
|
import { and, eq, isNull } from "drizzle-orm";
|
|
18
21
|
import { useEffect, useRef, useState } from "react";
|
|
19
|
-
import type {
|
|
20
|
-
|
|
22
|
+
import type {
|
|
23
|
+
HeadersArgs,
|
|
24
|
+
LoaderFunctionArgs,
|
|
25
|
+
MetaFunction,
|
|
26
|
+
} from "react-router";
|
|
27
|
+
import { useLoaderData, useParams, useSearchParams } from "react-router";
|
|
21
28
|
import { toast } from "sonner";
|
|
22
29
|
|
|
23
30
|
import {
|
|
@@ -36,15 +43,37 @@ import {
|
|
|
36
43
|
} from "@/lib/public-meeting";
|
|
37
44
|
|
|
38
45
|
import { getDb, schema } from "../../server/db";
|
|
46
|
+
import { CLIPS_MEETING_AGENT_RESOURCE_KIND } from "../../shared/meeting-agent-access";
|
|
47
|
+
import { privateShareLoaderData } from "../../shared/share-loader-response";
|
|
39
48
|
|
|
40
49
|
type LoaderData = { meeting: PublicMeeting | null };
|
|
41
50
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
51
|
+
function shareMeetingLoaderData(
|
|
52
|
+
payload: LoaderData,
|
|
53
|
+
privateAgentAccess = false,
|
|
54
|
+
) {
|
|
55
|
+
return privateAgentAccess ? privateShareLoaderData(payload) : payload;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function headers({ loaderHeaders }: HeadersArgs) {
|
|
59
|
+
return loaderHeaders;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export async function loader({ params, url }: LoaderFunctionArgs) {
|
|
45
63
|
const meetingId = params.meetingId;
|
|
46
64
|
if (!meetingId) return { meeting: null };
|
|
47
65
|
|
|
66
|
+
const { verifyScopedAgentAccessToken } =
|
|
67
|
+
await import("@agent-native/core/server");
|
|
68
|
+
const agentAccessToken = url.searchParams.get(AGENT_ACCESS_PARAM) ?? "";
|
|
69
|
+
const hasAgentAccessToken = Boolean(agentAccessToken);
|
|
70
|
+
const tokenGrantsAgentAccess = agentAccessToken
|
|
71
|
+
? verifyScopedAgentAccessToken(agentAccessToken, {
|
|
72
|
+
resourceKind: CLIPS_MEETING_AGENT_RESOURCE_KIND,
|
|
73
|
+
resourceId: meetingId,
|
|
74
|
+
}).ok
|
|
75
|
+
: false;
|
|
76
|
+
|
|
48
77
|
const [meeting] = await getDb()
|
|
49
78
|
.select({
|
|
50
79
|
id: schema.meetings.id,
|
|
@@ -59,14 +88,21 @@ export async function loader({
|
|
|
59
88
|
})
|
|
60
89
|
.from(schema.meetings)
|
|
61
90
|
.where(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
91
|
+
tokenGrantsAgentAccess
|
|
92
|
+
? and(
|
|
93
|
+
eq(schema.meetings.id, meetingId),
|
|
94
|
+
isNull(schema.meetings.trashedAt),
|
|
95
|
+
)
|
|
96
|
+
: and(
|
|
97
|
+
eq(schema.meetings.id, meetingId),
|
|
98
|
+
eq(schema.meetings.visibility, "public"),
|
|
99
|
+
isNull(schema.meetings.trashedAt),
|
|
100
|
+
),
|
|
67
101
|
)
|
|
68
102
|
.limit(1);
|
|
69
|
-
if (!meeting)
|
|
103
|
+
if (!meeting) {
|
|
104
|
+
return shareMeetingLoaderData({ meeting: null }, hasAgentAccessToken);
|
|
105
|
+
}
|
|
70
106
|
|
|
71
107
|
const [participants, actionItems] = await Promise.all([
|
|
72
108
|
getDb()
|
|
@@ -101,20 +137,23 @@ export async function loader({
|
|
|
101
137
|
}
|
|
102
138
|
} catch {}
|
|
103
139
|
|
|
104
|
-
return
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
140
|
+
return shareMeetingLoaderData(
|
|
141
|
+
{
|
|
142
|
+
meeting: {
|
|
143
|
+
id: meeting.id,
|
|
144
|
+
title: meeting.title,
|
|
145
|
+
scheduledStart: meeting.scheduledStart,
|
|
146
|
+
summaryMd: meeting.summaryMd,
|
|
147
|
+
bullets,
|
|
148
|
+
participants,
|
|
149
|
+
actionItems,
|
|
150
|
+
actualStart: meeting.actualStart,
|
|
151
|
+
actualEnd: meeting.actualEnd,
|
|
152
|
+
transcriptStatus: meeting.transcriptStatus,
|
|
153
|
+
},
|
|
116
154
|
},
|
|
117
|
-
|
|
155
|
+
hasAgentAccessToken,
|
|
156
|
+
);
|
|
118
157
|
}
|
|
119
158
|
|
|
120
159
|
export const meta: MetaFunction<typeof loader> = ({ loaderData }) => {
|
|
@@ -197,7 +236,9 @@ export default function ShareMeetingRoute() {
|
|
|
197
236
|
const t = useT();
|
|
198
237
|
const loaderData = useLoaderData<LoaderData>();
|
|
199
238
|
const { meetingId } = useParams<{ meetingId: string }>();
|
|
239
|
+
const [searchParams] = useSearchParams();
|
|
200
240
|
const { session, isLoading: sessionLoading } = useSession();
|
|
241
|
+
const agentAccessToken = searchParams.get(AGENT_ACCESS_PARAM) ?? "";
|
|
201
242
|
const pollingStartedAtRef = useRef<number | null>(null);
|
|
202
243
|
const [transcriptCopied, setTranscriptCopied] = useState(false);
|
|
203
244
|
const initialMeetingResult: PublicMeetingResult | undefined =
|
|
@@ -215,8 +256,13 @@ export default function ShareMeetingRoute() {
|
|
|
215
256
|
meetingId,
|
|
216
257
|
session?.email ?? null,
|
|
217
258
|
session?.orgId ?? null,
|
|
259
|
+
agentAccessToken,
|
|
218
260
|
],
|
|
219
|
-
queryFn: ({ signal }) =>
|
|
261
|
+
queryFn: ({ signal }) =>
|
|
262
|
+
fetchPublicMeeting(meetingId ?? "", {
|
|
263
|
+
signal,
|
|
264
|
+
agentAccessToken,
|
|
265
|
+
}),
|
|
220
266
|
enabled: !!meetingId && !sessionLoading,
|
|
221
267
|
initialData: initialMeetingResult,
|
|
222
268
|
refetchInterval: (query) => {
|