@agent-native/core 0.120.2 → 0.120.4
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 +3 -3
- package/corpus/core/CHANGELOG.md +28 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/cli/context-xray-local.ts +1 -1
- package/corpus/core/src/cli/index.ts +63 -18
- package/corpus/core/src/cli/skills.ts +5 -0
- package/corpus/core/src/cli/telemetry.ts +118 -1
- package/corpus/core/src/client/AgentPanel.tsx +10 -0
- package/corpus/core/src/client/CommandMenu.tsx +13 -1
- package/corpus/core/src/client/agent-page/AgentTabsPage.tsx +39 -4
- package/corpus/core/src/client/analytics.ts +13 -0
- package/corpus/core/src/client/error-capture.ts +6 -1
- package/corpus/core/src/client/extensions/ExtensionsListPage.tsx +12 -5
- package/corpus/core/src/client/extensions/agent-native-extension-runtime.ts +1 -1
- package/corpus/core/src/client/navigation/index.ts +2 -0
- package/corpus/core/src/client/org/OrgSwitcher.tsx +14 -32
- package/corpus/core/src/client/settings/ExtensionsSettingsContent.tsx +1 -1
- package/corpus/core/src/extensions/theme.ts +1 -1
- package/corpus/core/src/localization/default-messages.ts +2 -0
- package/corpus/core/src/server/core-routes-plugin.ts +10 -1
- package/corpus/core/src/server/framework-request-handler.ts +17 -26
- package/corpus/core/src/styles/agent-native.css +13 -0
- package/corpus/core/src/templates/chat/app/components/layout/Layout.tsx +3 -0
- package/corpus/core/src/templates/chat/app/components/layout/Sidebar.tsx +78 -45
- package/corpus/core/src/templates/chat/app/global.css +1 -1
- package/corpus/core/src/templates/default/app/global.css +1 -1
- package/corpus/core/src/tracking/error-capture.ts +151 -0
- package/corpus/core/src/tracking/index.ts +5 -0
- package/corpus/templates/analytics/app/components/dashboard/CumulativeNetChart.tsx +1 -1
- package/corpus/templates/analytics/app/components/dashboard/DashboardHistoryPanel.tsx +1 -4
- package/corpus/templates/analytics/app/components/dashboard/DashboardPanelSkeleton.tsx +1 -1
- package/corpus/templates/analytics/app/components/dashboard/DataTable.tsx +1 -1
- package/corpus/templates/analytics/app/components/dashboard/DateRangePicker.tsx +2 -2
- package/corpus/templates/analytics/app/components/dashboard/MetricCard.tsx +1 -1
- package/corpus/templates/analytics/app/components/dashboard/RecentActivity.tsx +1 -1
- package/corpus/templates/analytics/app/components/dashboard/RevenueChart.tsx +1 -1
- package/corpus/templates/analytics/app/components/dashboard/RevenueComparisonChart.tsx +1 -1
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +41 -9
- package/corpus/templates/analytics/app/components/dashboard/StatsCard.tsx +1 -1
- package/corpus/templates/analytics/app/components/dashboard/TimeSeriesChart.tsx +1 -1
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +2 -0
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +28 -14
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +152 -124
- package/corpus/templates/analytics/app/global.css +5 -5
- package/corpus/templates/analytics/app/lib/dashboard-report-capture.ts +42 -0
- package/corpus/templates/analytics/app/pages/adhoc/_shared/KpiChart.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/explorer/components/ChartTypePicker.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/explorer/components/DateRangePicker.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/explorer/components/EventRow.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/explorer/components/SqlPreview.tsx +2 -2
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/DashboardFilterBar.tsx +3 -3
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/EmailReportDialog.tsx +2 -2
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +162 -51
- package/corpus/templates/analytics/app/root.tsx +28 -0
- package/corpus/templates/analytics/changelog/2026-07-24-analytics-charts-now-explain-slow-loads-and-offer-a-direct-r.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-24-daily-dashboard-emails-now-load-signed-reports-more-reliably.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-24-manage-agent-is-clearly-marked-as-a-link-to-its-dedicated-pa.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +1 -1
- package/corpus/templates/analytics/server/db/schema.ts +5 -0
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +21 -0
- package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +11 -0
- package/corpus/templates/analytics/server/lib/dashboard-report-subscriptions.ts +54 -0
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +235 -26
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +4 -1
- package/corpus/templates/analytics/server/plugins/db.ts +9 -0
- package/corpus/templates/analytics/shared/dashboard-report-timeouts.ts +1 -1
- package/corpus/templates/assets/app/components/asset/AssetPreviewDialog.tsx +376 -0
- package/corpus/templates/assets/app/components/create/RecentDraftsSection.tsx +14 -4
- package/corpus/templates/assets/app/components/layout/Layout.tsx +5 -0
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +118 -74
- package/corpus/templates/assets/app/global.css +1 -1
- package/corpus/templates/assets/app/i18n-data.ts +10 -0
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +99 -10
- package/corpus/templates/assets/app/routes/library.tsx +21 -198
- package/corpus/templates/assets/changelog/2026-07-21-unified-asset-preview-click-any-asset-to-open-one-preview-wi.md +6 -0
- package/corpus/templates/assets/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/assets/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/brain/app/components/layout/Layout.tsx +3 -0
- package/corpus/templates/brain/app/components/layout/Sidebar.tsx +76 -43
- package/corpus/templates/brain/app/global.css +1 -1
- package/corpus/templates/brain/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +67 -52
- package/corpus/templates/calendar/app/global.css +1 -1
- package/corpus/templates/calendar/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/calendar/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/chat/app/components/layout/Layout.tsx +3 -0
- package/corpus/templates/chat/app/components/layout/Sidebar.tsx +78 -45
- package/corpus/templates/chat/app/global.css +1 -1
- package/corpus/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/clips/app/components/library/library-layout.tsx +65 -31
- package/corpus/templates/clips/app/components/library/organization-switcher.tsx +2 -2
- package/corpus/templates/clips/app/components/player/video-player.tsx +16 -1
- package/corpus/templates/clips/app/global.css +1 -1
- package/corpus/templates/clips/app/hooks/use-view-tracking.ts +55 -12
- package/corpus/templates/clips/app/routes/embed.$shareId.tsx +6 -5
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +7 -7
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -5
- package/corpus/templates/clips/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/clips/server/plugins/db.ts +113 -68
- package/corpus/templates/content/actions/update-document.ts +145 -91
- package/corpus/templates/content/app/components/editor/CommentComposer.tsx +4 -1
- package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +366 -164
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +51 -28
- package/corpus/templates/content/app/components/editor/database/sidebar.tsx +19 -8
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +66 -42
- package/corpus/templates/content/app/global.css +1 -1
- package/corpus/templates/content/app/i18n-data.ts +15 -0
- package/corpus/templates/content/changelog/2026-07-23-shared-pages-now-keep-durable-content-visible-and-comment-th.md +6 -0
- package/corpus/templates/content/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/content/changelog/2026-07-24-comment-drafts-now-stay-open-when-saving-fails-and-long-live.md +6 -0
- package/corpus/templates/content/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/design/actions/update-file.ts +85 -18
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +65 -30
- package/corpus/templates/design/app/entry.client.tsx +14 -1
- package/corpus/templates/design/app/global.css +1 -1
- package/corpus/templates/design/app/lib/design-save-outbox.ts +39 -0
- package/corpus/templates/design/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/design/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/dispatch/app/global.css +1 -1
- package/corpus/templates/dispatch/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/forms/app/components/layout/Layout.tsx +3 -0
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +72 -37
- package/corpus/templates/forms/app/global.css +1 -1
- package/corpus/templates/forms/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/forms/changelog/2026-07-24-forms-sidebar-actions-now-keep-search-language-feedback-and-.md +6 -0
- package/corpus/templates/forms/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/macros/app/components/DailyProgress.tsx +5 -5
- package/corpus/templates/macros/app/components/ExerciseCard.tsx +2 -2
- package/corpus/templates/macros/app/components/MealCard.tsx +2 -2
- package/corpus/templates/macros/app/components/WeightCard.tsx +2 -2
- package/corpus/templates/macros/app/components/layout/AppLayout.tsx +56 -29
- package/corpus/templates/macros/app/components/ui/button.tsx +1 -2
- package/corpus/templates/macros/app/components/ui/card.tsx +1 -1
- package/corpus/templates/macros/app/global.css +1 -1
- package/corpus/templates/macros/app/routes/_index.tsx +1 -1
- package/corpus/templates/macros/app/routes/analytics.tsx +4 -7
- package/corpus/templates/macros/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/macros/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +125 -37
- package/corpus/templates/mail/app/global.css +1 -1
- package/corpus/templates/mail/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/mail/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/plan/app/components/layout/Layout.tsx +3 -0
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +90 -60
- package/corpus/templates/plan/app/global.css +1 -1
- package/corpus/templates/plan/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/slides/app/components/layout/Sidebar.tsx +69 -32
- package/corpus/templates/slides/app/global.css +1 -1
- package/corpus/templates/slides/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/tasks/app/global.css +1 -1
- package/corpus/templates/tasks/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/toolkit/CHANGELOG.md +14 -0
- package/corpus/toolkit/README.md +8 -1
- package/corpus/toolkit/agent-native.eject.json +1 -1
- package/corpus/toolkit/package.json +1 -1
- package/corpus/toolkit/src/app-shell/index.ts +1 -0
- package/corpus/toolkit/src/app-shell/sidebar-footer-actions.tsx +48 -0
- package/corpus/toolkit/src/chat-history.css +52 -1
- package/corpus/toolkit/src/design-system/default-adapter.tsx +1 -1
- package/corpus/toolkit/src/editor/useCollabReconcile.ts +83 -15
- package/corpus/toolkit/src/ui/button.tsx +1 -2
- package/corpus/toolkit/src/ui/card.tsx +1 -1
- package/corpus/toolkit/src/ui/table.tsx +4 -11
- package/dist/cli/context-xray-local.js +1 -1
- package/dist/cli/context-xray-local.js.map +1 -1
- package/dist/cli/index.js +56 -17
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +5 -0
- package/dist/cli/skills.js.map +1 -1
- package/dist/cli/telemetry.d.ts +7 -0
- package/dist/cli/telemetry.d.ts.map +1 -1
- package/dist/cli/telemetry.js +91 -1
- package/dist/cli/telemetry.js.map +1 -1
- package/dist/client/AgentPanel.d.ts +7 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +2 -2
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/CommandMenu.d.ts +2 -0
- package/dist/client/CommandMenu.d.ts.map +1 -1
- package/dist/client/CommandMenu.js +12 -1
- package/dist/client/CommandMenu.js.map +1 -1
- package/dist/client/agent-page/AgentTabsPage.d.ts +4 -0
- package/dist/client/agent-page/AgentTabsPage.d.ts.map +1 -1
- package/dist/client/agent-page/AgentTabsPage.js +8 -4
- package/dist/client/agent-page/AgentTabsPage.js.map +1 -1
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +7 -0
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/error-capture.d.ts.map +1 -1
- package/dist/client/error-capture.js +8 -1
- package/dist/client/error-capture.js.map +1 -1
- package/dist/client/extensions/ExtensionsListPage.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionsListPage.js +2 -2
- package/dist/client/extensions/ExtensionsListPage.js.map +1 -1
- package/dist/client/extensions/agent-native-extension-runtime.js +1 -1
- package/dist/client/extensions/agent-native-extension-runtime.js.map +1 -1
- package/dist/client/navigation/index.d.ts +1 -1
- package/dist/client/navigation/index.d.ts.map +1 -1
- package/dist/client/navigation/index.js +1 -1
- package/dist/client/navigation/index.js.map +1 -1
- package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
- package/dist/client/org/OrgSwitcher.js +9 -13
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/settings/ExtensionsSettingsContent.js +1 -1
- package/dist/client/settings/ExtensionsSettingsContent.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/extensions/theme.js +1 -1
- package/dist/extensions/theme.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/localization/default-messages.d.ts +2 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +2 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/provider-api/actions/provider-api.d.ts +2 -2
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +8 -1
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/framework-request-handler.d.ts.map +1 -1
- package/dist/server/framework-request-handler.js +17 -27
- package/dist/server/framework-request-handler.js.map +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/styles/agent-native.css +13 -0
- package/dist/templates/chat/app/components/layout/Layout.tsx +3 -0
- package/dist/templates/chat/app/components/layout/Sidebar.tsx +78 -45
- package/dist/templates/chat/app/global.css +1 -1
- package/dist/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/dist/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/dist/templates/default/app/global.css +1 -1
- package/dist/tracking/error-capture.d.ts +14 -0
- package/dist/tracking/error-capture.d.ts.map +1 -0
- package/dist/tracking/error-capture.js +113 -0
- package/dist/tracking/error-capture.js.map +1 -0
- package/dist/tracking/index.d.ts +1 -0
- package/dist/tracking/index.d.ts.map +1 -1
- package/dist/tracking/index.js +1 -0
- package/dist/tracking/index.js.map +1 -1
- package/package.json +2 -2
- package/src/cli/context-xray-local.ts +1 -1
- package/src/cli/index.ts +63 -18
- package/src/cli/skills.ts +5 -0
- package/src/cli/telemetry.ts +118 -1
- package/src/client/AgentPanel.tsx +10 -0
- package/src/client/CommandMenu.tsx +13 -1
- package/src/client/agent-page/AgentTabsPage.tsx +39 -4
- package/src/client/analytics.ts +13 -0
- package/src/client/error-capture.ts +6 -1
- package/src/client/extensions/ExtensionsListPage.tsx +12 -5
- package/src/client/extensions/agent-native-extension-runtime.ts +1 -1
- package/src/client/navigation/index.ts +2 -0
- package/src/client/org/OrgSwitcher.tsx +14 -32
- package/src/client/settings/ExtensionsSettingsContent.tsx +1 -1
- package/src/extensions/theme.ts +1 -1
- package/src/localization/default-messages.ts +2 -0
- package/src/server/core-routes-plugin.ts +10 -1
- package/src/server/framework-request-handler.ts +17 -26
- package/src/styles/agent-native.css +13 -0
- package/src/templates/chat/app/components/layout/Layout.tsx +3 -0
- package/src/templates/chat/app/components/layout/Sidebar.tsx +78 -45
- package/src/templates/chat/app/global.css +1 -1
- package/src/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/src/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/src/templates/default/app/global.css +1 -1
- package/src/tracking/error-capture.ts +151 -0
- package/src/tracking/index.ts +5 -0
|
@@ -579,13 +579,13 @@ export default function ShareRoute() {
|
|
|
579
579
|
|
|
580
580
|
usePlayerShortcuts({ playerRef });
|
|
581
581
|
|
|
582
|
+
const [trackedVideoEl, setTrackedVideoEl] = useState<HTMLVideoElement | null>(
|
|
583
|
+
null,
|
|
584
|
+
);
|
|
585
|
+
|
|
582
586
|
const tracking = useViewTracking({
|
|
583
587
|
recordingId: shareId ?? "",
|
|
584
|
-
|
|
585
|
-
get current() {
|
|
586
|
-
return playerRef.current?.video ?? null;
|
|
587
|
-
},
|
|
588
|
-
} as any,
|
|
588
|
+
videoEl: trackedVideoEl,
|
|
589
589
|
durationMs: recording?.durationMs ?? 0,
|
|
590
590
|
trackOpenWithoutVideo: isLoomEmbedBacked,
|
|
591
591
|
});
|
|
@@ -961,6 +961,7 @@ export default function ShareRoute() {
|
|
|
961
961
|
<div className="aspect-video w-full lg:min-h-0 lg:flex-1 lg:aspect-auto">
|
|
962
962
|
<VideoPlayer
|
|
963
963
|
ref={playerRef}
|
|
964
|
+
onVideoElementChange={setTrackedVideoEl}
|
|
964
965
|
recordingId={recording.id}
|
|
965
966
|
videoUrl={recording.videoUrl}
|
|
966
967
|
videoFormat={recording.videoFormat}
|
|
@@ -1261,16 +1261,6 @@ async function sweepOrphanedRecordingChunks(): Promise<void> {
|
|
|
1261
1261
|
}
|
|
1262
1262
|
}
|
|
1263
1263
|
|
|
1264
|
-
function rowNumber(value: unknown): number {
|
|
1265
|
-
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
1266
|
-
if (typeof value === "bigint") return Number(value);
|
|
1267
|
-
if (typeof value === "string") {
|
|
1268
|
-
const parsed = Number(value);
|
|
1269
|
-
return Number.isFinite(parsed) ? parsed : 0;
|
|
1270
|
-
}
|
|
1271
|
-
return 0;
|
|
1272
|
-
}
|
|
1273
|
-
|
|
1274
1264
|
/**
|
|
1275
1265
|
* Sweep orphaned resumable upload sessions out of `application_state`.
|
|
1276
1266
|
*
|
|
@@ -1287,6 +1277,8 @@ function rowNumber(value: unknown): number {
|
|
|
1287
1277
|
async function sweepOrphanedResumableSessions(): Promise<void> {
|
|
1288
1278
|
const exec = getDbExec();
|
|
1289
1279
|
const pg = isPostgres();
|
|
1280
|
+
const SWEEP_BATCH = 500;
|
|
1281
|
+
const IN_CHUNK = 200;
|
|
1290
1282
|
|
|
1291
1283
|
let sessionRows: Array<{
|
|
1292
1284
|
session_id?: unknown;
|
|
@@ -1295,7 +1287,7 @@ async function sweepOrphanedResumableSessions(): Promise<void> {
|
|
|
1295
1287
|
}> = [];
|
|
1296
1288
|
try {
|
|
1297
1289
|
const probe = await exec.execute({
|
|
1298
|
-
sql: `SELECT session_id, key, updated_at FROM application_state WHERE key LIKE 'resumable-session-%'`,
|
|
1290
|
+
sql: `SELECT session_id, key, updated_at FROM application_state WHERE key LIKE 'resumable-session-%' ORDER BY updated_at ASC LIMIT ${SWEEP_BATCH}`,
|
|
1299
1291
|
args: [],
|
|
1300
1292
|
});
|
|
1301
1293
|
sessionRows =
|
|
@@ -1326,8 +1318,15 @@ async function sweepOrphanedResumableSessions(): Promise<void> {
|
|
|
1326
1318
|
const staleInProgressIso = new Date(
|
|
1327
1319
|
Date.now() - 24 * 60 * 60 * 1000,
|
|
1328
1320
|
).toISOString();
|
|
1329
|
-
let totalDeleted = 0;
|
|
1330
1321
|
|
|
1322
|
+
// Parse candidate rows and collect the referenced recording ids so they can
|
|
1323
|
+
// be resolved in a few batched lookups instead of one query per session.
|
|
1324
|
+
const candidates: Array<{
|
|
1325
|
+
key: string;
|
|
1326
|
+
recordingId: string;
|
|
1327
|
+
sessionUpdatedAt: string;
|
|
1328
|
+
}> = [];
|
|
1329
|
+
const recordingIds = new Set<string>();
|
|
1331
1330
|
for (const row of sessionRows) {
|
|
1332
1331
|
const key = typeof row.key === "string" ? row.key : "";
|
|
1333
1332
|
if (!key.startsWith(prefix)) continue;
|
|
@@ -1343,78 +1342,124 @@ async function sweepOrphanedResumableSessions(): Promise<void> {
|
|
|
1343
1342
|
Number.isFinite(sessionUpdatedAtMs) && sessionUpdatedAtMs > 0
|
|
1344
1343
|
? new Date(sessionUpdatedAtMs).toISOString()
|
|
1345
1344
|
: "";
|
|
1345
|
+
candidates.push({ key, recordingId, sessionUpdatedAt });
|
|
1346
|
+
recordingIds.add(recordingId);
|
|
1347
|
+
}
|
|
1348
|
+
if (candidates.length === 0) return;
|
|
1346
1349
|
|
|
1347
|
-
|
|
1350
|
+
// Resolve every referenced recording in chunked `IN (...)` lookups.
|
|
1351
|
+
const recordingById = new Map<
|
|
1352
|
+
string,
|
|
1353
|
+
{ status?: string; updatedAt?: string }
|
|
1354
|
+
>();
|
|
1355
|
+
const idList = [...recordingIds];
|
|
1356
|
+
for (let i = 0; i < idList.length; i += IN_CHUNK) {
|
|
1357
|
+
const chunk = idList.slice(i, i + IN_CHUNK);
|
|
1358
|
+
const placeholders = chunk
|
|
1359
|
+
.map((_, j) => (pg ? `$${j + 1}` : "?"))
|
|
1360
|
+
.join(", ");
|
|
1348
1361
|
try {
|
|
1349
1362
|
const probe = await exec.execute({
|
|
1350
|
-
sql:
|
|
1351
|
-
|
|
1352
|
-
: `SELECT status, updated_at FROM recordings WHERE id = ? LIMIT 1`,
|
|
1353
|
-
args: [recordingId],
|
|
1363
|
+
sql: `SELECT id, status, updated_at FROM recordings WHERE id IN (${placeholders})`,
|
|
1364
|
+
args: chunk,
|
|
1354
1365
|
});
|
|
1355
|
-
const
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
shouldSweep = true;
|
|
1365
|
-
} else if (
|
|
1366
|
-
(recording.status === "uploading" ||
|
|
1367
|
-
recording.status === "processing") &&
|
|
1368
|
-
(sessionUpdatedAt || recording.updated_at || "") < staleInProgressIso
|
|
1369
|
-
) {
|
|
1370
|
-
try {
|
|
1371
|
-
await exec.execute({
|
|
1372
|
-
sql: pg
|
|
1373
|
-
? `UPDATE recordings SET status = 'failed', failure_reason = $1, updated_at = $2 WHERE id = $3 AND status = $4`
|
|
1374
|
-
: `UPDATE recordings SET status = 'failed', failure_reason = ?, updated_at = ? WHERE id = ? AND status = ?`,
|
|
1375
|
-
args: [
|
|
1376
|
-
"Upload did not finish before the resumable upload cleanup window.",
|
|
1377
|
-
new Date().toISOString(),
|
|
1378
|
-
recordingId,
|
|
1379
|
-
recording.status,
|
|
1380
|
-
],
|
|
1366
|
+
for (const rec of probe.rows as Array<{
|
|
1367
|
+
id?: string;
|
|
1368
|
+
status?: string;
|
|
1369
|
+
updated_at?: string;
|
|
1370
|
+
}>) {
|
|
1371
|
+
if (typeof rec.id === "string") {
|
|
1372
|
+
recordingById.set(rec.id, {
|
|
1373
|
+
status: rec.status,
|
|
1374
|
+
updatedAt: rec.updated_at,
|
|
1381
1375
|
});
|
|
1382
|
-
} catch (err) {
|
|
1383
|
-
console.warn(
|
|
1384
|
-
"[db] resumable-session sweep: stale upload mark-failed failed",
|
|
1385
|
-
{
|
|
1386
|
-
recordingId,
|
|
1387
|
-
status: recording.status,
|
|
1388
|
-
err: (err as Error)?.message ?? err,
|
|
1389
|
-
},
|
|
1390
|
-
);
|
|
1391
1376
|
}
|
|
1392
|
-
shouldSweep = true;
|
|
1393
1377
|
}
|
|
1394
1378
|
} catch (err) {
|
|
1395
|
-
console.warn(
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1379
|
+
console.warn(
|
|
1380
|
+
"[db] resumable-session sweep: recordings batch probe failed",
|
|
1381
|
+
(err as Error)?.message ?? err,
|
|
1382
|
+
);
|
|
1383
|
+
return;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
// Decide sweeps in memory, then mark stale uploads failed and batch-delete.
|
|
1388
|
+
const keysToDelete = new Set<string>();
|
|
1389
|
+
const staleIdsByStatus = new Map<string, Set<string>>();
|
|
1390
|
+
for (const candidate of candidates) {
|
|
1391
|
+
const recording = recordingById.get(candidate.recordingId);
|
|
1392
|
+
if (!recording) {
|
|
1393
|
+
keysToDelete.add(candidate.key);
|
|
1399
1394
|
continue;
|
|
1400
1395
|
}
|
|
1396
|
+
const status = recording.status;
|
|
1397
|
+
if (
|
|
1398
|
+
(status === "ready" || status === "failed") &&
|
|
1399
|
+
(recording.updatedAt ?? "") < oneHourAgoIso
|
|
1400
|
+
) {
|
|
1401
|
+
keysToDelete.add(candidate.key);
|
|
1402
|
+
} else if (
|
|
1403
|
+
(status === "uploading" || status === "processing") &&
|
|
1404
|
+
(candidate.sessionUpdatedAt || recording.updatedAt || "") <
|
|
1405
|
+
staleInProgressIso
|
|
1406
|
+
) {
|
|
1407
|
+
const bucket = staleIdsByStatus.get(status) ?? new Set<string>();
|
|
1408
|
+
bucket.add(candidate.recordingId);
|
|
1409
|
+
staleIdsByStatus.set(status, bucket);
|
|
1410
|
+
keysToDelete.add(candidate.key);
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1401
1413
|
|
|
1402
|
-
|
|
1414
|
+
// Mark stale in-progress uploads failed, one chunked `IN (...)` update per
|
|
1415
|
+
// status. The `status = ?` guard keeps a recording that concurrently
|
|
1416
|
+
// advanced out of that status from being clobbered back to failed.
|
|
1417
|
+
const staleReason =
|
|
1418
|
+
"Upload did not finish before the resumable upload cleanup window.";
|
|
1419
|
+
for (const [status, idSet] of staleIdsByStatus) {
|
|
1420
|
+
const ids = [...idSet];
|
|
1421
|
+
for (let i = 0; i < ids.length; i += IN_CHUNK) {
|
|
1422
|
+
const chunk = ids.slice(i, i + IN_CHUNK);
|
|
1423
|
+
const idPlaceholders = chunk
|
|
1424
|
+
.map((_, j) => (pg ? `$${j + 3}` : "?"))
|
|
1425
|
+
.join(", ");
|
|
1426
|
+
const statusPlaceholder = pg ? `$${chunk.length + 3}` : "?";
|
|
1427
|
+
try {
|
|
1428
|
+
await exec.execute({
|
|
1429
|
+
sql: `UPDATE recordings SET status = 'failed', failure_reason = ${pg ? "$1" : "?"}, updated_at = ${pg ? "$2" : "?"} WHERE id IN (${idPlaceholders}) AND status = ${statusPlaceholder}`,
|
|
1430
|
+
args: [staleReason, new Date().toISOString(), ...chunk, status],
|
|
1431
|
+
});
|
|
1432
|
+
} catch (err) {
|
|
1433
|
+
console.warn(
|
|
1434
|
+
"[db] resumable-session sweep: stale upload mark-failed failed",
|
|
1435
|
+
{
|
|
1436
|
+
status,
|
|
1437
|
+
recordingIds: chunk,
|
|
1438
|
+
err: (err as Error)?.message ?? err,
|
|
1439
|
+
},
|
|
1440
|
+
);
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1403
1444
|
|
|
1445
|
+
let totalDeleted = 0;
|
|
1446
|
+
const deleteKeys = [...keysToDelete];
|
|
1447
|
+
for (let i = 0; i < deleteKeys.length; i += IN_CHUNK) {
|
|
1448
|
+
const chunk = deleteKeys.slice(i, i + IN_CHUNK);
|
|
1449
|
+
const placeholders = chunk
|
|
1450
|
+
.map((_, j) => (pg ? `$${j + 1}` : "?"))
|
|
1451
|
+
.join(", ");
|
|
1404
1452
|
try {
|
|
1405
1453
|
await exec.execute({
|
|
1406
|
-
sql:
|
|
1407
|
-
|
|
1408
|
-
: `DELETE FROM application_state WHERE session_id = ? AND key = ?`,
|
|
1409
|
-
args: [String(row.session_id ?? ""), key],
|
|
1454
|
+
sql: `DELETE FROM application_state WHERE key IN (${placeholders})`,
|
|
1455
|
+
args: chunk,
|
|
1410
1456
|
});
|
|
1411
|
-
totalDeleted +=
|
|
1457
|
+
totalDeleted += chunk.length;
|
|
1412
1458
|
} catch (err) {
|
|
1413
|
-
console.warn(
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
});
|
|
1459
|
+
console.warn(
|
|
1460
|
+
"[db] resumable-session sweep: batch delete failed",
|
|
1461
|
+
(err as Error)?.message ?? err,
|
|
1462
|
+
);
|
|
1418
1463
|
}
|
|
1419
1464
|
}
|
|
1420
1465
|
|
|
@@ -40,6 +40,33 @@ export interface DocumentUpdateConflictResponse {
|
|
|
40
40
|
document: DocumentUpdateResponse;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
const documentAuditOwner = Symbol("documentAuditOwner");
|
|
44
|
+
|
|
45
|
+
type DocumentAuditScopedResult = {
|
|
46
|
+
[documentAuditOwner]?: string;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
function scopeDocumentAudit<T extends object>(result: T, ownerEmail: string) {
|
|
50
|
+
Object.defineProperty(result, documentAuditOwner, { value: ownerEmail });
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function isFavoriteOnlyUpdate(args: {
|
|
55
|
+
isFavorite?: boolean;
|
|
56
|
+
title?: string;
|
|
57
|
+
content?: string;
|
|
58
|
+
description?: string;
|
|
59
|
+
icon?: string | null;
|
|
60
|
+
}) {
|
|
61
|
+
return (
|
|
62
|
+
args.isFavorite !== undefined &&
|
|
63
|
+
args.title === undefined &&
|
|
64
|
+
args.content === undefined &&
|
|
65
|
+
args.description === undefined &&
|
|
66
|
+
args.icon === undefined
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
43
70
|
function nanoid(size = 12): string {
|
|
44
71
|
const chars =
|
|
45
72
|
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
@@ -301,6 +328,29 @@ export default defineAction({
|
|
|
301
328
|
.default([])
|
|
302
329
|
.describe("Exact item versions that influenced this agent update."),
|
|
303
330
|
}),
|
|
331
|
+
audit: {
|
|
332
|
+
// Document bodies and personal favorite preferences are both sensitive.
|
|
333
|
+
// Keep actor/target/outcome attribution without copying mutation payloads
|
|
334
|
+
// into an owner-visible audit row.
|
|
335
|
+
recordInputs: false,
|
|
336
|
+
target: (args, result) => {
|
|
337
|
+
const favoriteOnly = isFavoriteOnlyUpdate(args);
|
|
338
|
+
return {
|
|
339
|
+
type: "document",
|
|
340
|
+
id: args.id,
|
|
341
|
+
// Favorites are a private preference owned by the actor, even when
|
|
342
|
+
// the underlying document belongs to somebody else.
|
|
343
|
+
ownerEmail: favoriteOnly
|
|
344
|
+
? undefined
|
|
345
|
+
: (result as DocumentAuditScopedResult | null)?.[documentAuditOwner],
|
|
346
|
+
visibility: "private",
|
|
347
|
+
};
|
|
348
|
+
},
|
|
349
|
+
summary: (args, result) =>
|
|
350
|
+
(result as DocumentUpdateConflictResponse | null)?.conflict
|
|
351
|
+
? `Document update conflicted for ${args.id}`
|
|
352
|
+
: `Updated document ${args.id}`,
|
|
353
|
+
},
|
|
304
354
|
run: async (
|
|
305
355
|
args,
|
|
306
356
|
ctx,
|
|
@@ -315,12 +365,7 @@ export default defineAction({
|
|
|
315
365
|
const isAgentCaller =
|
|
316
366
|
ctx?.caller === "tool" || ctx?.caller === "mcp" || ctx?.caller === "a2a";
|
|
317
367
|
|
|
318
|
-
const favoriteOnly =
|
|
319
|
-
args.isFavorite !== undefined &&
|
|
320
|
-
args.title === undefined &&
|
|
321
|
-
args.content === undefined &&
|
|
322
|
-
args.description === undefined &&
|
|
323
|
-
args.icon === undefined;
|
|
368
|
+
const favoriteOnly = isFavoriteOnlyUpdate(args);
|
|
324
369
|
const access = favoriteOnly
|
|
325
370
|
? await resolveContentDocumentAccess(id)
|
|
326
371
|
: await assertAccess("document", id, "editor");
|
|
@@ -411,6 +456,11 @@ export default defineAction({
|
|
|
411
456
|
args.title !== undefined && args.title !== existing.title;
|
|
412
457
|
const contentChanged =
|
|
413
458
|
content !== undefined && content !== existing.content;
|
|
459
|
+
const clearsNonEmptyContent =
|
|
460
|
+
contentChanged &&
|
|
461
|
+
content !== undefined &&
|
|
462
|
+
isEffectivelyEmptyDocumentContent(content) &&
|
|
463
|
+
!isEffectivelyEmptyDocumentContent(existing.content);
|
|
414
464
|
const iconChanged = args.icon !== undefined && args.icon !== existing.icon;
|
|
415
465
|
const favoriteChanged =
|
|
416
466
|
args.isFavorite !== undefined && args.isFavorite !== currentFavorite;
|
|
@@ -426,40 +476,6 @@ export default defineAction({
|
|
|
426
476
|
favoriteChanged ||
|
|
427
477
|
descriptionChanged;
|
|
428
478
|
|
|
429
|
-
// Snapshot the current state before applying content/title changes.
|
|
430
|
-
// Versions are scoped to the document owner, not the caller — an editor
|
|
431
|
-
// share collaborator shouldn't create a phantom version row under their
|
|
432
|
-
// own email.
|
|
433
|
-
if (titleChanged || contentChanged) {
|
|
434
|
-
const [latestVersion] = await db
|
|
435
|
-
.select({ createdAt: schema.documentVersions.createdAt })
|
|
436
|
-
.from(schema.documentVersions)
|
|
437
|
-
.where(
|
|
438
|
-
and(
|
|
439
|
-
eq(schema.documentVersions.documentId, id),
|
|
440
|
-
eq(schema.documentVersions.ownerEmail, ownerEmail),
|
|
441
|
-
),
|
|
442
|
-
)
|
|
443
|
-
.orderBy(desc(schema.documentVersions.createdAt))
|
|
444
|
-
.limit(1);
|
|
445
|
-
|
|
446
|
-
const shouldSnapshot =
|
|
447
|
-
!latestVersion ||
|
|
448
|
-
Date.now() - new Date(latestVersion.createdAt).getTime() >
|
|
449
|
-
SNAPSHOT_INTERVAL_MS;
|
|
450
|
-
|
|
451
|
-
if (shouldSnapshot) {
|
|
452
|
-
await db.insert(schema.documentVersions).values({
|
|
453
|
-
id: nanoid(),
|
|
454
|
-
ownerEmail,
|
|
455
|
-
documentId: id,
|
|
456
|
-
title: existing.title,
|
|
457
|
-
content: existing.content,
|
|
458
|
-
createdAt: new Date().toISOString(),
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
|
|
463
479
|
let softDeletedDatabaseIds: string[] = [];
|
|
464
480
|
let creativeContext:
|
|
465
481
|
| Awaited<ReturnType<typeof documentMutationCreativeContext>>
|
|
@@ -507,6 +523,36 @@ export default defineAction({
|
|
|
507
523
|
.where(eq(schema.documents.id, id));
|
|
508
524
|
}
|
|
509
525
|
|
|
526
|
+
if (titleChanged || contentChanged) {
|
|
527
|
+
const [latestVersion] = await tx
|
|
528
|
+
.select({ createdAt: schema.documentVersions.createdAt })
|
|
529
|
+
.from(schema.documentVersions)
|
|
530
|
+
.where(
|
|
531
|
+
and(
|
|
532
|
+
eq(schema.documentVersions.documentId, id),
|
|
533
|
+
eq(schema.documentVersions.ownerEmail, ownerEmail),
|
|
534
|
+
),
|
|
535
|
+
)
|
|
536
|
+
.orderBy(desc(schema.documentVersions.createdAt))
|
|
537
|
+
.limit(1);
|
|
538
|
+
const shouldSnapshot =
|
|
539
|
+
clearsNonEmptyContent ||
|
|
540
|
+
!latestVersion ||
|
|
541
|
+
Date.now() - new Date(latestVersion.createdAt).getTime() >
|
|
542
|
+
SNAPSHOT_INTERVAL_MS;
|
|
543
|
+
|
|
544
|
+
if (shouldSnapshot) {
|
|
545
|
+
await tx.insert(schema.documentVersions).values({
|
|
546
|
+
id: nanoid(),
|
|
547
|
+
ownerEmail,
|
|
548
|
+
documentId: id,
|
|
549
|
+
title: existing.title,
|
|
550
|
+
content: existing.content,
|
|
551
|
+
createdAt: new Date().toISOString(),
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
510
556
|
if (favoriteChanged) {
|
|
511
557
|
await setFavoriteMembership({
|
|
512
558
|
db: tx,
|
|
@@ -580,30 +626,35 @@ export default defineAction({
|
|
|
580
626
|
.select()
|
|
581
627
|
.from(schema.documents)
|
|
582
628
|
.where(eq(schema.documents.id, id));
|
|
583
|
-
return
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
629
|
+
return scopeDocumentAudit(
|
|
630
|
+
{
|
|
631
|
+
conflict: true,
|
|
632
|
+
id,
|
|
633
|
+
document: {
|
|
634
|
+
id: current.id,
|
|
635
|
+
urlPath: `/page/${current.id}`,
|
|
636
|
+
parentId: current.parentId,
|
|
637
|
+
title: current.title,
|
|
638
|
+
content: current.content,
|
|
639
|
+
description: current.description,
|
|
640
|
+
icon: current.icon,
|
|
641
|
+
position: current.position,
|
|
642
|
+
isFavorite: currentFavorite,
|
|
643
|
+
hideFromSearch: parseDocumentHideFromSearch(
|
|
644
|
+
current.hideFromSearch,
|
|
645
|
+
),
|
|
646
|
+
visibility: current.visibility,
|
|
647
|
+
accessRole: access.role,
|
|
648
|
+
canEdit: canEditRole(access.role),
|
|
649
|
+
canManage: canManageRole(access.role),
|
|
650
|
+
createdAt: current.createdAt,
|
|
651
|
+
updatedAt: current.updatedAt,
|
|
652
|
+
source: serializeDocumentSource(current),
|
|
653
|
+
softDeletedDatabaseIds: [],
|
|
654
|
+
},
|
|
655
|
+
} satisfies DocumentUpdateConflictResponse,
|
|
656
|
+
ownerEmail,
|
|
657
|
+
);
|
|
607
658
|
}
|
|
608
659
|
|
|
609
660
|
if (contentChanged) {
|
|
@@ -665,32 +716,35 @@ export default defineAction({
|
|
|
665
716
|
|
|
666
717
|
await writeAppState("refresh-signal", { ts: Date.now() });
|
|
667
718
|
|
|
668
|
-
return
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
719
|
+
return scopeDocumentAudit(
|
|
720
|
+
{
|
|
721
|
+
id: doc.id,
|
|
722
|
+
urlPath: `/page/${doc.id}`,
|
|
723
|
+
parentId: doc.parentId,
|
|
724
|
+
title: doc.title,
|
|
725
|
+
content: doc.content,
|
|
726
|
+
description: doc.description,
|
|
727
|
+
icon: doc.icon,
|
|
728
|
+
position: doc.position,
|
|
729
|
+
isFavorite: finalFavorite,
|
|
730
|
+
hideFromSearch: parseDocumentHideFromSearch(doc.hideFromSearch),
|
|
731
|
+
visibility: doc.visibility,
|
|
732
|
+
accessRole: access.role,
|
|
733
|
+
canEdit: canEditRole(access.role),
|
|
734
|
+
canManage: canManageRole(access.role),
|
|
735
|
+
createdAt: doc.createdAt,
|
|
736
|
+
updatedAt: doc.updatedAt,
|
|
737
|
+
source: serializeDocumentSource(doc),
|
|
738
|
+
softDeletedDatabaseIds,
|
|
739
|
+
...(creativeContext
|
|
740
|
+
? {
|
|
741
|
+
contextMode: creativeContext.contextMode,
|
|
742
|
+
contextPackId: creativeContext.contextPackId,
|
|
743
|
+
reuseLabels: creativeContext.reuseLabels,
|
|
744
|
+
}
|
|
745
|
+
: {}),
|
|
746
|
+
} satisfies DocumentUpdateResponse,
|
|
747
|
+
ownerEmail,
|
|
748
|
+
);
|
|
695
749
|
},
|
|
696
750
|
});
|
|
@@ -28,6 +28,7 @@ interface CommentComposerProps {
|
|
|
28
28
|
members: MentionMember[];
|
|
29
29
|
placeholder?: string;
|
|
30
30
|
autoFocus?: boolean;
|
|
31
|
+
disabled?: boolean;
|
|
31
32
|
rows?: number;
|
|
32
33
|
className?: string;
|
|
33
34
|
}
|
|
@@ -52,6 +53,7 @@ export const CommentComposer = forwardRef<
|
|
|
52
53
|
members,
|
|
53
54
|
placeholder,
|
|
54
55
|
autoFocus,
|
|
56
|
+
disabled = false,
|
|
55
57
|
rows = 2,
|
|
56
58
|
className,
|
|
57
59
|
},
|
|
@@ -158,6 +160,7 @@ export const CommentComposer = forwardRef<
|
|
|
158
160
|
<textarea
|
|
159
161
|
ref={setRefs}
|
|
160
162
|
value={value}
|
|
163
|
+
disabled={disabled}
|
|
161
164
|
rows={rows}
|
|
162
165
|
onChange={(e) => {
|
|
163
166
|
onChange(e.target.value);
|
|
@@ -177,7 +180,7 @@ export const CommentComposer = forwardRef<
|
|
|
177
180
|
"w-full resize-none bg-transparent text-sm placeholder:text-muted-foreground focus:outline-none"
|
|
178
181
|
}
|
|
179
182
|
/>
|
|
180
|
-
{menuOpen && (
|
|
183
|
+
{!disabled && menuOpen && (
|
|
181
184
|
<div className="absolute left-0 right-0 top-full z-20 mt-1 overflow-hidden rounded-md border border-border bg-popover py-1 shadow-md">
|
|
182
185
|
{filtered.map((member, i) => (
|
|
183
186
|
<button
|