@agent-native/core 0.124.3 → 0.124.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/README.md +1 -1
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +10 -0
- package/corpus/core/docs/content/cloneable-saas.mdx +9 -9
- package/corpus/core/docs/content/creating-templates.mdx +2 -2
- package/corpus/core/docs/content/deployment.mdx +23 -0
- package/corpus/core/docs/content/faq.mdx +4 -4
- package/corpus/core/docs/content/key-concepts.mdx +1 -1
- package/corpus/core/docs/content/multi-app-workspace.mdx +1 -1
- package/corpus/core/docs/content/syncing-template-changes.mdx +1 -1
- package/corpus/core/docs/content/template-analytics-developers.mdx +2 -2
- package/corpus/core/docs/content/template-analytics.mdx +2 -2
- package/corpus/core/docs/content/template-assets-developers.mdx +3 -3
- package/corpus/core/docs/content/template-assets.mdx +2 -2
- package/corpus/core/docs/content/template-brain-developers.mdx +2 -2
- package/corpus/core/docs/content/template-brain.mdx +1 -1
- package/corpus/core/docs/content/template-calendar-developers.mdx +1 -1
- package/corpus/core/docs/content/template-calendar.mdx +1 -1
- package/corpus/core/docs/content/template-chat.mdx +1 -1
- package/corpus/core/docs/content/template-clips-developers.mdx +4 -4
- package/corpus/core/docs/content/template-clips.mdx +2 -2
- package/corpus/core/docs/content/template-content-developers.mdx +2 -2
- package/corpus/core/docs/content/template-content.mdx +1 -1
- package/corpus/core/docs/content/template-design-brand-and-figma.mdx +1 -1
- package/corpus/core/docs/content/template-design-developers.mdx +2 -2
- package/corpus/core/docs/content/template-design.mdx +2 -2
- package/corpus/core/docs/content/template-dispatch-developers.mdx +5 -5
- package/corpus/core/docs/content/template-forms-developers.mdx +1 -1
- package/corpus/core/docs/content/template-forms.mdx +1 -1
- package/corpus/core/docs/content/template-mail-developers.mdx +2 -2
- package/corpus/core/docs/content/template-mail.mdx +2 -2
- package/corpus/core/docs/content/template-plan-developers.mdx +3 -3
- package/corpus/core/docs/content/template-plan.mdx +3 -3
- package/corpus/core/docs/content/template-slides-developers.mdx +4 -4
- package/corpus/core/docs/content/template-slides.mdx +1 -1
- package/corpus/core/docs/content/what-is-agent-native.mdx +5 -5
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/auth-policy.ts +1 -1
- package/corpus/core/src/agent/production-agent.ts +14 -1
- package/corpus/core/src/agent/run-manager.ts +6 -13
- package/corpus/core/src/cli/index.ts +11 -1
- package/corpus/core/src/client/route-chunk-recovery.ts +18 -7
- package/corpus/core/src/db/client.ts +7 -6
- package/corpus/core/src/db/migrations.ts +2 -1
- package/corpus/core/src/deploy/build.ts +290 -4
- package/corpus/core/src/deploy/nitro-preset.ts +50 -0
- package/corpus/core/src/integrations/pending-tasks-retry-job.ts +2 -1
- package/corpus/core/src/scripts/call-agent.ts +4 -2
- package/corpus/core/src/server/agent-discovery.ts +1 -0
- package/corpus/core/src/server/agent-run-context.ts +13 -3
- package/corpus/core/src/server/request-context.ts +2 -0
- package/corpus/core/src/shared/cloudflare-globals.d.ts +2 -1
- package/corpus/core/src/shared/runtime.ts +2 -0
- package/corpus/core/src/templates/default/.agents/skills/secrets/SKILL.md +29 -0
- package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/de-DE.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/en-US.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/es-ES.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +6 -6
- package/corpus/core/src/templates/headless/.agents/skills/secrets/SKILL.md +29 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +29 -0
- package/corpus/core/src/vite/client.ts +20 -1
- package/corpus/templates/analytics/actions/restore-dashboard-revision.ts +9 -2
- package/corpus/templates/analytics/app/components/dashboard/DashboardHistoryPanel.tsx +3 -0
- package/corpus/templates/analytics/app/components/dashboard/DashboardPanelSkeleton.tsx +1 -1
- package/corpus/templates/analytics/app/global.css +10 -9
- package/corpus/templates/analytics/app/hooks/use-chart-tooltip-portal.ts +59 -18
- package/corpus/templates/analytics/app/hooks/use-dashboard-revisions.ts +14 -2
- package/corpus/templates/analytics/app/i18n-data.ts +102 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +232 -2
- package/corpus/templates/analytics/changelog/2026-07-27-chart-tooltips-stay-beside-the-cursor-when-they-extend-beyon.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-27-chat-no-longer-claims-a-data-source-is-disconnected-when-it-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-27-dashboard-changes-can-be-undone-with-cmd-z-and-actions-menu.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-27-dashboard-redo-with-cmd-shift-z-and-actions-menu.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-27-dashboard-skeletons-are-subtler-and-smoother.md +6 -0
- package/corpus/templates/analytics/server/lib/dashboards-store.ts +61 -20
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +1 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +7 -3
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +7 -32
- package/corpus/templates/calendar/changelog/2026-07-27-calendar-s-sidebar-now-uses-a-cleaner-layout-with-fewer-util.md +6 -0
- package/corpus/templates/content/app/components/editor/database/sidebar.tsx +14 -6
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +32 -37
- package/corpus/templates/content/changelog/2026-07-27-content-sidebar-page-lists-now-load-with-quiet-skeletons-and.md +6 -0
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +16 -18
- package/corpus/templates/design/changelog/2026-07-27-collapsed-sidebar-keeps-the-agent-native-logo.md +6 -0
- package/corpus/templates/dispatch/AGENTS.md +7 -2
- package/corpus/templates/dispatch/actions/view-screen.ts +3 -2
- package/corpus/templates/dispatch/changelog/2026-07-17-curated-template-remixes.md +1 -1
- package/corpus/templates/dispatch/changelog/2026-07-27-creating-an-app-from-a-curated-template-now-uses-clearer-mor.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-07-27-thread-debug-accepts-request-run-ids.md +6 -0
- package/corpus/templates/slides/actions/create-design-system.ts +10 -2
- package/corpus/templates/slides/actions/import-file.ts +173 -1
- package/corpus/templates/slides/actions/list-slide-comments.ts +16 -1
- package/corpus/templates/slides/actions/update-design-system.ts +13 -2
- package/corpus/templates/slides/app/components/editor/AssetLibraryPanel.tsx +35 -12
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +36 -0
- package/corpus/templates/slides/app/i18n/en-US.ts +3 -0
- package/corpus/templates/slides/app/lib/dynamic-import.ts +63 -0
- package/corpus/templates/slides/app/lib/export-pdf-client.ts +3 -2
- package/corpus/templates/slides/app/lib/export-pptx-client.ts +5 -2
- package/corpus/templates/slides/app/pages/DesignSystems.tsx +9 -1
- package/corpus/templates/slides/server/db/schema.ts +11 -0
- package/corpus/templates/slides/server/handlers/assets.ts +64 -19
- package/corpus/templates/slides/server/handlers/import/html-converter.ts +38 -0
- package/corpus/templates/slides/server/plugins/db.ts +20 -0
- package/corpus/templates/slides/shared/design-system-validation.ts +62 -0
- package/dist/a2a/auth-policy.js +1 -1
- package/dist/a2a/auth-policy.js.map +1 -1
- package/dist/agent/production-agent.d.ts +1 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +12 -1
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts +2 -0
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +4 -10
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/cli/index.js +8 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/client/route-chunk-recovery.d.ts.map +1 -1
- package/dist/client/route-chunk-recovery.js +16 -7
- package/dist/client/route-chunk-recovery.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +4 -2
- package/dist/db/client.js.map +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +2 -1
- package/dist/db/migrations.js.map +1 -1
- package/dist/deploy/build.d.ts +25 -0
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +227 -4
- package/dist/deploy/build.js.map +1 -1
- package/dist/deploy/nitro-preset.d.ts +8 -0
- package/dist/deploy/nitro-preset.d.ts.map +1 -0
- package/dist/deploy/nitro-preset.js +36 -0
- package/dist/deploy/nitro-preset.js.map +1 -0
- package/dist/integrations/pending-tasks-retry-job.d.ts.map +1 -1
- package/dist/integrations/pending-tasks-retry-job.js +2 -1
- package/dist/integrations/pending-tasks-retry-job.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +3 -3
- 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 +11 -11
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +4 -2
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/agent-discovery.d.ts.map +1 -1
- package/dist/server/agent-discovery.js +1 -0
- package/dist/server/agent-discovery.js.map +1 -1
- package/dist/server/agent-run-context.d.ts.map +1 -1
- package/dist/server/agent-run-context.js +10 -3
- package/dist/server/agent-run-context.js.map +1 -1
- package/dist/server/request-context.d.ts +2 -0
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/request-context.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/runtime.d.ts.map +1 -1
- package/dist/shared/runtime.js +2 -0
- package/dist/shared/runtime.js.map +1 -1
- package/dist/templates/default/.agents/skills/secrets/SKILL.md +29 -0
- package/dist/templates/default/app/i18n/ar-SA.ts +6 -6
- package/dist/templates/default/app/i18n/de-DE.ts +6 -6
- package/dist/templates/default/app/i18n/en-US.ts +6 -6
- package/dist/templates/default/app/i18n/es-ES.ts +6 -6
- package/dist/templates/default/app/i18n/fr-FR.ts +6 -6
- package/dist/templates/default/app/i18n/hi-IN.ts +6 -6
- package/dist/templates/default/app/i18n/ja-JP.ts +6 -6
- package/dist/templates/default/app/i18n/ko-KR.ts +6 -6
- package/dist/templates/default/app/i18n/pt-BR.ts +6 -6
- package/dist/templates/default/app/i18n/zh-CN.ts +6 -6
- package/dist/templates/default/app/i18n/zh-TW.ts +6 -6
- package/dist/templates/headless/.agents/skills/secrets/SKILL.md +29 -0
- package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +29 -0
- package/dist/vite/client.d.ts +1 -1
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +16 -0
- package/dist/vite/client.js.map +1 -1
- package/docs/content/cloneable-saas.mdx +9 -9
- package/docs/content/creating-templates.mdx +2 -2
- package/docs/content/deployment.mdx +23 -0
- package/docs/content/faq.mdx +4 -4
- package/docs/content/key-concepts.mdx +1 -1
- package/docs/content/multi-app-workspace.mdx +1 -1
- package/docs/content/syncing-template-changes.mdx +1 -1
- package/docs/content/template-analytics-developers.mdx +2 -2
- package/docs/content/template-analytics.mdx +2 -2
- package/docs/content/template-assets-developers.mdx +3 -3
- package/docs/content/template-assets.mdx +2 -2
- package/docs/content/template-brain-developers.mdx +2 -2
- package/docs/content/template-brain.mdx +1 -1
- package/docs/content/template-calendar-developers.mdx +1 -1
- package/docs/content/template-calendar.mdx +1 -1
- package/docs/content/template-chat.mdx +1 -1
- package/docs/content/template-clips-developers.mdx +4 -4
- package/docs/content/template-clips.mdx +2 -2
- package/docs/content/template-content-developers.mdx +2 -2
- package/docs/content/template-content.mdx +1 -1
- package/docs/content/template-design-brand-and-figma.mdx +1 -1
- package/docs/content/template-design-developers.mdx +2 -2
- package/docs/content/template-design.mdx +2 -2
- package/docs/content/template-dispatch-developers.mdx +5 -5
- package/docs/content/template-forms-developers.mdx +1 -1
- package/docs/content/template-forms.mdx +1 -1
- package/docs/content/template-mail-developers.mdx +2 -2
- package/docs/content/template-mail.mdx +2 -2
- package/docs/content/template-plan-developers.mdx +3 -3
- package/docs/content/template-plan.mdx +3 -3
- package/docs/content/template-slides-developers.mdx +4 -4
- package/docs/content/template-slides.mdx +1 -1
- package/docs/content/what-is-agent-native.mdx +5 -5
- package/package.json +1 -1
- package/src/a2a/auth-policy.ts +1 -1
- package/src/agent/production-agent.ts +14 -1
- package/src/agent/run-manager.ts +6 -13
- package/src/cli/index.ts +11 -1
- package/src/client/route-chunk-recovery.ts +18 -7
- package/src/db/client.ts +7 -6
- package/src/db/migrations.ts +2 -1
- package/src/deploy/build.ts +290 -4
- package/src/deploy/nitro-preset.ts +50 -0
- package/src/integrations/pending-tasks-retry-job.ts +2 -1
- package/src/scripts/call-agent.ts +4 -2
- package/src/server/agent-discovery.ts +1 -0
- package/src/server/agent-run-context.ts +13 -3
- package/src/server/request-context.ts +2 -0
- package/src/shared/cloudflare-globals.d.ts +2 -1
- package/src/shared/runtime.ts +2 -0
- package/src/templates/default/.agents/skills/secrets/SKILL.md +29 -0
- package/src/templates/default/app/i18n/ar-SA.ts +6 -6
- package/src/templates/default/app/i18n/de-DE.ts +6 -6
- package/src/templates/default/app/i18n/en-US.ts +6 -6
- package/src/templates/default/app/i18n/es-ES.ts +6 -6
- package/src/templates/default/app/i18n/fr-FR.ts +6 -6
- package/src/templates/default/app/i18n/hi-IN.ts +6 -6
- package/src/templates/default/app/i18n/ja-JP.ts +6 -6
- package/src/templates/default/app/i18n/ko-KR.ts +6 -6
- package/src/templates/default/app/i18n/pt-BR.ts +6 -6
- package/src/templates/default/app/i18n/zh-CN.ts +6 -6
- package/src/templates/default/app/i18n/zh-TW.ts +6 -6
- package/src/templates/headless/.agents/skills/secrets/SKILL.md +29 -0
- package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +29 -0
- package/src/vite/client.ts +20 -1
- /package/corpus/templates/slides/server/routes/api/assets/{[filename].delete.ts → [id].delete.ts} +0 -0
|
@@ -34,6 +34,8 @@ import {
|
|
|
34
34
|
} from "@dnd-kit/core";
|
|
35
35
|
import {
|
|
36
36
|
IconArchive,
|
|
37
|
+
IconArrowBackUp,
|
|
38
|
+
IconArrowForwardUp,
|
|
37
39
|
IconDotsVertical,
|
|
38
40
|
IconEye,
|
|
39
41
|
IconEyeOff,
|
|
@@ -103,6 +105,10 @@ import {
|
|
|
103
105
|
type DashboardPanelChatContextArgs,
|
|
104
106
|
type SelectDashboardPanelOptions,
|
|
105
107
|
} from "@/hooks/use-dashboard-chat-context";
|
|
108
|
+
import {
|
|
109
|
+
useDashboardRevisions,
|
|
110
|
+
useRestoreDashboardRevision,
|
|
111
|
+
} from "@/hooks/use-dashboard-revisions";
|
|
106
112
|
import { useDashboardViews } from "@/hooks/use-dashboard-views";
|
|
107
113
|
import { useUserPref } from "@/hooks/use-user-pref";
|
|
108
114
|
import {
|
|
@@ -584,6 +590,8 @@ function SqlDashboardPageContent({
|
|
|
584
590
|
const [confirmDeleteOpen, setConfirmDeleteOpen] = useState(false);
|
|
585
591
|
const [emailReportOpen, setEmailReportOpen] = useState(false);
|
|
586
592
|
const [historyOpen, setHistoryOpen] = useState(false);
|
|
593
|
+
const [undoRevisionId, setUndoRevisionId] = useState<string | null>(null);
|
|
594
|
+
const [redoRevisionIds, setRedoRevisionIds] = useState<string[]>([]);
|
|
587
595
|
const [dashboardActionsOpen, setDashboardActionsOpen] = useState(false);
|
|
588
596
|
const [contextSheetOpen, setContextSheetOpen] = useState(false);
|
|
589
597
|
const [activeDropSlot, setActiveDropSlot] =
|
|
@@ -593,8 +601,13 @@ function SqlDashboardPageContent({
|
|
|
593
601
|
);
|
|
594
602
|
const viewedDashboardIdRef = useRef<string | null>(null);
|
|
595
603
|
const pendingConfigRef = useRef<DashboardAdoptionHold | null>(null);
|
|
604
|
+
const revisionRestoreInFlightRef = useRef(false);
|
|
596
605
|
const canEdit = !reportScreenshot && resourceCanEdit(resourceAccess);
|
|
597
606
|
const canManage = !reportScreenshot && resourceCanManage(resourceAccess);
|
|
607
|
+
const resetRevisionNavigation = useCallback(() => {
|
|
608
|
+
setUndoRevisionId(null);
|
|
609
|
+
setRedoRevisionIds([]);
|
|
610
|
+
}, []);
|
|
598
611
|
const dashboardColumns = clampDashboardColumns(
|
|
599
612
|
dashboard?.columns ?? DEFAULT_DASHBOARD_COLUMNS,
|
|
600
613
|
);
|
|
@@ -616,6 +629,25 @@ function SqlDashboardPageContent({
|
|
|
616
629
|
);
|
|
617
630
|
const { mutateAsync: archiveDashboardAction } =
|
|
618
631
|
useActionMutation("archive-dashboard");
|
|
632
|
+
const { data: dashboardRevisions } = useDashboardRevisions(
|
|
633
|
+
!reportScreenshot && dashboardId ? dashboardId : null,
|
|
634
|
+
);
|
|
635
|
+
const restoreDashboardRevision = useRestoreDashboardRevision(
|
|
636
|
+
dashboardId ?? "",
|
|
637
|
+
);
|
|
638
|
+
const undoRevisionIndex = undoRevisionId
|
|
639
|
+
? (dashboardRevisions?.findIndex(
|
|
640
|
+
(revision) => revision.id === undoRevisionId,
|
|
641
|
+
) ?? -1)
|
|
642
|
+
: -1;
|
|
643
|
+
const canUndo =
|
|
644
|
+
canEdit &&
|
|
645
|
+
!!dashboardId &&
|
|
646
|
+
!!dashboardRevisions?.length &&
|
|
647
|
+
(undoRevisionId === null ||
|
|
648
|
+
(undoRevisionIndex >= 0 &&
|
|
649
|
+
undoRevisionIndex < dashboardRevisions.length - 1));
|
|
650
|
+
const canRedo = canEdit && !!dashboardId && redoRevisionIds.length > 0;
|
|
619
651
|
|
|
620
652
|
// Refetch the dashboard whenever the `dashboards` source bumps OR any
|
|
621
653
|
// agent action runs. We depend on both because:
|
|
@@ -757,6 +789,9 @@ function SqlDashboardPageContent({
|
|
|
757
789
|
try {
|
|
758
790
|
const parsed = JSON.parse(raw) as SqlDashboardConfig;
|
|
759
791
|
if (parsed && Array.isArray(parsed.panels)) {
|
|
792
|
+
if (!revisionRestoreInFlightRef.current) {
|
|
793
|
+
resetRevisionNavigation();
|
|
794
|
+
}
|
|
760
795
|
holdDashboardConfig();
|
|
761
796
|
setDashboard(parsed);
|
|
762
797
|
updateCachedDashboardConfig(parsed);
|
|
@@ -769,7 +804,13 @@ function SqlDashboardPageContent({
|
|
|
769
804
|
return () => {
|
|
770
805
|
ytext.unobserve(handler);
|
|
771
806
|
};
|
|
772
|
-
}, [
|
|
807
|
+
}, [
|
|
808
|
+
ydoc,
|
|
809
|
+
collabSynced,
|
|
810
|
+
holdDashboardConfig,
|
|
811
|
+
resetRevisionNavigation,
|
|
812
|
+
updateCachedDashboardConfig,
|
|
813
|
+
]);
|
|
773
814
|
|
|
774
815
|
// Per-user saved filter state
|
|
775
816
|
const filterPrefKey = dashboardId ? `dashboard-filters:${dashboardId}` : "";
|
|
@@ -798,8 +839,10 @@ function SqlDashboardPageContent({
|
|
|
798
839
|
setDashboardUpdatedAt(null);
|
|
799
840
|
setDashboardUpdatedBy(null);
|
|
800
841
|
setResourceAccess(null);
|
|
842
|
+
resetRevisionNavigation();
|
|
843
|
+
revisionRestoreInFlightRef.current = false;
|
|
801
844
|
if (!dashboardId) setLoaded(true);
|
|
802
|
-
}, [dashboardId]);
|
|
845
|
+
}, [dashboardId, resetRevisionNavigation]);
|
|
803
846
|
|
|
804
847
|
useEffect(() => {
|
|
805
848
|
if (!dashboardId || !dashboardQuery.isSuccess) return;
|
|
@@ -817,6 +860,16 @@ function SqlDashboardPageContent({
|
|
|
817
860
|
pendingConfigRef.current = null;
|
|
818
861
|
}
|
|
819
862
|
if (!adoption.adopt) return;
|
|
863
|
+
if (
|
|
864
|
+
loaded &&
|
|
865
|
+
dashboardUpdatedAt &&
|
|
866
|
+
fetched?.updatedAt &&
|
|
867
|
+
fetched.updatedAt !== dashboardUpdatedAt &&
|
|
868
|
+
!revisionRestoreInFlightRef.current &&
|
|
869
|
+
!pendingConfigRef.current
|
|
870
|
+
) {
|
|
871
|
+
resetRevisionNavigation();
|
|
872
|
+
}
|
|
820
873
|
const fetchedConfig = fetched?.config ?? null;
|
|
821
874
|
const fetchedVisibility =
|
|
822
875
|
fetched?.visibility === "private" ||
|
|
@@ -858,6 +911,7 @@ function SqlDashboardPageContent({
|
|
|
858
911
|
dashboardUpdatedAt,
|
|
859
912
|
loaded,
|
|
860
913
|
reportScreenshot,
|
|
914
|
+
resetRevisionNavigation,
|
|
861
915
|
]);
|
|
862
916
|
|
|
863
917
|
// Apply saved filters on initial load if no filter URL params are present
|
|
@@ -982,6 +1036,7 @@ function SqlDashboardPageContent({
|
|
|
982
1036
|
toast.error(t("sqlDashboard.viewOnly"));
|
|
983
1037
|
return;
|
|
984
1038
|
}
|
|
1039
|
+
resetRevisionNavigation();
|
|
985
1040
|
holdDashboardConfig();
|
|
986
1041
|
setDashboard(updated);
|
|
987
1042
|
updateCachedDashboardConfig(updated);
|
|
@@ -1017,6 +1072,7 @@ function SqlDashboardPageContent({
|
|
|
1017
1072
|
holdDashboardConfig,
|
|
1018
1073
|
queryClient,
|
|
1019
1074
|
pushToCollab,
|
|
1075
|
+
resetRevisionNavigation,
|
|
1020
1076
|
t,
|
|
1021
1077
|
updateCachedDashboardConfig,
|
|
1022
1078
|
],
|
|
@@ -1032,6 +1088,7 @@ function SqlDashboardPageContent({
|
|
|
1032
1088
|
if (!canEdit) {
|
|
1033
1089
|
throw new Error(t("sqlDashboard.viewOnly"));
|
|
1034
1090
|
}
|
|
1091
|
+
resetRevisionNavigation();
|
|
1035
1092
|
holdDashboardConfig();
|
|
1036
1093
|
await saveDashboard(dashboardId, updated);
|
|
1037
1094
|
setDashboard(updated);
|
|
@@ -1052,11 +1109,148 @@ function SqlDashboardPageContent({
|
|
|
1052
1109
|
holdDashboardConfig,
|
|
1053
1110
|
queryClient,
|
|
1054
1111
|
pushToCollab,
|
|
1112
|
+
resetRevisionNavigation,
|
|
1055
1113
|
t,
|
|
1056
1114
|
updateCachedDashboardConfig,
|
|
1057
1115
|
],
|
|
1058
1116
|
);
|
|
1059
1117
|
|
|
1118
|
+
const handleUndo = useCallback(async () => {
|
|
1119
|
+
if (
|
|
1120
|
+
!dashboardId ||
|
|
1121
|
+
!canEdit ||
|
|
1122
|
+
!canUndo ||
|
|
1123
|
+
restoreDashboardRevision.isPending
|
|
1124
|
+
) {
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
const revisions = dashboardRevisions ?? [];
|
|
1129
|
+
const targetIndex =
|
|
1130
|
+
undoRevisionId === null ? 0 : Math.max(0, undoRevisionIndex + 1);
|
|
1131
|
+
const targetRevision = revisions[targetIndex];
|
|
1132
|
+
if (!targetRevision) return;
|
|
1133
|
+
|
|
1134
|
+
revisionRestoreInFlightRef.current = true;
|
|
1135
|
+
holdDashboardConfig();
|
|
1136
|
+
try {
|
|
1137
|
+
const restored = await restoreDashboardRevision.mutateAsync({
|
|
1138
|
+
dashboardId,
|
|
1139
|
+
revisionId: targetRevision.id,
|
|
1140
|
+
expectedUpdatedAt: dashboardUpdatedAt ?? undefined,
|
|
1141
|
+
});
|
|
1142
|
+
setUndoRevisionId(targetRevision.id);
|
|
1143
|
+
setRedoRevisionIds((current) => [
|
|
1144
|
+
...current,
|
|
1145
|
+
restored.snapshotRevisionId,
|
|
1146
|
+
]);
|
|
1147
|
+
if (restored?.updatedAt) setDashboardUpdatedAt(restored.updatedAt);
|
|
1148
|
+
toast.success(t("dashboard.undoSuccess"));
|
|
1149
|
+
} catch (error) {
|
|
1150
|
+
resetRevisionNavigation();
|
|
1151
|
+
toast.error(
|
|
1152
|
+
error instanceof Error
|
|
1153
|
+
? t("dashboard.undoFailedWithMessage", { message: error.message })
|
|
1154
|
+
: t("dashboard.undoFailed"),
|
|
1155
|
+
);
|
|
1156
|
+
} finally {
|
|
1157
|
+
revisionRestoreInFlightRef.current = false;
|
|
1158
|
+
}
|
|
1159
|
+
}, [
|
|
1160
|
+
canEdit,
|
|
1161
|
+
canUndo,
|
|
1162
|
+
dashboardId,
|
|
1163
|
+
dashboardRevisions,
|
|
1164
|
+
dashboardUpdatedAt,
|
|
1165
|
+
holdDashboardConfig,
|
|
1166
|
+
restoreDashboardRevision,
|
|
1167
|
+
resetRevisionNavigation,
|
|
1168
|
+
t,
|
|
1169
|
+
undoRevisionId,
|
|
1170
|
+
undoRevisionIndex,
|
|
1171
|
+
]);
|
|
1172
|
+
|
|
1173
|
+
const handleRedo = useCallback(async () => {
|
|
1174
|
+
if (
|
|
1175
|
+
!dashboardId ||
|
|
1176
|
+
!canEdit ||
|
|
1177
|
+
!canRedo ||
|
|
1178
|
+
restoreDashboardRevision.isPending
|
|
1179
|
+
) {
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
const targetRevisionId = redoRevisionIds[redoRevisionIds.length - 1];
|
|
1184
|
+
if (!targetRevisionId) return;
|
|
1185
|
+
|
|
1186
|
+
revisionRestoreInFlightRef.current = true;
|
|
1187
|
+
holdDashboardConfig();
|
|
1188
|
+
try {
|
|
1189
|
+
const restored = await restoreDashboardRevision.mutateAsync({
|
|
1190
|
+
dashboardId,
|
|
1191
|
+
revisionId: targetRevisionId,
|
|
1192
|
+
expectedUpdatedAt: dashboardUpdatedAt ?? undefined,
|
|
1193
|
+
});
|
|
1194
|
+
setRedoRevisionIds((current) => current.slice(0, -1));
|
|
1195
|
+
setUndoRevisionId(null);
|
|
1196
|
+
if (restored?.updatedAt) setDashboardUpdatedAt(restored.updatedAt);
|
|
1197
|
+
toast.success(t("dashboard.redoSuccess"));
|
|
1198
|
+
} catch (error) {
|
|
1199
|
+
resetRevisionNavigation();
|
|
1200
|
+
toast.error(
|
|
1201
|
+
error instanceof Error
|
|
1202
|
+
? t("dashboard.redoFailedWithMessage", { message: error.message })
|
|
1203
|
+
: t("dashboard.redoFailed"),
|
|
1204
|
+
);
|
|
1205
|
+
} finally {
|
|
1206
|
+
revisionRestoreInFlightRef.current = false;
|
|
1207
|
+
}
|
|
1208
|
+
}, [
|
|
1209
|
+
canEdit,
|
|
1210
|
+
canRedo,
|
|
1211
|
+
dashboardId,
|
|
1212
|
+
dashboardUpdatedAt,
|
|
1213
|
+
holdDashboardConfig,
|
|
1214
|
+
redoRevisionIds,
|
|
1215
|
+
resetRevisionNavigation,
|
|
1216
|
+
restoreDashboardRevision,
|
|
1217
|
+
t,
|
|
1218
|
+
]);
|
|
1219
|
+
|
|
1220
|
+
useEffect(() => {
|
|
1221
|
+
if (reportScreenshot) return;
|
|
1222
|
+
|
|
1223
|
+
const handleUndoShortcut = (event: KeyboardEvent) => {
|
|
1224
|
+
if (
|
|
1225
|
+
event.defaultPrevented ||
|
|
1226
|
+
!(event.metaKey || event.ctrlKey) ||
|
|
1227
|
+
event.key.toLowerCase() !== "z"
|
|
1228
|
+
) {
|
|
1229
|
+
return;
|
|
1230
|
+
}
|
|
1231
|
+
const target = event.target as HTMLElement | null;
|
|
1232
|
+
if (
|
|
1233
|
+
target?.closest("input, textarea, select, [contenteditable='true']")
|
|
1234
|
+
) {
|
|
1235
|
+
return;
|
|
1236
|
+
}
|
|
1237
|
+
const canHandle = event.shiftKey ? canRedo : canUndo;
|
|
1238
|
+
if (!canHandle || restoreDashboardRevision.isPending) return;
|
|
1239
|
+
event.preventDefault();
|
|
1240
|
+
void (event.shiftKey ? handleRedo() : handleUndo());
|
|
1241
|
+
};
|
|
1242
|
+
|
|
1243
|
+
window.addEventListener("keydown", handleUndoShortcut);
|
|
1244
|
+
return () => window.removeEventListener("keydown", handleUndoShortcut);
|
|
1245
|
+
}, [
|
|
1246
|
+
canUndo,
|
|
1247
|
+
canRedo,
|
|
1248
|
+
handleRedo,
|
|
1249
|
+
handleUndo,
|
|
1250
|
+
reportScreenshot,
|
|
1251
|
+
restoreDashboardRevision.isPending,
|
|
1252
|
+
]);
|
|
1253
|
+
|
|
1060
1254
|
const removePanel = useCallback(
|
|
1061
1255
|
(panelId: string) => {
|
|
1062
1256
|
if (!dashboard) return;
|
|
@@ -1594,6 +1788,41 @@ function SqlDashboardPageContent({
|
|
|
1594
1788
|
{dashboardId ? (
|
|
1595
1789
|
<>
|
|
1596
1790
|
<DropdownMenuSeparator />
|
|
1791
|
+
{canEdit ? (
|
|
1792
|
+
<DropdownMenuItem
|
|
1793
|
+
disabled={!canUndo || restoreDashboardRevision.isPending}
|
|
1794
|
+
aria-keyshortcuts="Meta+Z"
|
|
1795
|
+
onSelect={(event) => {
|
|
1796
|
+
event.preventDefault();
|
|
1797
|
+
setDashboardActionsOpen(false);
|
|
1798
|
+
void handleUndo();
|
|
1799
|
+
}}
|
|
1800
|
+
>
|
|
1801
|
+
<IconArrowBackUp className="mr-2 h-3.5 w-3.5" />
|
|
1802
|
+
{t("dashboard.undo")}
|
|
1803
|
+
<span className="ml-auto text-[10px] text-muted-foreground">
|
|
1804
|
+
⌘Z
|
|
1805
|
+
</span>
|
|
1806
|
+
</DropdownMenuItem>
|
|
1807
|
+
) : null}
|
|
1808
|
+
{canEdit ? (
|
|
1809
|
+
<DropdownMenuItem
|
|
1810
|
+
disabled={!canRedo || restoreDashboardRevision.isPending}
|
|
1811
|
+
aria-keyshortcuts="Meta+Shift+Z"
|
|
1812
|
+
onSelect={(event) => {
|
|
1813
|
+
event.preventDefault();
|
|
1814
|
+
setDashboardActionsOpen(false);
|
|
1815
|
+
void handleRedo();
|
|
1816
|
+
}}
|
|
1817
|
+
>
|
|
1818
|
+
<IconArrowForwardUp className="mr-2 h-3.5 w-3.5" />
|
|
1819
|
+
{t("dashboard.redo")}
|
|
1820
|
+
<span className="ml-auto text-[10px] text-muted-foreground">
|
|
1821
|
+
{/* i18n-ignore keyboard shortcut hint */}
|
|
1822
|
+
⌘⇧Z
|
|
1823
|
+
</span>
|
|
1824
|
+
</DropdownMenuItem>
|
|
1825
|
+
) : null}
|
|
1597
1826
|
<DropdownMenuItem
|
|
1598
1827
|
onSelect={(event) => {
|
|
1599
1828
|
event.preventDefault();
|
|
@@ -1696,6 +1925,7 @@ function SqlDashboardPageContent({
|
|
|
1696
1925
|
open={historyOpen}
|
|
1697
1926
|
onOpenChange={setHistoryOpen}
|
|
1698
1927
|
canRestore={canEdit && !archivedAt}
|
|
1928
|
+
onRestored={resetRevisionNavigation}
|
|
1699
1929
|
/>
|
|
1700
1930
|
) : null}
|
|
1701
1931
|
{dashboardId ? (
|
|
@@ -635,9 +635,10 @@ async function snapshotDashboardRevision(
|
|
|
635
635
|
db: any,
|
|
636
636
|
dashboard: DashboardRecord,
|
|
637
637
|
ctx: AccessCtx,
|
|
638
|
-
): Promise<
|
|
638
|
+
): Promise<string> {
|
|
639
|
+
const id = `dashrev-${Date.now()}-${nanoidFallback()}`;
|
|
639
640
|
await db.insert(schema.dashboardRevisions).values({
|
|
640
|
-
id
|
|
641
|
+
id,
|
|
641
642
|
dashboardId: dashboard.id,
|
|
642
643
|
kind: dashboard.kind,
|
|
643
644
|
title: dashboard.title,
|
|
@@ -648,6 +649,7 @@ async function snapshotDashboardRevision(
|
|
|
648
649
|
orgId: dashboard.orgId,
|
|
649
650
|
});
|
|
650
651
|
await pruneDashboardRevisions(db, dashboard.id);
|
|
652
|
+
return id;
|
|
651
653
|
}
|
|
652
654
|
|
|
653
655
|
/**
|
|
@@ -844,13 +846,23 @@ export async function restoreDashboardRevision(
|
|
|
844
846
|
dashboardId: string,
|
|
845
847
|
revisionId: string,
|
|
846
848
|
ctx: AccessCtx,
|
|
847
|
-
|
|
849
|
+
expectedUpdatedAt?: string,
|
|
850
|
+
): Promise<{
|
|
851
|
+
dashboard: DashboardRecord;
|
|
852
|
+
snapshotRevisionId: string;
|
|
853
|
+
} | null> {
|
|
848
854
|
const existing = await getDashboard(dashboardId, ctx);
|
|
849
855
|
if (!existing) return null;
|
|
850
856
|
await assertAccess("dashboard", dashboardId, "editor", {
|
|
851
857
|
userEmail: ctx.email,
|
|
852
858
|
orgId: ctx.orgId ?? undefined,
|
|
853
859
|
});
|
|
860
|
+
if (
|
|
861
|
+
expectedUpdatedAt !== undefined &&
|
|
862
|
+
existing.updatedAt !== expectedUpdatedAt
|
|
863
|
+
) {
|
|
864
|
+
throw new DashboardConflictError(dashboardId);
|
|
865
|
+
}
|
|
854
866
|
const db = getDb() as any;
|
|
855
867
|
const [revisionRow] = await db
|
|
856
868
|
.select()
|
|
@@ -864,22 +876,51 @@ export async function restoreDashboardRevision(
|
|
|
864
876
|
.limit(1);
|
|
865
877
|
if (!revisionRow) return null;
|
|
866
878
|
const revision = rowToDashboardRevision(revisionRow);
|
|
867
|
-
|
|
868
|
-
await db
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
879
|
+
const updatedAt = nowIso();
|
|
880
|
+
const restored = await db.transaction(async (tx: any) => {
|
|
881
|
+
const updateResult = await tx
|
|
882
|
+
.update(schema.dashboards)
|
|
883
|
+
.set({
|
|
884
|
+
kind: revision.kind,
|
|
885
|
+
title: revision.title,
|
|
886
|
+
config: JSON.stringify(revision.config),
|
|
887
|
+
updatedAt,
|
|
888
|
+
updatedBy: ctx.email,
|
|
889
|
+
})
|
|
890
|
+
.where(
|
|
891
|
+
expectedUpdatedAt === undefined
|
|
892
|
+
? eq(schema.dashboards.id, dashboardId)
|
|
893
|
+
: and(
|
|
894
|
+
eq(schema.dashboards.id, dashboardId),
|
|
895
|
+
eq(schema.dashboards.updatedAt, expectedUpdatedAt),
|
|
896
|
+
),
|
|
897
|
+
);
|
|
898
|
+
if (expectedUpdatedAt !== undefined) {
|
|
899
|
+
const affected = affectedRowCount(updateResult);
|
|
900
|
+
if (affected === undefined) {
|
|
901
|
+
throw new Error(
|
|
902
|
+
"The database driver did not report an affected-row count for the fenced dashboard restore.",
|
|
903
|
+
);
|
|
904
|
+
}
|
|
905
|
+
if (affected === 0) throw new DashboardConflictError(dashboardId);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
const snapshotRevisionId = await snapshotDashboardRevision(
|
|
909
|
+
tx,
|
|
910
|
+
existing,
|
|
911
|
+
ctx,
|
|
912
|
+
);
|
|
913
|
+
const [row] = await tx
|
|
914
|
+
.select()
|
|
915
|
+
.from(schema.dashboards)
|
|
916
|
+
.where(eq(schema.dashboards.id, dashboardId));
|
|
917
|
+
return {
|
|
918
|
+
dashboard: rowToDashboard(row),
|
|
919
|
+
snapshotRevisionId,
|
|
920
|
+
};
|
|
921
|
+
});
|
|
922
|
+
if (!restored) return null;
|
|
923
|
+
const { dashboard } = restored;
|
|
883
924
|
recordScopedChange(
|
|
884
925
|
"dashboards",
|
|
885
926
|
"change",
|
|
@@ -888,7 +929,7 @@ export async function restoreDashboardRevision(
|
|
|
888
929
|
dashboard.orgId,
|
|
889
930
|
dashboard.visibility,
|
|
890
931
|
);
|
|
891
|
-
return
|
|
932
|
+
return restored;
|
|
892
933
|
}
|
|
893
934
|
|
|
894
935
|
/**
|
|
@@ -479,10 +479,14 @@ export function realDataFinalGuard(
|
|
|
479
479
|
);
|
|
480
480
|
const firstPartySourceShouldBeTried =
|
|
481
481
|
noConnectedExternalSources && !externalSourceRequest;
|
|
482
|
+
// Only a `data-source-status` result can show something is missing. A turn
|
|
483
|
+
// that never called it has empty label lists, which is "we did not look",
|
|
484
|
+
// not "nothing is connected" — treating those the same made the guard demand
|
|
485
|
+
// a Connect-data-sources link on turns whose sources were working fine.
|
|
482
486
|
const needsDataSourceLink =
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
487
|
+
sourceStatus.checked &&
|
|
488
|
+
externalSourceRequest &&
|
|
489
|
+
(noConnectedExternalSources || missingRequestedExternalSource);
|
|
486
490
|
if (
|
|
487
491
|
hasFailedCorpusWorkflowEvidence(context.toolResults) &&
|
|
488
492
|
looksLikeCoverageSensitiveAnalyticsRequest(userText) &&
|
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
IconChevronRight,
|
|
17
17
|
IconPlus,
|
|
18
18
|
IconX,
|
|
19
|
-
IconKeyboard,
|
|
20
19
|
IconInfoCircle,
|
|
21
20
|
IconCheck,
|
|
22
21
|
IconEye,
|
|
@@ -46,7 +45,6 @@ import { useState, useEffect, useMemo } from "react";
|
|
|
46
45
|
import { Link, useLocation, useNavigate } from "react-router";
|
|
47
46
|
import { toast } from "sonner";
|
|
48
47
|
|
|
49
|
-
import { ThemeToggle } from "@/components/ThemeToggle";
|
|
50
48
|
import { Button } from "@/components/ui/button";
|
|
51
49
|
import {
|
|
52
50
|
Collapsible,
|
|
@@ -353,7 +351,7 @@ function GoogleConnectSidebarButton() {
|
|
|
353
351
|
}
|
|
354
352
|
|
|
355
353
|
return (
|
|
356
|
-
<div className="
|
|
354
|
+
<div className="p-3">
|
|
357
355
|
<div className="rounded-lg bg-primary/10 p-3">
|
|
358
356
|
<p className="mb-1 text-xs font-semibold text-foreground">
|
|
359
357
|
{t("settings.connectGoogleCalendar")}
|
|
@@ -502,7 +500,7 @@ function GoogleAccountsSection({
|
|
|
502
500
|
}
|
|
503
501
|
|
|
504
502
|
return (
|
|
505
|
-
<div className="
|
|
503
|
+
<div className="px-1.5 py-1.5">
|
|
506
504
|
<div className="mb-1 flex min-h-8 items-center justify-between px-3">
|
|
507
505
|
<div className="flex items-center">
|
|
508
506
|
<span className="text-[11px] font-medium uppercase tracking-wider text-muted-foreground">
|
|
@@ -769,14 +767,14 @@ export function Sidebar({
|
|
|
769
767
|
data-open={open ? "true" : "false"}
|
|
770
768
|
data-collapsed={collapsed ? "true" : "false"}
|
|
771
769
|
className={cn(
|
|
772
|
-
"agent-layout-left-drawer calendar-app-sidebar fixed start-0 top-0 z-50 flex h-full min-w-0 flex-col overflow-hidden
|
|
770
|
+
"agent-layout-left-drawer calendar-app-sidebar fixed start-0 top-0 z-50 flex h-full min-w-0 flex-col overflow-hidden bg-sidebar transition-[width,translate] duration-200 ease-out lg:static",
|
|
773
771
|
collapsed ? "w-12" : "w-56",
|
|
774
772
|
)}
|
|
775
773
|
>
|
|
776
774
|
{/* Logo */}
|
|
777
775
|
<div
|
|
778
776
|
className={cn(
|
|
779
|
-
"flex h-12 shrink-0 items-center justify-between gap-2.5
|
|
777
|
+
"flex h-12 shrink-0 items-center justify-between gap-2.5",
|
|
780
778
|
collapsed ? "px-1" : "px-4",
|
|
781
779
|
)}
|
|
782
780
|
>
|
|
@@ -846,7 +844,7 @@ export function Sidebar({
|
|
|
846
844
|
/>
|
|
847
845
|
|
|
848
846
|
{/* Nav */}
|
|
849
|
-
<nav className="space-y-0.5
|
|
847
|
+
<nav className="space-y-0.5 p-2.5">
|
|
850
848
|
{navItems.map((item) => {
|
|
851
849
|
const isActive =
|
|
852
850
|
item.path === "/"
|
|
@@ -886,7 +884,7 @@ export function Sidebar({
|
|
|
886
884
|
)}
|
|
887
885
|
|
|
888
886
|
{/* Other Calendars — people overlays + external ICS feeds combined */}
|
|
889
|
-
<div className="
|
|
887
|
+
<div className="px-1.5 py-1.5">
|
|
890
888
|
<div className="flex min-h-8 items-center justify-between px-3">
|
|
891
889
|
<div className="flex items-center gap-1">
|
|
892
890
|
<span className="text-[11px] font-medium uppercase tracking-wider text-muted-foreground">
|
|
@@ -1135,7 +1133,7 @@ export function Sidebar({
|
|
|
1135
1133
|
"shrink-0",
|
|
1136
1134
|
collapsed
|
|
1137
1135
|
? "flex flex-col items-center gap-1 px-1 py-2"
|
|
1138
|
-
: "space-y-0.5
|
|
1136
|
+
: "space-y-0.5 p-2.5",
|
|
1139
1137
|
)}
|
|
1140
1138
|
>
|
|
1141
1139
|
{bottomNavItems.map((item) => {
|
|
@@ -1178,29 +1176,6 @@ export function Sidebar({
|
|
|
1178
1176
|
|
|
1179
1177
|
<div className="flex items-center gap-1 px-1.5 py-1.5">
|
|
1180
1178
|
<DevDatabaseLink />
|
|
1181
|
-
<Tooltip>
|
|
1182
|
-
<TooltipTrigger asChild>
|
|
1183
|
-
<Button
|
|
1184
|
-
variant="ghost"
|
|
1185
|
-
size="icon"
|
|
1186
|
-
className="h-8 w-8 text-muted-foreground"
|
|
1187
|
-
onClick={() =>
|
|
1188
|
-
window.dispatchEvent(new Event("calendar:open-shortcuts"))
|
|
1189
|
-
}
|
|
1190
|
-
>
|
|
1191
|
-
<IconKeyboard className="h-4 w-4" />
|
|
1192
|
-
</Button>
|
|
1193
|
-
</TooltipTrigger>
|
|
1194
|
-
<TooltipContent side="top">
|
|
1195
|
-
<p>
|
|
1196
|
-
{t("keyboardShortcuts.title")}{" "}
|
|
1197
|
-
<kbd className="ms-1 rounded border border-border bg-muted px-1 font-mono text-[10px]">
|
|
1198
|
-
?
|
|
1199
|
-
</kbd>
|
|
1200
|
-
</p>
|
|
1201
|
-
</TooltipContent>
|
|
1202
|
-
</Tooltip>
|
|
1203
|
-
<ThemeToggle className="h-8 w-8" />
|
|
1204
1179
|
</div>
|
|
1205
1180
|
</div>
|
|
1206
1181
|
) : null}
|