@agent-native/core 0.120.1 → 0.120.3
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 +29 -0
- package/corpus/core/docs/content/extensions.mdx +23 -4
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +4 -0
- package/corpus/core/src/agent/run-manager.ts +36 -10
- package/corpus/core/src/agent/types.ts +2 -0
- 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 +28 -8
- 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 +24 -0
- package/corpus/core/src/client/settings/SettingsPanel.tsx +10 -0
- package/corpus/core/src/deploy/build.ts +3 -0
- package/corpus/core/src/extensions/theme.ts +1 -1
- package/corpus/core/src/localization/default-messages.ts +2 -0
- package/corpus/core/src/server/analytics.ts +154 -25
- 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 +113 -51
- package/corpus/core/src/templates/chat/app/global.css +1 -1
- package/corpus/core/src/templates/chat/app/routes/extensions._index.tsx +2 -2
- package/corpus/core/src/templates/chat/netlify.toml +1 -0
- package/corpus/core/src/templates/default/app/global.css +1 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +16 -0
- package/corpus/core/src/tracking/error-capture.ts +151 -0
- package/corpus/core/src/tracking/index.ts +5 -0
- package/corpus/core/src/vite/client.ts +6 -0
- package/corpus/templates/analytics/.agents/skills/adhoc-analysis/SKILL.md +27 -43
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +19 -8
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +2 -2
- package/corpus/templates/analytics/AGENTS.md +20 -8
- package/corpus/templates/analytics/actions/get-explorer-dashboard.ts +3 -0
- package/corpus/templates/analytics/actions/list-dashboard-usage-stats.ts +140 -46
- package/corpus/templates/analytics/actions/migrate-analytics-artifacts.ts +48 -0
- package/corpus/templates/analytics/actions/save-analysis.ts +2 -3
- package/corpus/templates/analytics/actions/view-screen.ts +1 -1
- 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/DashboardMetadata.tsx +77 -0
- package/corpus/templates/analytics/app/components/dashboard/DashboardPanelSkeleton.tsx +7 -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/NewDashboardDialog.tsx +1 -0
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +255 -626
- package/corpus/templates/analytics/app/global.css +31 -1
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +2 -2
- package/corpus/templates/analytics/app/i18n-data.ts +80 -0
- package/corpus/templates/analytics/app/lib/dashboard-report-capture.ts +42 -0
- package/corpus/templates/analytics/app/pages/Agents.tsx +49 -2
- 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/explorer-dashboard/index.tsx +54 -11
- 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 +4 -54
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +178 -69
- package/corpus/templates/analytics/app/pages/analyses/AnalysisDetail.tsx +2 -2
- package/corpus/templates/analytics/app/root.tsx +28 -0
- package/corpus/templates/analytics/app/routes/analyses._index.tsx +3 -2
- package/corpus/templates/analytics/app/routes/extensions._index.tsx +2 -2
- package/corpus/templates/analytics/changelog/2026-07-23-analytics-now-groups-saved-analyses-and-embedded-extensions-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-23-dashboard-menus-show-who-created-and-last-updated-each-dashb.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-23-dashboard-usage-now-loads-reliably-for-organizations-with-ma.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-23-long-dashboard-building-requests-now-continue-without-stoppi.md +6 -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/netlify.toml +4 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +1 -1
- package/corpus/templates/analytics/server/db/schema.ts +9 -0
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +21 -0
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +0 -1
- package/corpus/templates/analytics/server/lib/agent-readable-resource-context.ts +1 -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/lib/migrate-analytics-artifacts.ts +1062 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +6 -52
- package/corpus/templates/analytics/server/plugins/core-routes.ts +1 -1
- package/corpus/templates/analytics/server/plugins/db.ts +19 -0
- package/corpus/templates/analytics/shared/dashboard-report-timeouts.ts +1 -1
- package/corpus/templates/assets/actions/generate-image-batch.ts +36 -1
- package/corpus/templates/assets/actions/generate-image.ts +28 -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 +164 -82
- 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/extensions._index.tsx +2 -2
- 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-23-assets-image-generation-now-recovers-after-a-completed-tool-.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/assets/netlify.toml +1 -0
- package/corpus/templates/brain/app/components/layout/Layout.tsx +3 -0
- package/corpus/templates/brain/app/components/layout/Sidebar.tsx +114 -51
- package/corpus/templates/brain/app/global.css +1 -1
- package/corpus/templates/brain/app/routes/extensions._index.tsx +2 -2
- 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/brain/netlify.toml +1 -0
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +110 -57
- package/corpus/templates/calendar/app/global.css +1 -1
- package/corpus/templates/calendar/app/routes/_app.extensions._index.tsx +2 -16
- 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/calendar/netlify.toml +1 -0
- package/corpus/templates/chat/app/components/layout/Layout.tsx +3 -0
- package/corpus/templates/chat/app/components/layout/Sidebar.tsx +113 -51
- package/corpus/templates/chat/app/global.css +1 -1
- package/corpus/templates/chat/app/routes/extensions._index.tsx +2 -2
- 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/chat/netlify.toml +1 -0
- package/corpus/templates/clips/app/components/library/library-layout.tsx +117 -37
- 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/_app.extensions._index.tsx +2 -16
- 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-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-23-meeting-recording-meters-and-dismissed-prompts.md +6 -0
- 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/desktop/src/hooks/useMicMeter.ts +1 -1
- package/corpus/templates/clips/desktop/src/lib/meeting-notification-dismissal.ts +2 -0
- package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +1 -3
- package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +86 -0
- package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +24 -0
- package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +5 -69
- package/corpus/templates/clips/desktop/src/styles.css +35 -3
- package/corpus/templates/clips/desktop/src-tauri/src/adhoc_meetings_watcher.rs +13 -44
- package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +119 -17
- package/corpus/templates/clips/netlify.toml +1 -0
- package/corpus/templates/clips/server/plugins/db.ts +113 -68
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +69 -49
- package/corpus/templates/content/app/global.css +1 -1
- package/corpus/templates/content/app/routes/_app.extensions._index.tsx +2 -2
- package/corpus/templates/content/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.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-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/content/netlify.toml +1 -0
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +115 -42
- package/corpus/templates/design/app/entry.client.tsx +14 -1
- package/corpus/templates/design/app/global.css +1 -1
- package/corpus/templates/design/app/routes/extensions._index.tsx +2 -2
- package/corpus/templates/design/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -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/design/netlify.toml +1 -0
- package/corpus/templates/dispatch/app/dispatch-extensions.tsx +1 -1
- package/corpus/templates/dispatch/app/global.css +1 -1
- package/corpus/templates/dispatch/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
- 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/dispatch/netlify.toml +1 -0
- package/corpus/templates/forms/app/components/layout/Layout.tsx +3 -0
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +113 -82
- package/corpus/templates/forms/app/global.css +1 -1
- package/corpus/templates/forms/app/routes/_app.extensions._index.tsx +2 -2
- package/corpus/templates/forms/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
- 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/forms/netlify.toml +1 -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 +92 -34
- 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/app/routes/extensions._index.tsx +2 -2
- 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/macros/netlify.toml +1 -0
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +125 -46
- package/corpus/templates/mail/app/global.css +1 -1
- package/corpus/templates/mail/app/routes/extensions._index.tsx +2 -2
- 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/mail/netlify.toml +1 -0
- package/corpus/templates/plan/app/components/layout/Layout.tsx +3 -0
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +128 -65
- package/corpus/templates/plan/app/global.css +1 -1
- package/corpus/templates/plan/app/routes/extensions._index.tsx +2 -2
- 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/plan/netlify.toml +1 -0
- package/corpus/templates/slides/app/components/layout/Sidebar.tsx +116 -36
- package/corpus/templates/slides/app/global.css +1 -1
- package/corpus/templates/slides/app/routes/extensions._index.tsx +2 -2
- 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/slides/netlify.toml +1 -0
- package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +37 -6
- package/corpus/templates/tasks/app/global.css +1 -1
- package/corpus/templates/tasks/app/routes/extensions._index.tsx +2 -2
- package/corpus/templates/tasks/app/routes/settings.tsx +31 -0
- package/corpus/templates/tasks/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/tasks/netlify.toml +1 -0
- package/corpus/toolkit/CHANGELOG.md +8 -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/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/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +4 -0
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts +9 -0
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +25 -10
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/types.d.ts +2 -2
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- 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 +5 -1
- package/dist/client/extensions/ExtensionsListPage.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionsListPage.js +6 -4
- 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.d.ts +2 -0
- package/dist/client/settings/ExtensionsSettingsContent.d.ts.map +1 -0
- package/dist/client/settings/ExtensionsSettingsContent.js +10 -0
- package/dist/client/settings/ExtensionsSettingsContent.js.map +1 -0
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +10 -1
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/deploy/build.js +1 -0
- package/dist/deploy/build.js.map +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/observability/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +7 -7
- package/dist/provider-api/actions/provider-api.d.ts +9 -9
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/analytics.d.ts +9 -4
- package/dist/server/analytics.d.ts.map +1 -1
- package/dist/server/analytics.js +111 -22
- package/dist/server/analytics.js.map +1 -1
- 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 +113 -51
- package/dist/templates/chat/app/global.css +1 -1
- package/dist/templates/chat/app/routes/extensions._index.tsx +2 -2
- 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/chat/netlify.toml +1 -0
- package/dist/templates/default/app/global.css +1 -1
- package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +16 -0
- 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/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +2 -0
- package/dist/vite/client.js.map +1 -1
- package/docs/content/extensions.mdx +23 -4
- package/package.json +2 -2
- package/src/agent/production-agent.ts +4 -0
- package/src/agent/run-manager.ts +36 -10
- package/src/agent/types.ts +2 -0
- 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 +28 -8
- 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 +24 -0
- package/src/client/settings/SettingsPanel.tsx +10 -0
- package/src/deploy/build.ts +3 -0
- package/src/extensions/theme.ts +1 -1
- package/src/localization/default-messages.ts +2 -0
- package/src/server/analytics.ts +154 -25
- 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 +113 -51
- package/src/templates/chat/app/global.css +1 -1
- package/src/templates/chat/app/routes/extensions._index.tsx +2 -2
- 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/chat/netlify.toml +1 -0
- package/src/templates/default/app/global.css +1 -1
- package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +16 -0
- package/src/tracking/error-capture.ts +151 -0
- package/src/tracking/index.ts +5 -0
- package/src/vite/client.ts +6 -0
- package/corpus/templates/analytics/app/components/layout/NewAnalysisDialog.tsx +0 -165
- package/corpus/templates/analytics/app/pages/analyses/AnalysesList.tsx +0 -175
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
IconGripVertical,
|
|
12
12
|
IconBook2,
|
|
13
13
|
IconDatabase,
|
|
14
|
-
IconReportAnalytics,
|
|
15
14
|
IconSearch,
|
|
16
15
|
IconArchive,
|
|
17
16
|
IconActivity,
|
|
@@ -27,6 +26,7 @@ import {
|
|
|
27
26
|
IconPlayerPlay,
|
|
28
27
|
IconLayoutSidebarLeftCollapse,
|
|
29
28
|
IconLayoutSidebarLeftExpand,
|
|
29
|
+
IconArrowUpRight,
|
|
30
30
|
} from "@tabler/icons-react";
|
|
31
31
|
import {
|
|
32
32
|
useQuery,
|
|
@@ -62,7 +62,8 @@ type SidebarDashboard = {
|
|
|
62
62
|
id: string;
|
|
63
63
|
name: string;
|
|
64
64
|
subviews?: DashboardSubview[];
|
|
65
|
-
source: "static" | "sql";
|
|
65
|
+
source: "static" | "sql" | "analysis";
|
|
66
|
+
resourceId?: string;
|
|
66
67
|
visibility?: Visibility;
|
|
67
68
|
/** Id of the dashboard this one nests under in the sidebar, if any. */
|
|
68
69
|
parentId?: string;
|
|
@@ -88,15 +89,16 @@ import {
|
|
|
88
89
|
} from "@agent-native/core/client/agent-chat";
|
|
89
90
|
import { appApiPath, appPath } from "@agent-native/core/client/api-path";
|
|
90
91
|
import { DevDatabaseLink } from "@agent-native/core/client/db-admin";
|
|
91
|
-
import { ExtensionsSidebarSection } from "@agent-native/core/client/extensions";
|
|
92
92
|
import {
|
|
93
93
|
callAction,
|
|
94
94
|
useActionMutation,
|
|
95
95
|
useChangeVersions,
|
|
96
96
|
} from "@agent-native/core/client/hooks";
|
|
97
97
|
import { LanguagePicker, useT } from "@agent-native/core/client/i18n";
|
|
98
|
+
import { openCommandMenu } from "@agent-native/core/client/navigation";
|
|
98
99
|
import { OrgSwitcher } from "@agent-native/core/client/org";
|
|
99
100
|
import { FeedbackButton } from "@agent-native/core/client/ui";
|
|
101
|
+
import { SidebarFooterActions } from "@agent-native/toolkit/app-shell";
|
|
100
102
|
import {
|
|
101
103
|
ChatHistoryRail,
|
|
102
104
|
type ChatHistoryItem,
|
|
@@ -143,24 +145,18 @@ import { useUserPref } from "@/hooks/use-user-pref";
|
|
|
143
145
|
import { shouldRenderDashboardList } from "@/lib/dashboard-list-loading";
|
|
144
146
|
import { usePopularity, popularityOf } from "@/lib/item-popularity";
|
|
145
147
|
import {
|
|
146
|
-
analysisDetailPrefetchKey,
|
|
147
148
|
sqlDashboardPrefetchKey,
|
|
148
149
|
type PrefetchSnapshot,
|
|
149
150
|
} from "@/lib/prefetch-keys";
|
|
150
151
|
import type { ResourceAccess } from "@/lib/resource-access";
|
|
151
152
|
|
|
152
|
-
import { NewAnalysisDialog } from "./NewAnalysisDialog";
|
|
153
153
|
import { NewDashboardDialog } from "./NewDashboardDialog";
|
|
154
154
|
import { SidebarLoadError } from "./SidebarLoadError";
|
|
155
155
|
|
|
156
|
-
type AnalysisHiddenFilter = "visible" | "hidden";
|
|
157
|
-
|
|
158
156
|
const SIDEBAR_PREVIEW_COUNT = 5;
|
|
159
157
|
const ASK_OPEN_KEY = "analytics-sidebar-ask-open";
|
|
160
158
|
const DASHBOARD_SORT_MODE_KEY = "dashboard-sort-mode";
|
|
161
|
-
const ANALYSIS_SORT_MODE_KEY = "analysis-sort-mode";
|
|
162
159
|
const DASHBOARDS_OPEN_KEY = "analytics-sidebar-dashboards-open";
|
|
163
|
-
const ANALYSES_OPEN_KEY = "analytics-sidebar-analyses-open";
|
|
164
160
|
const SIDEBAR_COLLAPSE_KEY = "analytics.sidebar.collapsed";
|
|
165
161
|
const SIDEBAR_SKELETON_CLASS =
|
|
166
162
|
"bg-sidebar-foreground/12 dark:bg-sidebar-foreground/10";
|
|
@@ -191,6 +187,7 @@ const bottomItems = [
|
|
|
191
187
|
icon: IconHierarchy2,
|
|
192
188
|
labelKey: "settings.agentTitle",
|
|
193
189
|
href: "/agent",
|
|
190
|
+
showExternalLinkIcon: true,
|
|
194
191
|
},
|
|
195
192
|
{ icon: IconSettings, labelKey: "navigation.settings", href: "/settings" },
|
|
196
193
|
];
|
|
@@ -867,7 +864,10 @@ function SortableDashboardItem({
|
|
|
867
864
|
visibility: Visibility,
|
|
868
865
|
) => Promise<void>;
|
|
869
866
|
}) {
|
|
870
|
-
const
|
|
867
|
+
const resourceId = d.resourceId ?? d.id;
|
|
868
|
+
const href =
|
|
869
|
+
d.source === "analysis" ? `/analyses/${resourceId}` : `/dashboards/${d.id}`;
|
|
870
|
+
const favoriteKey = d.source === "analysis" ? `analysis:${resourceId}` : d.id;
|
|
871
871
|
const t = useT();
|
|
872
872
|
const { mutateAsync: deleteView } = useDeleteDashboardView();
|
|
873
873
|
const [deletingViewId, setDeletingViewId] = useState<string | null>(null);
|
|
@@ -908,7 +908,7 @@ function SortableDashboardItem({
|
|
|
908
908
|
return (
|
|
909
909
|
<SortableRow
|
|
910
910
|
id={d.id}
|
|
911
|
-
favoriteKey={
|
|
911
|
+
favoriteKey={favoriteKey}
|
|
912
912
|
name={d.name}
|
|
913
913
|
href={href}
|
|
914
914
|
isActive={isActive}
|
|
@@ -916,7 +916,9 @@ function SortableDashboardItem({
|
|
|
916
916
|
onToggleFavorite={onToggleFavorite}
|
|
917
917
|
onDelete={() => onDelete(d)}
|
|
918
918
|
onRename={(name) => onRename(d, name)}
|
|
919
|
-
onArchive={
|
|
919
|
+
onArchive={
|
|
920
|
+
d.source === "analysis" || !onArchive ? undefined : () => onArchive(d)
|
|
921
|
+
}
|
|
920
922
|
onPrefetch={() => onPrefetch?.(d)}
|
|
921
923
|
visibility={d.visibility}
|
|
922
924
|
onSetVisibility={
|
|
@@ -1068,33 +1070,6 @@ function SortableDashboardItem({
|
|
|
1068
1070
|
);
|
|
1069
1071
|
}
|
|
1070
1072
|
|
|
1071
|
-
// Analyses reuse SortableRow directly — no wrapper component needed.
|
|
1072
|
-
|
|
1073
|
-
const ANALYSIS_ORDER_KEY = "analysis-order";
|
|
1074
|
-
|
|
1075
|
-
function getAnalysisOrder(): string[] {
|
|
1076
|
-
if (typeof window === "undefined") return [];
|
|
1077
|
-
try {
|
|
1078
|
-
const raw = window.localStorage.getItem(ANALYSIS_ORDER_KEY);
|
|
1079
|
-
if (!raw) return [];
|
|
1080
|
-
const parsed = JSON.parse(raw);
|
|
1081
|
-
return Array.isArray(parsed)
|
|
1082
|
-
? parsed.filter((x) => typeof x === "string")
|
|
1083
|
-
: [];
|
|
1084
|
-
} catch {
|
|
1085
|
-
return [];
|
|
1086
|
-
}
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
function setAnalysisOrder(order: string[]): void {
|
|
1090
|
-
if (typeof window === "undefined") return;
|
|
1091
|
-
try {
|
|
1092
|
-
window.localStorage.setItem(ANALYSIS_ORDER_KEY, JSON.stringify(order));
|
|
1093
|
-
} catch {
|
|
1094
|
-
// localStorage unavailable / quota — ignore, order is best-effort
|
|
1095
|
-
}
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
1073
|
const STATIC_DASHBOARD_RENAMES_KEY = "dashboard-name-overrides";
|
|
1099
1074
|
|
|
1100
1075
|
function getStaticDashboardRenames(): Record<string, string> {
|
|
@@ -1161,10 +1136,7 @@ async function fetchSqlDashboards(
|
|
|
1161
1136
|
}));
|
|
1162
1137
|
}
|
|
1163
1138
|
|
|
1164
|
-
async function fetchSidebarAnalyses(
|
|
1165
|
-
t: (key: string) => string,
|
|
1166
|
-
hidden: AnalysisHiddenFilter = "visible",
|
|
1167
|
-
): Promise<
|
|
1139
|
+
async function fetchSidebarAnalyses(t: (key: string) => string): Promise<
|
|
1168
1140
|
{
|
|
1169
1141
|
id: string;
|
|
1170
1142
|
name: string;
|
|
@@ -1172,13 +1144,7 @@ async function fetchSidebarAnalyses(
|
|
|
1172
1144
|
hiddenAt: string | null;
|
|
1173
1145
|
}[]
|
|
1174
1146
|
> {
|
|
1175
|
-
const rows = await callAction(
|
|
1176
|
-
"list-analyses",
|
|
1177
|
-
{
|
|
1178
|
-
...(hidden === "hidden" ? { hidden: "hidden" } : {}),
|
|
1179
|
-
} as Record<string, unknown>,
|
|
1180
|
-
{ method: "GET" },
|
|
1181
|
-
);
|
|
1147
|
+
const rows = await callAction("list-analyses", {}, { method: "GET" });
|
|
1182
1148
|
return (Array.isArray(rows) ? rows : [])
|
|
1183
1149
|
.filter((a: any) => a && typeof a.id === "string" && a.id.length > 0)
|
|
1184
1150
|
.map((a: any) => ({
|
|
@@ -1256,16 +1222,6 @@ async function fetchSqlDashboardForPrefetch(
|
|
|
1256
1222
|
}
|
|
1257
1223
|
}
|
|
1258
1224
|
|
|
1259
|
-
async function fetchAnalysisDetailForPrefetch(id: string): Promise<unknown> {
|
|
1260
|
-
try {
|
|
1261
|
-
const data = await callAction("get-analysis", { id }, { method: "GET" });
|
|
1262
|
-
if (!data || (data as Record<string, unknown>).error) return null;
|
|
1263
|
-
return data;
|
|
1264
|
-
} catch {
|
|
1265
|
-
return null;
|
|
1266
|
-
}
|
|
1267
|
-
}
|
|
1268
|
-
|
|
1269
1225
|
const ANALYTICS_ACTIVE_THREAD_KEY = `agent-chat-active-thread:${ANALYTICS_CHAT_STORAGE_KEY}`;
|
|
1270
1226
|
|
|
1271
1227
|
function formatThreadAge(updatedAt: number) {
|
|
@@ -1311,7 +1267,13 @@ function persistedAnalyticsThreadId() {
|
|
|
1311
1267
|
}
|
|
1312
1268
|
}
|
|
1313
1269
|
|
|
1314
|
-
function AnalyticsChatsSection({
|
|
1270
|
+
function AnalyticsChatsSection({
|
|
1271
|
+
isAskRoute,
|
|
1272
|
+
open,
|
|
1273
|
+
}: {
|
|
1274
|
+
isAskRoute: boolean;
|
|
1275
|
+
open: boolean;
|
|
1276
|
+
}) {
|
|
1315
1277
|
const navigate = useNavigate();
|
|
1316
1278
|
const t = useT();
|
|
1317
1279
|
const {
|
|
@@ -1413,57 +1375,63 @@ function AnalyticsChatsSection({ isAskRoute }: { isAskRoute: boolean }) {
|
|
|
1413
1375
|
}
|
|
1414
1376
|
|
|
1415
1377
|
return (
|
|
1416
|
-
<div
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
}
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1378
|
+
<div
|
|
1379
|
+
className="an-chat-history-rail__collapse"
|
|
1380
|
+
data-state={open ? "open" : "closed"}
|
|
1381
|
+
aria-hidden={!open}
|
|
1382
|
+
>
|
|
1383
|
+
<div className="ms-4 min-w-0 space-y-0.5">
|
|
1384
|
+
{chatsLoading &&
|
|
1385
|
+
visibleThreads.length === 0 &&
|
|
1386
|
+
Array.from({ length: 3 }).map((_, i) => (
|
|
1387
|
+
<div
|
|
1388
|
+
key={`chat-skeleton-${i}`}
|
|
1389
|
+
className="flex items-center gap-2 px-3 py-1"
|
|
1390
|
+
>
|
|
1391
|
+
<Skeleton
|
|
1392
|
+
className={cn(
|
|
1393
|
+
"h-3.5 w-3.5 shrink-0 rounded-sm",
|
|
1394
|
+
SIDEBAR_SKELETON_CLASS,
|
|
1395
|
+
)}
|
|
1396
|
+
/>
|
|
1397
|
+
<Skeleton
|
|
1398
|
+
className={cn("h-3 rounded", SIDEBAR_SKELETON_CLASS)}
|
|
1399
|
+
style={{ width: `${60 + ((i * 17) % 30)}%` }}
|
|
1400
|
+
/>
|
|
1401
|
+
</div>
|
|
1402
|
+
))}
|
|
1403
|
+
<ChatHistoryRail
|
|
1404
|
+
items={chatItems}
|
|
1405
|
+
activeId={displayedActiveThreadId}
|
|
1406
|
+
onSelect={(threadId) => openThread(threadId)}
|
|
1407
|
+
onNewChat={() => void handleNewChat()}
|
|
1408
|
+
railLabels={{
|
|
1409
|
+
newChat: t("chat.newChat"),
|
|
1410
|
+
showMore: t("sidebar.showMore", {
|
|
1411
|
+
count: Math.max(0, visibleThreads.length - SIDEBAR_PREVIEW_COUNT),
|
|
1412
|
+
}),
|
|
1413
|
+
showLess: t("sidebar.showLess"),
|
|
1414
|
+
}}
|
|
1415
|
+
renameMaxLength={160}
|
|
1416
|
+
onTogglePin={(threadId) => {
|
|
1417
|
+
const thread = visibleThreads.find((item) => item.id === threadId);
|
|
1418
|
+
if (thread) void pinThread(threadId, !thread.pinnedAt);
|
|
1419
|
+
}}
|
|
1420
|
+
onRename={handleRenameThread}
|
|
1421
|
+
onDelete={(threadId) => void handleArchiveThread(threadId)}
|
|
1422
|
+
labels={{
|
|
1423
|
+
options: (item) =>
|
|
1424
|
+
t("chat.optionsFor", { title: item.titleText ?? "" }),
|
|
1425
|
+
renameInput: (item) =>
|
|
1426
|
+
t("chat.renameThread", { title: item.titleText ?? "" }),
|
|
1427
|
+
rename: t("chat.renameChat"),
|
|
1428
|
+
pin: t("chat.pinChat"),
|
|
1429
|
+
unpin: t("chat.unpinChat"),
|
|
1430
|
+
delete: t("chat.archiveChat"),
|
|
1431
|
+
}}
|
|
1432
|
+
className="min-w-0"
|
|
1433
|
+
/>
|
|
1434
|
+
</div>
|
|
1467
1435
|
</div>
|
|
1468
1436
|
);
|
|
1469
1437
|
}
|
|
@@ -1510,20 +1478,8 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
1510
1478
|
);
|
|
1511
1479
|
const [dashShowAll, setDashShowAll] = useState(false);
|
|
1512
1480
|
const [dashFilter, setDashFilter] = useState<SidebarVisibilityFilter>("all");
|
|
1513
|
-
const [analysesOpen, setAnalysesOpen] = useState(
|
|
1514
|
-
() =>
|
|
1515
|
-
getStoredBooleanPreference(ANALYSES_OPEN_KEY) ??
|
|
1516
|
-
activeAnalysisId !== null,
|
|
1517
|
-
);
|
|
1518
|
-
const [analysesShowAll, setAnalysesShowAll] = useState(false);
|
|
1519
|
-
const [analysisFilter, setAnalysisFilter] =
|
|
1520
|
-
useState<SidebarVisibilityFilter>("all");
|
|
1521
|
-
const [analysisHiddenFilter, setAnalysisHiddenFilter] =
|
|
1522
|
-
useState<AnalysisHiddenFilter>("visible");
|
|
1523
1481
|
const [dashboardSortMode, setDashboardSortModeState] =
|
|
1524
1482
|
useState<SidebarSortMode>(() => getStoredSortMode(DASHBOARD_SORT_MODE_KEY));
|
|
1525
|
-
const [analysisSortMode, setAnalysisSortModeState] =
|
|
1526
|
-
useState<SidebarSortMode>(() => getStoredSortMode(ANALYSIS_SORT_MODE_KEY));
|
|
1527
1483
|
const { data: popularity, isReady: popularityReady } = usePopularity();
|
|
1528
1484
|
|
|
1529
1485
|
useEffect(() => {
|
|
@@ -1542,7 +1498,6 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
1542
1498
|
const { mutateAsync: renameDashboard } =
|
|
1543
1499
|
useActionMutation("rename-dashboard");
|
|
1544
1500
|
const { mutateAsync: renameAnalysis } = useActionMutation("rename-analysis");
|
|
1545
|
-
const { mutateAsync: hideAnalysisMut } = useActionMutation("hide-analysis");
|
|
1546
1501
|
const { mutateAsync: setResourceVisibility } = useActionMutation(
|
|
1547
1502
|
"set-resource-visibility",
|
|
1548
1503
|
);
|
|
@@ -1580,10 +1535,6 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
1580
1535
|
const [dashboardOrderState, setDashboardOrderState] = useState(() =>
|
|
1581
1536
|
typeof window === "undefined" ? [] : getDashboardOrder(),
|
|
1582
1537
|
);
|
|
1583
|
-
const [analysisOrderState, setAnalysisOrderState] = useState(() =>
|
|
1584
|
-
typeof window === "undefined" ? [] : getAnalysisOrder(),
|
|
1585
|
-
);
|
|
1586
|
-
|
|
1587
1538
|
// Server-backed favorites
|
|
1588
1539
|
const {
|
|
1589
1540
|
data: favoritesData,
|
|
@@ -1614,11 +1565,6 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
1614
1565
|
setDashboardSortModeState(mode);
|
|
1615
1566
|
}, []);
|
|
1616
1567
|
|
|
1617
|
-
const setAnalysisSortMode = useCallback((mode: SidebarSortMode) => {
|
|
1618
|
-
setStoredSortMode(ANALYSIS_SORT_MODE_KEY, mode);
|
|
1619
|
-
setAnalysisSortModeState(mode);
|
|
1620
|
-
}, []);
|
|
1621
|
-
|
|
1622
1568
|
useEffect(() => {
|
|
1623
1569
|
if (getStoredBooleanPreference(ASK_OPEN_KEY) === null) {
|
|
1624
1570
|
setAskOpen(isAskRoute);
|
|
@@ -1631,12 +1577,6 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
1631
1577
|
}
|
|
1632
1578
|
}, [activeDashboardId]);
|
|
1633
1579
|
|
|
1634
|
-
useEffect(() => {
|
|
1635
|
-
if (getStoredBooleanPreference(ANALYSES_OPEN_KEY) === null) {
|
|
1636
|
-
setAnalysesOpen(activeAnalysisId !== null);
|
|
1637
|
-
}
|
|
1638
|
-
}, [activeAnalysisId]);
|
|
1639
|
-
|
|
1640
1580
|
const toggleAskOpen = useCallback(() => {
|
|
1641
1581
|
setAskOpen((current) => {
|
|
1642
1582
|
const next = !current;
|
|
@@ -1653,14 +1593,6 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
1653
1593
|
});
|
|
1654
1594
|
}, []);
|
|
1655
1595
|
|
|
1656
|
-
const toggleAnalysesOpen = useCallback(() => {
|
|
1657
|
-
setAnalysesOpen((current) => {
|
|
1658
|
-
const next = !current;
|
|
1659
|
-
setStoredBoolean(ANALYSES_OPEN_KEY, next);
|
|
1660
|
-
return next;
|
|
1661
|
-
});
|
|
1662
|
-
}, []);
|
|
1663
|
-
|
|
1664
1596
|
// Fold per-source counters into sidebar list query keys so agent-driven
|
|
1665
1597
|
// create/rename/archive/delete shows up without a manual refresh. We
|
|
1666
1598
|
// Domain counters keep these lists targeted. Folding the generic `action`
|
|
@@ -1671,9 +1603,7 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
1671
1603
|
);
|
|
1672
1604
|
const analysesSync = useSettledSyncVersion(useChangeVersions(["analyses"]));
|
|
1673
1605
|
const dashboardsSyncRef = useRef(dashboardsSync);
|
|
1674
|
-
const analysesSyncRef = useRef(analysesSync);
|
|
1675
1606
|
dashboardsSyncRef.current = dashboardsSync;
|
|
1676
|
-
analysesSyncRef.current = analysesSync;
|
|
1677
1607
|
|
|
1678
1608
|
const {
|
|
1679
1609
|
data: sqlDashboards = [],
|
|
@@ -1694,52 +1624,12 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
1694
1624
|
isError: analysesError,
|
|
1695
1625
|
refetch: refetchAnalyses,
|
|
1696
1626
|
} = useQuery({
|
|
1697
|
-
queryKey: ["analyses-sidebar", analysesSync
|
|
1698
|
-
queryFn: () => fetchSidebarAnalyses(t
|
|
1627
|
+
queryKey: ["analyses-sidebar", analysesSync],
|
|
1628
|
+
queryFn: () => fetchSidebarAnalyses(t),
|
|
1699
1629
|
staleTime: 30_000,
|
|
1700
1630
|
placeholderData: (prev) => prev,
|
|
1701
1631
|
});
|
|
1702
1632
|
|
|
1703
|
-
const sortedAnalyses = useMemo(() => {
|
|
1704
|
-
if (analysisSortMode === "alphabetical") {
|
|
1705
|
-
return sortByName(analysesList);
|
|
1706
|
-
}
|
|
1707
|
-
if (analysisSortMode === "manual" && analysisOrderState.length > 0) {
|
|
1708
|
-
return applyOrder(analysesList, analysisOrderState);
|
|
1709
|
-
}
|
|
1710
|
-
return [...analysesList].sort((a, b) => {
|
|
1711
|
-
const aFav = favoriteIds.has(`analysis:${a.id}`) ? 0 : 1;
|
|
1712
|
-
const bFav = favoriteIds.has(`analysis:${b.id}`) ? 0 : 1;
|
|
1713
|
-
if (aFav !== bFav) return aFav - bFav;
|
|
1714
|
-
const aPop = popularityOf(popularity, "analysis", a.id);
|
|
1715
|
-
const bPop = popularityOf(popularity, "analysis", b.id);
|
|
1716
|
-
if (aPop !== bPop) return bPop - aPop;
|
|
1717
|
-
return a.name.localeCompare(b.name);
|
|
1718
|
-
});
|
|
1719
|
-
}, [
|
|
1720
|
-
analysesList,
|
|
1721
|
-
analysisSortMode,
|
|
1722
|
-
analysisOrderState,
|
|
1723
|
-
popularity,
|
|
1724
|
-
favoriteIds,
|
|
1725
|
-
]);
|
|
1726
|
-
|
|
1727
|
-
const filteredAnalyses = useMemo(
|
|
1728
|
-
() =>
|
|
1729
|
-
sortedAnalyses.filter((analysis) =>
|
|
1730
|
-
matchesVisibilityFilter(analysis, analysisFilter),
|
|
1731
|
-
),
|
|
1732
|
-
[sortedAnalyses, analysisFilter],
|
|
1733
|
-
);
|
|
1734
|
-
|
|
1735
|
-
const displayedAnalyses = useMemo(
|
|
1736
|
-
() =>
|
|
1737
|
-
analysesShowAll
|
|
1738
|
-
? filteredAnalyses
|
|
1739
|
-
: filteredAnalyses.slice(0, SIDEBAR_PREVIEW_COUNT),
|
|
1740
|
-
[filteredAnalyses, analysesShowAll],
|
|
1741
|
-
);
|
|
1742
|
-
|
|
1743
1633
|
// Only the active dashboard can display saved views in the sidebar, so avoid
|
|
1744
1634
|
// issuing one request per dashboard on every sidebar mount.
|
|
1745
1635
|
const { views: activeDashboardViews = [] } = useDashboardViews(
|
|
@@ -1772,24 +1662,6 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
1772
1662
|
[dashboardsSync, queryClient, t],
|
|
1773
1663
|
);
|
|
1774
1664
|
|
|
1775
|
-
const prefetchAnalysis = useCallback(
|
|
1776
|
-
(id: string) => {
|
|
1777
|
-
const queryKey = analysisDetailPrefetchKey(id);
|
|
1778
|
-
const cached =
|
|
1779
|
-
queryClient.getQueryData<PrefetchSnapshot<unknown | null>>(queryKey);
|
|
1780
|
-
void import("@/pages/analyses/AnalysisDetail");
|
|
1781
|
-
void queryClient.prefetchQuery({
|
|
1782
|
-
queryKey,
|
|
1783
|
-
queryFn: async () => ({
|
|
1784
|
-
data: await fetchAnalysisDetailForPrefetch(id),
|
|
1785
|
-
syncVersion: analysesSync,
|
|
1786
|
-
}),
|
|
1787
|
-
staleTime: cached?.syncVersion === analysesSync ? 30_000 : 0,
|
|
1788
|
-
});
|
|
1789
|
-
},
|
|
1790
|
-
[analysesSync, queryClient],
|
|
1791
|
-
);
|
|
1792
|
-
|
|
1793
1665
|
const visibleDashboards = useMemo<SidebarDashboard[]>(() => {
|
|
1794
1666
|
const staticItems: SidebarDashboard[] = dashboards
|
|
1795
1667
|
.filter((d) => !hiddenIds.has(d.id))
|
|
@@ -1806,7 +1678,14 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
1806
1678
|
visibility: d.visibility,
|
|
1807
1679
|
parentId: d.parentId,
|
|
1808
1680
|
}));
|
|
1809
|
-
const
|
|
1681
|
+
const analysisItems: SidebarDashboard[] = analysesList.map((a) => ({
|
|
1682
|
+
id: `analysis:${a.id}`,
|
|
1683
|
+
resourceId: a.id,
|
|
1684
|
+
name: a.name,
|
|
1685
|
+
source: "analysis",
|
|
1686
|
+
visibility: a.visibility,
|
|
1687
|
+
}));
|
|
1688
|
+
const all = [...staticItems, ...sqlItems, ...analysisItems];
|
|
1810
1689
|
if (dashboardSortMode === "alphabetical") {
|
|
1811
1690
|
return sortByName(all);
|
|
1812
1691
|
}
|
|
@@ -1814,11 +1693,25 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
1814
1693
|
return applyOrder(all, dashboardOrderState);
|
|
1815
1694
|
}
|
|
1816
1695
|
return [...all].sort((a, b) => {
|
|
1817
|
-
const
|
|
1818
|
-
const
|
|
1696
|
+
const aResourceId = a.resourceId ?? a.id;
|
|
1697
|
+
const bResourceId = b.resourceId ?? b.id;
|
|
1698
|
+
const aFavoriteKey =
|
|
1699
|
+
a.source === "analysis" ? `analysis:${aResourceId}` : a.id;
|
|
1700
|
+
const bFavoriteKey =
|
|
1701
|
+
b.source === "analysis" ? `analysis:${bResourceId}` : b.id;
|
|
1702
|
+
const aFav = favoriteIds.has(aFavoriteKey) ? 0 : 1;
|
|
1703
|
+
const bFav = favoriteIds.has(bFavoriteKey) ? 0 : 1;
|
|
1819
1704
|
if (aFav !== bFav) return aFav - bFav;
|
|
1820
|
-
const aPop = popularityOf(
|
|
1821
|
-
|
|
1705
|
+
const aPop = popularityOf(
|
|
1706
|
+
popularity,
|
|
1707
|
+
a.source === "analysis" ? "analysis" : "dashboard",
|
|
1708
|
+
aResourceId,
|
|
1709
|
+
);
|
|
1710
|
+
const bPop = popularityOf(
|
|
1711
|
+
popularity,
|
|
1712
|
+
b.source === "analysis" ? "analysis" : "dashboard",
|
|
1713
|
+
bResourceId,
|
|
1714
|
+
);
|
|
1822
1715
|
if (aPop !== bPop) return bPop - aPop;
|
|
1823
1716
|
return a.name.localeCompare(b.name) || a.id.localeCompare(b.id);
|
|
1824
1717
|
});
|
|
@@ -1829,6 +1722,7 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
1829
1722
|
dashboardSortMode,
|
|
1830
1723
|
dashboardOrderState,
|
|
1831
1724
|
sqlDashboards,
|
|
1725
|
+
analysesList,
|
|
1832
1726
|
popularity,
|
|
1833
1727
|
]);
|
|
1834
1728
|
|
|
@@ -1905,6 +1799,12 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
1905
1799
|
|
|
1906
1800
|
const handleDashboardDelete = useCallback(
|
|
1907
1801
|
async (d: SidebarDashboard) => {
|
|
1802
|
+
if (d.source === "analysis") {
|
|
1803
|
+
await deleteAnalysisMut({ id: d.resourceId ?? d.id });
|
|
1804
|
+
queryClient.invalidateQueries({ queryKey: ["analyses-sidebar"] });
|
|
1805
|
+
queryClient.invalidateQueries({ queryKey: ["analyses-list"] });
|
|
1806
|
+
return;
|
|
1807
|
+
}
|
|
1908
1808
|
if (d.source === "static") {
|
|
1909
1809
|
hideDashboard(d.id);
|
|
1910
1810
|
setHiddenIds(getHiddenDashboards());
|
|
@@ -1931,11 +1831,12 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
1931
1831
|
throw err;
|
|
1932
1832
|
}
|
|
1933
1833
|
},
|
|
1934
|
-
[
|
|
1834
|
+
[deleteAnalysisMut, deleteSqlDashboard, queryClient],
|
|
1935
1835
|
);
|
|
1936
1836
|
|
|
1937
1837
|
const handleDashboardArchive = useCallback(
|
|
1938
1838
|
async (d: SidebarDashboard) => {
|
|
1839
|
+
if (d.source === "analysis") return;
|
|
1939
1840
|
if (d.source === "static") {
|
|
1940
1841
|
// Static dashboards can only be hidden, not archived; route to delete
|
|
1941
1842
|
// (which calls hideDashboard for static items).
|
|
@@ -1970,6 +1871,16 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
1970
1871
|
const trimmed = name.trim();
|
|
1971
1872
|
if (!trimmed || trimmed === d.name) return;
|
|
1972
1873
|
|
|
1874
|
+
if (d.source === "analysis") {
|
|
1875
|
+
await renameAnalysis({ id: d.resourceId ?? d.id, name: trimmed });
|
|
1876
|
+
queryClient.invalidateQueries({ queryKey: ["analyses-sidebar"] });
|
|
1877
|
+
queryClient.invalidateQueries({ queryKey: ["analyses-list"] });
|
|
1878
|
+
queryClient.invalidateQueries({
|
|
1879
|
+
queryKey: ["analysis-detail", d.resourceId ?? d.id],
|
|
1880
|
+
});
|
|
1881
|
+
return;
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1973
1884
|
if (d.source === "static") {
|
|
1974
1885
|
setStaticDashboardRenamesState((prev) => {
|
|
1975
1886
|
const next = { ...prev, [d.id]: trimmed };
|
|
@@ -2001,38 +1912,27 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
2001
1912
|
throw err;
|
|
2002
1913
|
}
|
|
2003
1914
|
},
|
|
2004
|
-
[queryClient, renameDashboard],
|
|
2005
|
-
);
|
|
2006
|
-
|
|
2007
|
-
const handleAnalysisDelete = useCallback(
|
|
2008
|
-
async (a: { id: string; name: string }) => {
|
|
2009
|
-
const queryKey = ["analyses-sidebar"] as const;
|
|
2010
|
-
const prev = getQuerySnapshots<{ id: string; name: string }[]>(
|
|
2011
|
-
queryClient,
|
|
2012
|
-
queryKey,
|
|
2013
|
-
);
|
|
2014
|
-
queryClient.setQueriesData<{ id: string; name: string }[]>(
|
|
2015
|
-
{ queryKey },
|
|
2016
|
-
(old) => (old ?? []).filter((item) => item.id !== a.id),
|
|
2017
|
-
);
|
|
2018
|
-
try {
|
|
2019
|
-
await deleteAnalysisMut({ id: a.id });
|
|
2020
|
-
queryClient.removeQueries({
|
|
2021
|
-
queryKey: analysisDetailPrefetchKey(a.id),
|
|
2022
|
-
});
|
|
2023
|
-
queryClient.invalidateQueries({ queryKey });
|
|
2024
|
-
queryClient.invalidateQueries({ queryKey: ["analyses-list"] });
|
|
2025
|
-
} catch (err) {
|
|
2026
|
-
restoreQuerySnapshots(queryClient, prev);
|
|
2027
|
-
throw err;
|
|
2028
|
-
}
|
|
2029
|
-
},
|
|
2030
|
-
[queryClient, deleteAnalysisMut],
|
|
1915
|
+
[queryClient, renameAnalysis, renameDashboard],
|
|
2031
1916
|
);
|
|
2032
1917
|
|
|
2033
1918
|
const handleDashboardSetVisibility = useCallback(
|
|
2034
1919
|
async (d: SidebarDashboard, visibility: Visibility) => {
|
|
2035
1920
|
if (d.source === "static") return;
|
|
1921
|
+
if (d.source === "analysis") {
|
|
1922
|
+
await setResourceVisibility({
|
|
1923
|
+
resourceType: "analysis",
|
|
1924
|
+
resourceId: d.resourceId ?? d.id,
|
|
1925
|
+
visibility,
|
|
1926
|
+
} as any);
|
|
1927
|
+
queryClient.invalidateQueries({ queryKey: ["analyses-sidebar"] });
|
|
1928
|
+
queryClient.invalidateQueries({ queryKey: ["analyses-list"] });
|
|
1929
|
+
toast.success(
|
|
1930
|
+
visibility === "org"
|
|
1931
|
+
? t("sidebar.nameSharedWithOrg", { name: d.name })
|
|
1932
|
+
: t("sidebar.nameMadePrivate", { name: d.name }),
|
|
1933
|
+
);
|
|
1934
|
+
return;
|
|
1935
|
+
}
|
|
2036
1936
|
const queryKey = [
|
|
2037
1937
|
"sql-dashboards-sidebar",
|
|
2038
1938
|
dashboardsSyncRef.current,
|
|
@@ -2066,143 +1966,6 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
2066
1966
|
[queryClient, setResourceVisibility, t],
|
|
2067
1967
|
);
|
|
2068
1968
|
|
|
2069
|
-
const handleAnalysisSetVisibility = useCallback(
|
|
2070
|
-
async (a: { id: string; name: string }, visibility: Visibility) => {
|
|
2071
|
-
const sidebarKey = ["analyses-sidebar", analysesSyncRef.current] as const;
|
|
2072
|
-
const listKey = ["analyses-list"] as const;
|
|
2073
|
-
const prevSidebar = getQuerySnapshots<
|
|
2074
|
-
{ id: string; name: string; visibility?: Visibility }[]
|
|
2075
|
-
>(queryClient, sidebarKey);
|
|
2076
|
-
const prevList = getQuerySnapshots<any[]>(queryClient, listKey);
|
|
2077
|
-
queryClient.setQueriesData<
|
|
2078
|
-
{ id: string; name: string; visibility?: Visibility }[]
|
|
2079
|
-
>({ queryKey: sidebarKey }, (old) =>
|
|
2080
|
-
(old ?? []).map((item) =>
|
|
2081
|
-
item.id === a.id ? { ...item, visibility } : item,
|
|
2082
|
-
),
|
|
2083
|
-
);
|
|
2084
|
-
queryClient.setQueriesData<any[]>({ queryKey: listKey }, (old) =>
|
|
2085
|
-
(old ?? []).map((item) =>
|
|
2086
|
-
item.id === a.id ? { ...item, visibility } : item,
|
|
2087
|
-
),
|
|
2088
|
-
);
|
|
2089
|
-
try {
|
|
2090
|
-
await setResourceVisibility({
|
|
2091
|
-
resourceType: "analysis",
|
|
2092
|
-
resourceId: a.id,
|
|
2093
|
-
visibility,
|
|
2094
|
-
} as any);
|
|
2095
|
-
queryClient.invalidateQueries({ queryKey: sidebarKey });
|
|
2096
|
-
queryClient.invalidateQueries({ queryKey: listKey });
|
|
2097
|
-
toast.success(
|
|
2098
|
-
visibility === "org"
|
|
2099
|
-
? t("sidebar.nameSharedWithOrg", { name: a.name })
|
|
2100
|
-
: t("sidebar.nameMadePrivate", { name: a.name }),
|
|
2101
|
-
);
|
|
2102
|
-
} catch (err) {
|
|
2103
|
-
restoreQuerySnapshots(queryClient, prevSidebar);
|
|
2104
|
-
restoreQuerySnapshots(queryClient, prevList);
|
|
2105
|
-
throw err;
|
|
2106
|
-
}
|
|
2107
|
-
},
|
|
2108
|
-
[queryClient, setResourceVisibility, t],
|
|
2109
|
-
);
|
|
2110
|
-
|
|
2111
|
-
const handleAnalysisRename = useCallback(
|
|
2112
|
-
async (a: { id: string; name: string }, name: string) => {
|
|
2113
|
-
const trimmed = name.trim();
|
|
2114
|
-
if (!trimmed || trimmed === a.name) return;
|
|
2115
|
-
|
|
2116
|
-
const sidebarKey = ["analyses-sidebar"] as const;
|
|
2117
|
-
const listKey = ["analyses-list"] as const;
|
|
2118
|
-
const detailKey = ["analysis-detail", a.id] as const;
|
|
2119
|
-
const prevSidebar = getQuerySnapshots<{ id: string; name: string }[]>(
|
|
2120
|
-
queryClient,
|
|
2121
|
-
sidebarKey,
|
|
2122
|
-
);
|
|
2123
|
-
const prevList = getQuerySnapshots<any[]>(queryClient, listKey);
|
|
2124
|
-
const prevDetail = getQuerySnapshots<any>(queryClient, detailKey);
|
|
2125
|
-
|
|
2126
|
-
queryClient.setQueriesData<{ id: string; name: string }[]>(
|
|
2127
|
-
{ queryKey: sidebarKey },
|
|
2128
|
-
(old) =>
|
|
2129
|
-
(old ?? []).map((item) =>
|
|
2130
|
-
item.id === a.id ? { ...item, name: trimmed } : item,
|
|
2131
|
-
),
|
|
2132
|
-
);
|
|
2133
|
-
queryClient.setQueriesData<any[]>({ queryKey: listKey }, (old) =>
|
|
2134
|
-
(old ?? []).map((item) =>
|
|
2135
|
-
item.id === a.id ? { ...item, name: trimmed } : item,
|
|
2136
|
-
),
|
|
2137
|
-
);
|
|
2138
|
-
queryClient.setQueriesData<any>({ queryKey: detailKey }, (old: any) =>
|
|
2139
|
-
old ? { ...old, name: trimmed } : old,
|
|
2140
|
-
);
|
|
2141
|
-
|
|
2142
|
-
try {
|
|
2143
|
-
await renameAnalysis({ id: a.id, name: trimmed });
|
|
2144
|
-
queryClient.removeQueries({
|
|
2145
|
-
queryKey: analysisDetailPrefetchKey(a.id),
|
|
2146
|
-
});
|
|
2147
|
-
queryClient.invalidateQueries({ queryKey: sidebarKey });
|
|
2148
|
-
queryClient.invalidateQueries({ queryKey: listKey });
|
|
2149
|
-
queryClient.invalidateQueries({ queryKey: detailKey });
|
|
2150
|
-
} catch (err) {
|
|
2151
|
-
restoreQuerySnapshots(queryClient, prevSidebar);
|
|
2152
|
-
restoreQuerySnapshots(queryClient, prevList);
|
|
2153
|
-
restoreQuerySnapshots(queryClient, prevDetail);
|
|
2154
|
-
throw err;
|
|
2155
|
-
}
|
|
2156
|
-
},
|
|
2157
|
-
[queryClient, renameAnalysis],
|
|
2158
|
-
);
|
|
2159
|
-
|
|
2160
|
-
const handleAnalysisHide = useCallback(
|
|
2161
|
-
async (a: { id: string; name: string }) => {
|
|
2162
|
-
const sidebarKey = ["analyses-sidebar"] as const;
|
|
2163
|
-
const prev = getQuerySnapshots<{ id: string }[]>(queryClient, sidebarKey);
|
|
2164
|
-
// Optimistically drop it from the visible list (the hidden-filter
|
|
2165
|
-
// variant is invalidated below to pick it up).
|
|
2166
|
-
queryClient.setQueriesData<{ id: string }[]>(
|
|
2167
|
-
{ queryKey: sidebarKey },
|
|
2168
|
-
(old) => (old ?? []).filter((item) => item.id !== a.id),
|
|
2169
|
-
);
|
|
2170
|
-
try {
|
|
2171
|
-
await hideAnalysisMut({ id: a.id, hidden: true });
|
|
2172
|
-
queryClient.invalidateQueries({ queryKey: sidebarKey });
|
|
2173
|
-
queryClient.invalidateQueries({ queryKey: ["analyses-list"] });
|
|
2174
|
-
toast.success(t("sidebar.nameHidden", { name: a.name }));
|
|
2175
|
-
} catch (err) {
|
|
2176
|
-
restoreQuerySnapshots(queryClient, prev);
|
|
2177
|
-
throw err;
|
|
2178
|
-
}
|
|
2179
|
-
},
|
|
2180
|
-
[queryClient, hideAnalysisMut, t],
|
|
2181
|
-
);
|
|
2182
|
-
|
|
2183
|
-
const handleAnalysisUnhide = useCallback(
|
|
2184
|
-
async (a: { id: string; name: string }) => {
|
|
2185
|
-
const sidebarKey = ["analyses-sidebar"] as const;
|
|
2186
|
-
const prev = getQuerySnapshots<{ id: string }[]>(queryClient, sidebarKey);
|
|
2187
|
-
// Optimistically drop it from the hidden list (the visible variant is
|
|
2188
|
-
// invalidated below to pick it up).
|
|
2189
|
-
queryClient.setQueriesData<{ id: string }[]>(
|
|
2190
|
-
{ queryKey: sidebarKey },
|
|
2191
|
-
(old) => (old ?? []).filter((item) => item.id !== a.id),
|
|
2192
|
-
);
|
|
2193
|
-
try {
|
|
2194
|
-
await hideAnalysisMut({ id: a.id, hidden: false });
|
|
2195
|
-
queryClient.invalidateQueries({ queryKey: sidebarKey });
|
|
2196
|
-
queryClient.invalidateQueries({ queryKey: ["analyses-list"] });
|
|
2197
|
-
toast.success(t("sidebar.nameUnhidden", { name: a.name }));
|
|
2198
|
-
} catch (err) {
|
|
2199
|
-
restoreQuerySnapshots(queryClient, prev);
|
|
2200
|
-
throw err;
|
|
2201
|
-
}
|
|
2202
|
-
},
|
|
2203
|
-
[queryClient, hideAnalysisMut, t],
|
|
2204
|
-
);
|
|
2205
|
-
|
|
2206
1969
|
const sensors = useSensors(
|
|
2207
1970
|
useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
|
|
2208
1971
|
useSensor(KeyboardSensor, {
|
|
@@ -2226,24 +1989,6 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
2226
1989
|
[setDashboardSortMode, dashboardRenderOrderIds],
|
|
2227
1990
|
);
|
|
2228
1991
|
|
|
2229
|
-
const handleAnalysisDragEnd = useCallback(
|
|
2230
|
-
(event: DragEndEvent) => {
|
|
2231
|
-
const { active, over } = event;
|
|
2232
|
-
if (!over || active.id === over.id) return;
|
|
2233
|
-
setAnalysisSortMode("manual");
|
|
2234
|
-
setAnalysisOrderState((prev) => {
|
|
2235
|
-
const ids = prev.length > 0 ? prev : sortedAnalyses.map((a) => a.id);
|
|
2236
|
-
const oldIndex = ids.indexOf(active.id as string);
|
|
2237
|
-
const newIndex = ids.indexOf(over.id as string);
|
|
2238
|
-
if (oldIndex === -1 || newIndex === -1) return prev;
|
|
2239
|
-
const newOrder = arrayMove(ids, oldIndex, newIndex);
|
|
2240
|
-
setAnalysisOrder(newOrder);
|
|
2241
|
-
return newOrder;
|
|
2242
|
-
});
|
|
2243
|
-
},
|
|
2244
|
-
[setAnalysisSortMode, sortedAnalyses],
|
|
2245
|
-
);
|
|
2246
|
-
|
|
2247
1992
|
const handleResizeStart = useCallback(
|
|
2248
1993
|
(e: React.MouseEvent) => {
|
|
2249
1994
|
if (effectiveCollapsed) return;
|
|
@@ -2283,7 +2028,8 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
2283
2028
|
|
|
2284
2029
|
const isAdhocActive =
|
|
2285
2030
|
location.pathname.startsWith("/adhoc") ||
|
|
2286
|
-
location.pathname.startsWith("/dashboards")
|
|
2031
|
+
location.pathname.startsWith("/dashboards") ||
|
|
2032
|
+
location.pathname.startsWith("/analyses");
|
|
2287
2033
|
|
|
2288
2034
|
useEffect(() => {
|
|
2289
2035
|
if (typeof window === "undefined") return;
|
|
@@ -2322,12 +2068,6 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
2322
2068
|
href: "/dashboards",
|
|
2323
2069
|
active: isAdhocActive,
|
|
2324
2070
|
},
|
|
2325
|
-
{
|
|
2326
|
-
icon: IconReportAnalytics,
|
|
2327
|
-
label: t("navigation.analyses"),
|
|
2328
|
-
href: "/analyses",
|
|
2329
|
-
active: location.pathname.startsWith("/analyses"),
|
|
2330
|
-
},
|
|
2331
2071
|
{
|
|
2332
2072
|
icon: IconPlayerPlay,
|
|
2333
2073
|
label: t("navigation.sessions"),
|
|
@@ -2372,6 +2112,63 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
2372
2112
|
},
|
|
2373
2113
|
];
|
|
2374
2114
|
|
|
2115
|
+
const footerSearch = (
|
|
2116
|
+
<Tooltip>
|
|
2117
|
+
<TooltipTrigger asChild>
|
|
2118
|
+
<button
|
|
2119
|
+
type="button"
|
|
2120
|
+
onClick={openCommandMenu}
|
|
2121
|
+
aria-label={t("sidebar.search")}
|
|
2122
|
+
className="flex h-8 w-8 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-sidebar-accent/50 hover:text-foreground"
|
|
2123
|
+
>
|
|
2124
|
+
<IconSearch className="h-4 w-4" />
|
|
2125
|
+
</button>
|
|
2126
|
+
</TooltipTrigger>
|
|
2127
|
+
<TooltipContent side="top">
|
|
2128
|
+
{t("sidebar.searchShortcut", {
|
|
2129
|
+
shortcut: `${shortcutModifierLabel()}+K`,
|
|
2130
|
+
})}
|
|
2131
|
+
</TooltipContent>
|
|
2132
|
+
</Tooltip>
|
|
2133
|
+
);
|
|
2134
|
+
const footerTranslate = (
|
|
2135
|
+
<LanguagePicker variant="ghost-icon" label={t("settings.languageLabel")} />
|
|
2136
|
+
);
|
|
2137
|
+
const footerCollapse = !mobile ? (
|
|
2138
|
+
<Tooltip>
|
|
2139
|
+
<TooltipTrigger asChild>
|
|
2140
|
+
<button
|
|
2141
|
+
type="button"
|
|
2142
|
+
onClick={() => setSidebarCollapsed(!effectiveCollapsed)}
|
|
2143
|
+
aria-label={
|
|
2144
|
+
effectiveCollapsed
|
|
2145
|
+
? t("sidebar.expandSidebar")
|
|
2146
|
+
: t("sidebar.collapseSidebar")
|
|
2147
|
+
}
|
|
2148
|
+
className="flex h-8 w-8 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-sidebar-accent/50 hover:text-foreground"
|
|
2149
|
+
>
|
|
2150
|
+
{effectiveCollapsed ? (
|
|
2151
|
+
<IconLayoutSidebarLeftExpand className="h-4 w-4 rtl:-scale-x-100" />
|
|
2152
|
+
) : (
|
|
2153
|
+
<IconLayoutSidebarLeftCollapse className="h-4 w-4 rtl:-scale-x-100" />
|
|
2154
|
+
)}
|
|
2155
|
+
</button>
|
|
2156
|
+
</TooltipTrigger>
|
|
2157
|
+
<TooltipContent side="top">
|
|
2158
|
+
{effectiveCollapsed
|
|
2159
|
+
? t("sidebar.expandSidebar")
|
|
2160
|
+
: t("sidebar.collapseSidebar")}
|
|
2161
|
+
</TooltipContent>
|
|
2162
|
+
</Tooltip>
|
|
2163
|
+
) : null;
|
|
2164
|
+
const footerFeedback = (
|
|
2165
|
+
<FeedbackButton
|
|
2166
|
+
variant={effectiveCollapsed ? "icon" : "sidebar"}
|
|
2167
|
+
side="right"
|
|
2168
|
+
className={effectiveCollapsed ? "h-8 w-8" : "min-w-0"}
|
|
2169
|
+
/>
|
|
2170
|
+
);
|
|
2171
|
+
|
|
2375
2172
|
return (
|
|
2376
2173
|
<div
|
|
2377
2174
|
className="relative flex h-full min-w-0 flex-col overflow-hidden border-r border-border bg-sidebar text-sidebar-foreground transition-[width] duration-200 ease-out"
|
|
@@ -2387,24 +2184,6 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
2387
2184
|
)}
|
|
2388
2185
|
{effectiveCollapsed ? (
|
|
2389
2186
|
<>
|
|
2390
|
-
<div className="flex h-12 shrink-0 items-center justify-center border-b border-border px-1">
|
|
2391
|
-
<Tooltip>
|
|
2392
|
-
<TooltipTrigger asChild>
|
|
2393
|
-
<button
|
|
2394
|
-
type="button"
|
|
2395
|
-
onClick={() => setSidebarCollapsed(false)}
|
|
2396
|
-
aria-label={t("sidebar.expandSidebar")}
|
|
2397
|
-
className="flex h-10 w-10 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-sidebar-accent/50 hover:text-foreground"
|
|
2398
|
-
>
|
|
2399
|
-
<IconLayoutSidebarLeftExpand className="h-4 w-4 rtl:-scale-x-100" />
|
|
2400
|
-
</button>
|
|
2401
|
-
</TooltipTrigger>
|
|
2402
|
-
<TooltipContent side="right">
|
|
2403
|
-
{t("sidebar.expandSidebar")}
|
|
2404
|
-
</TooltipContent>
|
|
2405
|
-
</Tooltip>
|
|
2406
|
-
</div>
|
|
2407
|
-
|
|
2408
2187
|
<nav className="flex min-h-0 flex-1 flex-col items-center gap-1 overflow-y-auto px-1 py-2">
|
|
2409
2188
|
{collapsedNavItems.map((item) => {
|
|
2410
2189
|
const Icon = item.icon;
|
|
@@ -2430,6 +2209,13 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
2430
2209
|
);
|
|
2431
2210
|
})}
|
|
2432
2211
|
</nav>
|
|
2212
|
+
<SidebarFooterActions
|
|
2213
|
+
collapsed
|
|
2214
|
+
feedback={footerFeedback}
|
|
2215
|
+
translate={footerTranslate}
|
|
2216
|
+
search={footerSearch}
|
|
2217
|
+
collapse={footerCollapse}
|
|
2218
|
+
/>
|
|
2433
2219
|
</>
|
|
2434
2220
|
) : (
|
|
2435
2221
|
<>
|
|
@@ -2454,23 +2240,6 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
2454
2240
|
{t("navigation.brand")}
|
|
2455
2241
|
</span>
|
|
2456
2242
|
</Link>
|
|
2457
|
-
{!mobile && (
|
|
2458
|
-
<Tooltip>
|
|
2459
|
-
<TooltipTrigger asChild>
|
|
2460
|
-
<button
|
|
2461
|
-
type="button"
|
|
2462
|
-
onClick={() => setSidebarCollapsed(true)}
|
|
2463
|
-
aria-label={t("sidebar.collapseSidebar")}
|
|
2464
|
-
className="flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-sidebar-accent/50 hover:text-foreground"
|
|
2465
|
-
>
|
|
2466
|
-
<IconLayoutSidebarLeftCollapse className="h-4 w-4 rtl:-scale-x-100" />
|
|
2467
|
-
</button>
|
|
2468
|
-
</TooltipTrigger>
|
|
2469
|
-
<TooltipContent side="right">
|
|
2470
|
-
{t("sidebar.collapseSidebar")}
|
|
2471
|
-
</TooltipContent>
|
|
2472
|
-
</Tooltip>
|
|
2473
|
-
)}
|
|
2474
2243
|
</div>
|
|
2475
2244
|
<div className="flex min-h-0 flex-1 flex-col overflow-y-auto overflow-x-hidden py-2">
|
|
2476
2245
|
<nav className="grid min-w-0 items-start px-2 text-sm font-medium lg:px-4 space-y-1">
|
|
@@ -2524,7 +2293,9 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
2524
2293
|
/>
|
|
2525
2294
|
</button>
|
|
2526
2295
|
</div>
|
|
2527
|
-
{askOpen &&
|
|
2296
|
+
{askOpen && isAskRoute ? (
|
|
2297
|
+
<AnalyticsChatsSection isAskRoute open />
|
|
2298
|
+
) : null}
|
|
2528
2299
|
</div>
|
|
2529
2300
|
|
|
2530
2301
|
{/* Sessions link */}
|
|
@@ -2665,7 +2436,11 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
2665
2436
|
<Fragment key={d.id}>
|
|
2666
2437
|
<SortableDashboardItem
|
|
2667
2438
|
d={d}
|
|
2668
|
-
isActive={
|
|
2439
|
+
isActive={
|
|
2440
|
+
d.source === "analysis"
|
|
2441
|
+
? activeAnalysisId === d.resourceId
|
|
2442
|
+
: activeDashboardId === d.id
|
|
2443
|
+
}
|
|
2669
2444
|
location={location}
|
|
2670
2445
|
favoriteIds={favoriteIds}
|
|
2671
2446
|
onToggleFavorite={toggleFavorite}
|
|
@@ -2683,7 +2458,10 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
2683
2458
|
key={child.id}
|
|
2684
2459
|
d={child}
|
|
2685
2460
|
isActive={
|
|
2686
|
-
|
|
2461
|
+
child.source === "analysis"
|
|
2462
|
+
? activeAnalysisId ===
|
|
2463
|
+
child.resourceId
|
|
2464
|
+
: activeDashboardId === child.id
|
|
2687
2465
|
}
|
|
2688
2466
|
location={location}
|
|
2689
2467
|
favoriteIds={favoriteIds}
|
|
@@ -2746,156 +2524,30 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
2746
2524
|
onRetry={() => void refetchSqlDashboards()}
|
|
2747
2525
|
/>
|
|
2748
2526
|
)}
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
)}
|
|
2765
|
-
>
|
|
2766
|
-
<button
|
|
2767
|
-
type="button"
|
|
2768
|
-
onClick={toggleAnalysesOpen}
|
|
2769
|
-
className="flex min-w-0 flex-1 items-center gap-3 px-3 py-2 text-start"
|
|
2770
|
-
aria-expanded={analysesOpen}
|
|
2771
|
-
>
|
|
2772
|
-
<IconReportAnalytics className="h-4 w-4 shrink-0" />
|
|
2773
|
-
<span className="min-w-0 flex-1 truncate">
|
|
2774
|
-
{t("navigation.analyses")}
|
|
2775
|
-
</span>
|
|
2776
|
-
</button>
|
|
2777
|
-
<SidebarSectionSettingsPopover
|
|
2778
|
-
label={t("navigation.analyses")}
|
|
2779
|
-
sortMode={analysisSortMode}
|
|
2780
|
-
onSortModeChange={setAnalysisSortMode}
|
|
2781
|
-
visibilityFilter={analysisFilter}
|
|
2782
|
-
onVisibilityFilterChange={setAnalysisFilter}
|
|
2783
|
-
showHidden={analysisHiddenFilter === "hidden"}
|
|
2784
|
-
onShowHiddenChange={(checked) =>
|
|
2785
|
-
setAnalysisHiddenFilter(checked ? "hidden" : "visible")
|
|
2786
|
-
}
|
|
2787
|
-
/>
|
|
2788
|
-
<button
|
|
2789
|
-
type="button"
|
|
2790
|
-
onClick={toggleAnalysesOpen}
|
|
2791
|
-
className="me-1 flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-muted-foreground/70 hover:bg-sidebar-accent hover:text-foreground"
|
|
2792
|
-
aria-label={
|
|
2793
|
-
analysesOpen
|
|
2794
|
-
? t("sidebar.collapseAnalyses")
|
|
2795
|
-
: t("sidebar.expandAnalyses")
|
|
2796
|
-
}
|
|
2797
|
-
>
|
|
2798
|
-
<IconChevronDown
|
|
2799
|
-
className={cn(
|
|
2800
|
-
"h-3.5 w-3.5 shrink-0 transition-transform",
|
|
2801
|
-
!analysesOpen && "-rotate-90",
|
|
2802
|
-
)}
|
|
2803
|
-
/>
|
|
2804
|
-
</button>
|
|
2805
|
-
</div>
|
|
2806
|
-
|
|
2807
|
-
{analysesOpen && (
|
|
2808
|
-
<DndContext
|
|
2809
|
-
sensors={sensors}
|
|
2810
|
-
collisionDetection={closestCenter}
|
|
2811
|
-
onDragEnd={handleAnalysisDragEnd}
|
|
2812
|
-
>
|
|
2813
|
-
<SortableContext
|
|
2814
|
-
items={displayedAnalyses.map((a) => a.id)}
|
|
2815
|
-
strategy={verticalListSortingStrategy}
|
|
2816
|
-
>
|
|
2817
|
-
<div className="ms-4 min-w-0 space-y-0.5">
|
|
2818
|
-
{displayedAnalyses.map((a) => (
|
|
2819
|
-
<SortableRow
|
|
2820
|
-
key={a.id}
|
|
2821
|
-
id={a.id}
|
|
2822
|
-
favoriteKey={`analysis:${a.id}`}
|
|
2823
|
-
name={a.name}
|
|
2824
|
-
href={`/analyses/${a.id}`}
|
|
2825
|
-
isActive={location.pathname === `/analyses/${a.id}`}
|
|
2826
|
-
favoriteIds={favoriteIds}
|
|
2827
|
-
onToggleFavorite={toggleFavorite}
|
|
2828
|
-
onDelete={() => handleAnalysisDelete(a)}
|
|
2829
|
-
onRename={(name) => handleAnalysisRename(a, name)}
|
|
2830
|
-
hidden={analysisHiddenFilter === "hidden"}
|
|
2831
|
-
onHide={
|
|
2832
|
-
analysisHiddenFilter === "hidden"
|
|
2833
|
-
? undefined
|
|
2834
|
-
: () => handleAnalysisHide(a)
|
|
2835
|
-
}
|
|
2836
|
-
onUnhide={
|
|
2837
|
-
analysisHiddenFilter === "hidden"
|
|
2838
|
-
? () => handleAnalysisUnhide(a)
|
|
2839
|
-
: undefined
|
|
2840
|
-
}
|
|
2841
|
-
visibility={a.visibility}
|
|
2842
|
-
onSetVisibility={(v) =>
|
|
2843
|
-
handleAnalysisSetVisibility(a, v)
|
|
2844
|
-
}
|
|
2845
|
-
onPrefetch={() => prefetchAnalysis(a.id)}
|
|
2846
|
-
/>
|
|
2847
|
-
))}
|
|
2848
|
-
{filteredAnalyses.length > SIDEBAR_PREVIEW_COUNT && (
|
|
2849
|
-
<button
|
|
2850
|
-
onClick={() => setAnalysesShowAll(!analysesShowAll)}
|
|
2851
|
-
className="flex items-center gap-1 px-3 py-1 text-[11px] text-muted-foreground/70 hover:text-primary"
|
|
2852
|
-
>
|
|
2853
|
-
{analysesShowAll
|
|
2854
|
-
? t("sidebar.showLess")
|
|
2855
|
-
: t("sidebar.showMore", {
|
|
2856
|
-
count:
|
|
2857
|
-
filteredAnalyses.length -
|
|
2858
|
-
SIDEBAR_PREVIEW_COUNT,
|
|
2859
|
-
})}
|
|
2860
|
-
</button>
|
|
2527
|
+
{analysesLoading && analysesList.length === 0 && (
|
|
2528
|
+
<div className="flex items-center gap-2 px-3 py-1">
|
|
2529
|
+
<Skeleton
|
|
2530
|
+
className={cn(
|
|
2531
|
+
"h-3.5 w-3.5 shrink-0 rounded-sm",
|
|
2532
|
+
SIDEBAR_SKELETON_CLASS,
|
|
2533
|
+
)}
|
|
2534
|
+
/>
|
|
2535
|
+
<Skeleton
|
|
2536
|
+
className={cn(
|
|
2537
|
+
"h-3 w-3/4 rounded",
|
|
2538
|
+
SIDEBAR_SKELETON_CLASS,
|
|
2539
|
+
)}
|
|
2540
|
+
/>
|
|
2541
|
+
</div>
|
|
2861
2542
|
)}
|
|
2862
|
-
{
|
|
2863
|
-
sortedAnalyses.length === 0 &&
|
|
2864
|
-
Array.from({ length: 3 }).map((_, i) => (
|
|
2865
|
-
<div
|
|
2866
|
-
key={`analysis-skeleton-${i}`}
|
|
2867
|
-
className="flex items-center gap-2 px-3 py-1"
|
|
2868
|
-
>
|
|
2869
|
-
<Skeleton
|
|
2870
|
-
className={cn(
|
|
2871
|
-
"h-3.5 w-3.5 shrink-0 rounded-sm",
|
|
2872
|
-
SIDEBAR_SKELETON_CLASS,
|
|
2873
|
-
)}
|
|
2874
|
-
/>
|
|
2875
|
-
<Skeleton
|
|
2876
|
-
className={cn(
|
|
2877
|
-
"h-3 rounded",
|
|
2878
|
-
SIDEBAR_SKELETON_CLASS,
|
|
2879
|
-
)}
|
|
2880
|
-
style={{ width: `${60 + ((i * 17) % 30)}%` }}
|
|
2881
|
-
/>
|
|
2882
|
-
</div>
|
|
2883
|
-
))}
|
|
2884
|
-
{analysesError && sortedAnalyses.length === 0 && (
|
|
2543
|
+
{analysesError && analysesList.length === 0 && (
|
|
2885
2544
|
<SidebarLoadError
|
|
2886
2545
|
message={t("sidebar.analysesLoadFailed")}
|
|
2887
2546
|
retryLabel={t("sidebar.retry")}
|
|
2888
2547
|
onRetry={() => void refetchAnalyses()}
|
|
2889
2548
|
/>
|
|
2890
2549
|
)}
|
|
2891
|
-
|
|
2892
|
-
!analysesError &&
|
|
2893
|
-
sortedAnalyses.length === 0 && (
|
|
2894
|
-
<p className="px-3 py-1 text-[11px] text-muted-foreground/60">
|
|
2895
|
-
{t("sidebar.noAnalysesYet")}
|
|
2896
|
-
</p>
|
|
2897
|
-
)}
|
|
2898
|
-
<NewAnalysisDialog />
|
|
2550
|
+
<NewDashboardDialog />
|
|
2899
2551
|
</div>
|
|
2900
2552
|
</SortableContext>
|
|
2901
2553
|
</DndContext>
|
|
@@ -2920,54 +2572,31 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
2920
2572
|
)}
|
|
2921
2573
|
>
|
|
2922
2574
|
<Icon className="h-4 w-4" />
|
|
2923
|
-
|
|
2575
|
+
<span className="flex min-w-0 items-center gap-1">
|
|
2576
|
+
<span className="truncate">{t(item.labelKey)}</span>
|
|
2577
|
+
{item.showExternalLinkIcon && (
|
|
2578
|
+
<IconArrowUpRight
|
|
2579
|
+
aria-hidden="true"
|
|
2580
|
+
className="h-3.5 w-3.5 shrink-0 text-muted-foreground/70"
|
|
2581
|
+
/>
|
|
2582
|
+
)}
|
|
2583
|
+
</span>
|
|
2924
2584
|
</Link>
|
|
2925
2585
|
);
|
|
2926
2586
|
})}
|
|
2927
2587
|
</nav>
|
|
2928
2588
|
|
|
2929
|
-
<div className="min-w-0">
|
|
2930
|
-
<ExtensionsSidebarSection />
|
|
2931
|
-
</div>
|
|
2932
|
-
|
|
2933
2589
|
<div className="space-y-2 pt-2">
|
|
2934
2590
|
<OrgSwitcher />
|
|
2591
|
+
<DevDatabaseLink />
|
|
2935
2592
|
<TooltipProvider delayDuration={200}>
|
|
2936
|
-
<
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
onClick={() =>
|
|
2944
|
-
window.dispatchEvent(
|
|
2945
|
-
new CustomEvent(
|
|
2946
|
-
"analytics:open-command-palette",
|
|
2947
|
-
),
|
|
2948
|
-
)
|
|
2949
|
-
}
|
|
2950
|
-
aria-label={t("sidebar.search")}
|
|
2951
|
-
className="flex items-center justify-center rounded-lg p-2 text-muted-foreground transition-colors hover:text-primary cursor-pointer hover:bg-sidebar-accent/50"
|
|
2952
|
-
>
|
|
2953
|
-
<IconSearch className="h-4 w-4" />
|
|
2954
|
-
</button>
|
|
2955
|
-
</TooltipTrigger>
|
|
2956
|
-
<TooltipContent side="top">
|
|
2957
|
-
<p>
|
|
2958
|
-
{t("sidebar.searchShortcut", {
|
|
2959
|
-
shortcut: `${shortcutModifierLabel()}+K`,
|
|
2960
|
-
})}
|
|
2961
|
-
</p>
|
|
2962
|
-
</TooltipContent>
|
|
2963
|
-
</Tooltip>
|
|
2964
|
-
<LanguagePicker
|
|
2965
|
-
variant="icon"
|
|
2966
|
-
label={t("settings.languageLabel")}
|
|
2967
|
-
className="[&_[data-language-picker-trigger]]:rounded-lg [&_[data-language-picker-trigger]]:border-0 [&_[data-language-picker-trigger]]:bg-transparent [&_[data-language-picker-trigger]]:text-muted-foreground [&_[data-language-picker-trigger]]:hover:bg-sidebar-accent/50 [&_[data-language-picker-trigger]]:hover:text-primary"
|
|
2968
|
-
/>
|
|
2969
|
-
</div>
|
|
2970
|
-
</div>
|
|
2593
|
+
<SidebarFooterActions
|
|
2594
|
+
feedback={footerFeedback}
|
|
2595
|
+
translate={footerTranslate}
|
|
2596
|
+
search={footerSearch}
|
|
2597
|
+
collapse={footerCollapse}
|
|
2598
|
+
className="px-0 py-0"
|
|
2599
|
+
/>
|
|
2971
2600
|
</TooltipProvider>
|
|
2972
2601
|
</div>
|
|
2973
2602
|
</div>
|