@agent-native/core 0.108.0 → 0.109.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +18 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/client.ts +140 -17
- package/corpus/core/src/a2a/handlers.ts +60 -0
- package/corpus/core/src/a2a/index.ts +6 -1
- package/corpus/core/src/a2a/invoke.ts +68 -1
- package/corpus/core/src/a2a/server.ts +13 -1
- package/corpus/core/src/a2a/types.ts +16 -0
- package/corpus/core/src/action.ts +3 -2
- package/corpus/core/src/agent/production-agent.ts +10 -4
- package/corpus/core/src/client/AssistantChat.tsx +648 -603
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +31 -4
- package/corpus/core/src/client/agent-chat-adapter.ts +23 -37
- package/corpus/core/src/client/agent-sidebar-state.ts +4 -0
- package/corpus/core/src/client/analytics.ts +84 -0
- package/corpus/core/src/client/chat/message-components.tsx +94 -22
- package/corpus/core/src/client/chat/tool-call-display.tsx +170 -47
- package/corpus/core/src/client/chat/use-agent-chat-lifecycle-tracking.ts +74 -0
- package/corpus/core/src/client/chat-thread-url.ts +11 -0
- package/corpus/core/src/client/error-capture.ts +12 -0
- package/corpus/core/src/client/extensions/ExtensionSlot.tsx +37 -1
- package/corpus/core/src/client/index.ts +2 -0
- package/corpus/core/src/client/route-chunk-recovery.ts +20 -8
- package/corpus/core/src/client/session-replay.ts +31 -0
- package/corpus/core/src/extensions/actions.ts +2 -14
- package/corpus/core/src/extensions/store.ts +1 -1
- package/corpus/core/src/localization/default-messages.ts +3 -0
- package/corpus/core/src/mcp/build-server.ts +2 -2
- package/corpus/core/src/progress/actions.ts +4 -2
- package/corpus/core/src/provider-api/index.ts +205 -105
- package/corpus/core/src/scripts/call-agent.ts +137 -17
- package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +40 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +31 -0
- package/corpus/core/src/styles/agent-conversation.css +7 -0
- package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/de-DE.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/en-US.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/es-ES.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +21 -0
- package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +19 -0
- package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +19 -0
- package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +19 -0
- package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +19 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +28 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +29 -10
- package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +54 -23
- package/corpus/templates/analytics/.builder/skills/apollo/SKILL.md +19 -41
- package/corpus/templates/analytics/.builder/skills/commonroom/SKILL.md +20 -35
- package/corpus/templates/analytics/.builder/skills/github/SKILL.md +23 -67
- package/corpus/templates/analytics/.builder/skills/pylon/SKILL.md +25 -43
- package/corpus/templates/analytics/AGENTS.md +22 -13
- package/corpus/templates/analytics/actions/account-deep-dive.ts +1 -0
- package/corpus/templates/analytics/actions/configure-gong-native-insights.ts +29 -0
- package/corpus/templates/analytics/actions/content-calendar-schema.ts +8 -4
- package/corpus/templates/analytics/actions/content-calendar.ts +12 -4
- package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +2 -1
- package/corpus/templates/analytics/actions/gong-calls.ts +113 -22
- package/corpus/templates/analytics/actions/gong-native-insights.ts +166 -0
- package/corpus/templates/analytics/actions/hubspot-deals.ts +190 -46
- package/corpus/templates/analytics/actions/pylon-issues.ts +123 -0
- package/corpus/templates/analytics/actions/slack-messages.ts +179 -27
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +48 -152
- package/corpus/templates/analytics/app/components/ui/chart.tsx +1 -1
- package/corpus/templates/analytics/app/hooks/use-chart-tooltip-flip.ts +21 -6
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +13 -0
- package/corpus/templates/analytics/app/i18n-data.ts +134 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +181 -30
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +6 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +4 -3
- package/corpus/templates/analytics/changelog/2026-07-17-dashboard-editors-can-add-shared-extensions-or-opt-into-per-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-dashboard-extensions-show-a-loading-skeleton.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-errors-now-group-repeat-failures-consistently-and-keep-priva.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-gong-transcript-reviews-now-batch-bounded-call-windows-for-f.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-hubspot-deal-filters-now-run-in-hubspot-before-paging-result.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-notion-content-calendars-now-discover-the-matching-database-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-pylon-dashboard-reads-now-use-the-paginated-issue-search-api.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-slack-reads-no-longer-join-channels-and-report-pagination-coverage.md +6 -0
- package/corpus/templates/analytics/server/handlers/notion.ts +14 -3
- package/corpus/templates/analytics/server/handlers/slack.ts +182 -29
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +2 -6
- package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +6 -2
- package/corpus/templates/analytics/server/lib/error-capture.ts +75 -8
- package/corpus/templates/analytics/server/lib/gong-native-policy.ts +72 -0
- package/corpus/templates/analytics/server/lib/gong.ts +54 -66
- package/corpus/templates/analytics/server/lib/hubspot.ts +40 -3
- package/corpus/templates/analytics/server/lib/notion.ts +83 -8
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +4 -0
- package/corpus/templates/analytics/server/lib/slack.ts +242 -90
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +3 -3
- package/corpus/templates/analytics/server/routes/api/pylon/accounts.get.ts +42 -1
- package/corpus/templates/analytics/server/routes/api/pylon/issues.get.ts +71 -1
- package/corpus/templates/analytics/server/routes/api/test-connection.post.ts +44 -4
- package/corpus/templates/clips/app/components/library/bulk-action-toolbar.tsx +19 -1
- package/corpus/templates/clips/app/components/library/create-folder-dialog.tsx +123 -0
- package/corpus/templates/clips/app/components/library/library-grid.tsx +42 -4
- package/corpus/templates/clips/app/components/library/recording-card.tsx +30 -0
- package/corpus/templates/clips/app/entry.client.tsx +6 -1
- package/corpus/templates/clips/app/i18n/ar-SA.ts +12 -1
- package/corpus/templates/clips/app/i18n/de-DE.ts +12 -1
- package/corpus/templates/clips/app/i18n/en-US.ts +12 -1
- package/corpus/templates/clips/app/i18n/es-ES.ts +11 -1
- package/corpus/templates/clips/app/i18n/fr-FR.ts +11 -1
- package/corpus/templates/clips/app/i18n/hi-IN.ts +10 -1
- package/corpus/templates/clips/app/i18n/ja-JP.ts +12 -1
- package/corpus/templates/clips/app/i18n/ko-KR.ts +11 -1
- package/corpus/templates/clips/app/i18n/pt-BR.ts +11 -1
- package/corpus/templates/clips/app/i18n/zh-CN.ts +11 -1
- package/corpus/templates/clips/app/i18n/zh-TW.ts +11 -1
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +72 -1
- package/corpus/templates/clips/changelog/2026-07-17-choose-which-workspace-receives-new-clips-recordings-and-des.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-create-folders-directly-from-the-move-menu.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-failed-desktop-uploads-now-offer-a-direct-way-to-reopen-clip.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +1 -1
- package/corpus/templates/content/app/entry.client.tsx +6 -1
- package/corpus/templates/dispatch/AGENTS.md +5 -0
- package/corpus/templates/dispatch/changelog/2026-07-17-apps-page-links-to-other-available-apps.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-07-17-curated-template-remixes.md +6 -0
- package/corpus/templates/mail/app/entry.client.tsx +6 -1
- package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +11 -7
- package/corpus/templates/slides/.env.example +0 -1
- package/corpus/templates/slides/AGENTS.md +4 -0
- package/corpus/templates/slides/DEVELOPING.md +2 -2
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +1 -1
- package/corpus/templates/slides/actions/logo-config.ts +6 -7
- package/corpus/templates/slides/actions/search-images.ts +11 -39
- package/corpus/templates/slides/actions/search-logos.ts +5 -52
- package/corpus/templates/slides/app/components/editor/ImageSearchPanel.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/LogoSearchPanel.tsx +16 -26
- package/corpus/templates/slides/app/entry.client.tsx +6 -1
- package/corpus/templates/slides/server/lib/media-search-providers.ts +216 -0
- package/corpus/templates/slides/server/register-secrets.ts +30 -0
- package/dist/a2a/client.d.ts +38 -1
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +81 -12
- package/dist/a2a/client.js.map +1 -1
- package/dist/a2a/handlers.d.ts.map +1 -1
- package/dist/a2a/handlers.js +47 -0
- package/dist/a2a/handlers.js.map +1 -1
- package/dist/a2a/index.d.ts +4 -4
- package/dist/a2a/index.d.ts.map +1 -1
- package/dist/a2a/index.js +2 -2
- package/dist/a2a/index.js.map +1 -1
- package/dist/a2a/invoke.d.ts +26 -2
- package/dist/a2a/invoke.d.ts.map +1 -1
- package/dist/a2a/invoke.js +30 -1
- package/dist/a2a/invoke.js.map +1 -1
- package/dist/a2a/server.d.ts.map +1 -1
- package/dist/a2a/server.js +14 -1
- package/dist/a2a/server.js.map +1 -1
- package/dist/a2a/types.d.ts +12 -0
- package/dist/a2a/types.d.ts.map +1 -1
- package/dist/a2a/types.js.map +1 -1
- package/dist/action.d.ts +3 -2
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js.map +1 -1
- package/dist/agent/production-agent.d.ts +5 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +5 -3
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +14 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +158 -136
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +27 -4
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +21 -39
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/agent-sidebar-state.d.ts +1 -0
- package/dist/client/agent-sidebar-state.d.ts.map +1 -1
- package/dist/client/agent-sidebar-state.js +4 -0
- package/dist/client/agent-sidebar-state.js.map +1 -1
- package/dist/client/analytics.d.ts +14 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +67 -0
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +8 -0
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +62 -19
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +6 -0
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +83 -14
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts +8 -0
- package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts.map +1 -0
- package/dist/client/chat/use-agent-chat-lifecycle-tracking.js +51 -0
- package/dist/client/chat/use-agent-chat-lifecycle-tracking.js.map +1 -0
- package/dist/client/chat-thread-url.d.ts +2 -0
- package/dist/client/chat-thread-url.d.ts.map +1 -0
- package/dist/client/chat-thread-url.js +12 -0
- package/dist/client/chat-thread-url.js.map +1 -0
- package/dist/client/error-capture.d.ts.map +1 -1
- package/dist/client/error-capture.js +7 -0
- package/dist/client/error-capture.js.map +1 -1
- package/dist/client/extensions/ExtensionSlot.d.ts +3 -1
- package/dist/client/extensions/ExtensionSlot.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionSlot.js +28 -3
- package/dist/client/extensions/ExtensionSlot.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/route-chunk-recovery.d.ts.map +1 -1
- package/dist/client/route-chunk-recovery.js +14 -9
- package/dist/client/route-chunk-recovery.js.map +1 -1
- package/dist/client/session-replay.d.ts +15 -0
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +20 -0
- package/dist/client/session-replay.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/extensions/actions.d.ts.map +1 -1
- package/dist/extensions/actions.js +2 -10
- package/dist/extensions/actions.js.map +1 -1
- package/dist/extensions/store.js +1 -1
- package/dist/extensions/store.js.map +1 -1
- package/dist/localization/default-messages.d.ts +3 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +3 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/mcp/build-server.d.ts +2 -0
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +2 -2
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +1 -1
- package/dist/progress/actions.d.ts.map +1 -1
- package/dist/progress/actions.js +3 -2
- package/dist/progress/actions.js.map +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/provider-api/index.d.ts.map +1 -1
- package/dist/provider-api/index.js +91 -8
- package/dist/provider-api/index.js.map +1 -1
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +107 -16
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/server/agent-chat/action-filters-a2a.d.ts +6 -0
- package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
- package/dist/server/agent-chat/action-filters-a2a.js +27 -0
- package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +27 -1
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/styles/agent-conversation.css +7 -0
- package/dist/templates/default/app/i18n/ar-SA.ts +20 -0
- package/dist/templates/default/app/i18n/de-DE.ts +20 -0
- package/dist/templates/default/app/i18n/en-US.ts +20 -0
- package/dist/templates/default/app/i18n/es-ES.ts +20 -0
- package/dist/templates/default/app/i18n/fr-FR.ts +21 -0
- package/dist/templates/default/app/i18n/hi-IN.ts +19 -0
- package/dist/templates/default/app/i18n/ja-JP.ts +20 -0
- package/dist/templates/default/app/i18n/ko-KR.ts +19 -0
- package/dist/templates/default/app/i18n/pt-BR.ts +20 -0
- package/dist/templates/default/app/i18n/zh-CN.ts +19 -0
- package/dist/templates/default/app/i18n/zh-TW.ts +19 -0
- package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +28 -0
- package/dist/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
- package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
- package/package.json +1 -1
- package/src/templates/default/app/i18n/ar-SA.ts +20 -0
- package/src/templates/default/app/i18n/de-DE.ts +20 -0
- package/src/templates/default/app/i18n/en-US.ts +20 -0
- package/src/templates/default/app/i18n/es-ES.ts +20 -0
- package/src/templates/default/app/i18n/fr-FR.ts +21 -0
- package/src/templates/default/app/i18n/hi-IN.ts +19 -0
- package/src/templates/default/app/i18n/ja-JP.ts +20 -0
- package/src/templates/default/app/i18n/ko-KR.ts +19 -0
- package/src/templates/default/app/i18n/pt-BR.ts +20 -0
- package/src/templates/default/app/i18n/zh-CN.ts +19 -0
- package/src/templates/default/app/i18n/zh-TW.ts +19 -0
- package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +28 -0
- package/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
- package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
- package/corpus/templates/analytics/server/handlers/github.ts +0 -200
- package/corpus/templates/analytics/server/handlers/pylon.ts +0 -43
- package/corpus/templates/analytics/server/lib/apollo.ts +0 -167
- package/corpus/templates/analytics/server/lib/commonroom.ts +0 -149
- package/corpus/templates/analytics/server/lib/github.ts +0 -660
- package/corpus/templates/analytics/server/lib/mixpanel.ts +0 -156
- package/corpus/templates/analytics/server/lib/posthog.ts +0 -194
- package/corpus/templates/analytics/server/lib/pylon.ts +0 -109
- package/corpus/templates/analytics/server/routes/api/github/graphql.post.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/github/issue.get.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/github/org-prs.get.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/github/pr.get.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/github/prs.get.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/github/search.get.ts +0 -1
- package/corpus/templates/slides/actions/fetch-logos.ts +0 -90
- package/corpus/templates/slides/actions/image-search.ts +0 -64
- package/corpus/templates/slides/actions/import-github.ts +0 -182
- package/corpus/templates/slides/actions/logo-lookup.ts +0 -113
|
@@ -484,12 +484,25 @@ const messages = {
|
|
|
484
484
|
chartTypePie: "餡餅",
|
|
485
485
|
chartTypeMetric: "公制",
|
|
486
486
|
chartTypeTable: "桌子",
|
|
487
|
+
chartTypeExtension: "擴充功能",
|
|
487
488
|
failedToSavePanel: "儲存面板失敗",
|
|
488
489
|
failedToFormatSql: "格式化 SQL 失敗",
|
|
489
490
|
title: "標題",
|
|
490
491
|
titlePlaceholder: "例如每週註冊人數",
|
|
491
492
|
chartType: "圖表型別",
|
|
492
493
|
source: "來源",
|
|
494
|
+
extensionDisplay: "擴充功能顯示方式",
|
|
495
|
+
sharedExtension: "共用擴充功能",
|
|
496
|
+
perViewerSlot: "每位檢視者的插槽",
|
|
497
|
+
extension: "擴充功能",
|
|
498
|
+
loadingExtensions: "正在載入擴充功能...",
|
|
499
|
+
selectExtension: "選取擴充功能",
|
|
500
|
+
noExtensions: "沒有可見的擴充功能。請先建立或共用一個。",
|
|
501
|
+
sharedExtensionHelp:
|
|
502
|
+
"選取的擴充功能會與此儀表板共用,並顯示在排程報告中。檢視者仍需具備該擴充功能的存取權。",
|
|
503
|
+
slotIdOptional: "插槽 ID(選填)",
|
|
504
|
+
perViewerSlotHelp:
|
|
505
|
+
"每位檢視者各自安裝擴充功能。排程報告可能會顯示空插槽。留空即可產生穩定的 ID。",
|
|
493
506
|
sectionColumns: "剖面列",
|
|
494
507
|
format: "格式",
|
|
495
508
|
filterInterpolation: "使用 {{example}} 插值濾波器值。",
|
|
@@ -908,12 +908,25 @@ const enUS = {
|
|
|
908
908
|
chartTypePie: "Pie",
|
|
909
909
|
chartTypeMetric: "Metric",
|
|
910
910
|
chartTypeTable: "Table",
|
|
911
|
+
chartTypeExtension: "Extension",
|
|
911
912
|
failedToSavePanel: "Failed to save panel",
|
|
912
913
|
failedToFormatSql: "Failed to format SQL",
|
|
913
914
|
title: "Title",
|
|
914
915
|
titlePlaceholder: "e.g. Weekly signups",
|
|
915
916
|
chartType: "Chart type",
|
|
916
917
|
source: "Source",
|
|
918
|
+
extensionDisplay: "Extension display",
|
|
919
|
+
sharedExtension: "Shared extension",
|
|
920
|
+
perViewerSlot: "Per-viewer slot",
|
|
921
|
+
extension: "Extension",
|
|
922
|
+
loadingExtensions: "Loading extensions...",
|
|
923
|
+
selectExtension: "Select an extension",
|
|
924
|
+
noExtensions: "No visible extensions. Create or share one first.",
|
|
925
|
+
sharedExtensionHelp:
|
|
926
|
+
"The selected extension is shared with this dashboard and appears in scheduled reports. Viewers still need access to the extension.",
|
|
927
|
+
slotIdOptional: "Slot ID (optional)",
|
|
928
|
+
perViewerSlotHelp:
|
|
929
|
+
"Each viewer installs their own extension. Scheduled reports may show an empty slot. Leave blank to generate a stable ID.",
|
|
917
930
|
sectionColumns: "Section columns",
|
|
918
931
|
format: "Format",
|
|
919
932
|
filterInterpolation: "Use {{example}} to interpolate filter values.",
|
|
@@ -1352,12 +1365,25 @@ const analyticsSliceTranslations: {
|
|
|
1352
1365
|
chartTypePie: "馅饼",
|
|
1353
1366
|
chartTypeMetric: "公制",
|
|
1354
1367
|
chartTypeTable: "桌子",
|
|
1368
|
+
chartTypeExtension: "扩展",
|
|
1355
1369
|
failedToSavePanel: "保存面板失败",
|
|
1356
1370
|
failedToFormatSql: "格式化SQL失败",
|
|
1357
1371
|
title: "标题",
|
|
1358
1372
|
titlePlaceholder: "例如每周注册人数",
|
|
1359
1373
|
chartType: "图表类型",
|
|
1360
1374
|
source: "来源",
|
|
1375
|
+
extensionDisplay: "扩展显示方式",
|
|
1376
|
+
sharedExtension: "共享扩展",
|
|
1377
|
+
perViewerSlot: "每位查看者的插槽",
|
|
1378
|
+
extension: "扩展",
|
|
1379
|
+
loadingExtensions: "正在加载扩展...",
|
|
1380
|
+
selectExtension: "选择扩展",
|
|
1381
|
+
noExtensions: "没有可见的扩展。请先创建或共享一个。",
|
|
1382
|
+
sharedExtensionHelp:
|
|
1383
|
+
"所选扩展会与此仪表板共享并显示在计划报告中。查看者仍需拥有该扩展的访问权限。",
|
|
1384
|
+
slotIdOptional: "插槽 ID(可选)",
|
|
1385
|
+
perViewerSlotHelp:
|
|
1386
|
+
"每位查看者各自安装扩展。计划报告可能显示空插槽。留空即可生成稳定 ID。",
|
|
1361
1387
|
sectionColumns: "剖面列",
|
|
1362
1388
|
format: "格式",
|
|
1363
1389
|
filterInterpolation: "使用 {{example}} 插值滤波器值。",
|
|
@@ -1627,12 +1653,25 @@ const analyticsSliceTranslations: {
|
|
|
1627
1653
|
chartTypePie: "Pastel",
|
|
1628
1654
|
chartTypeMetric: "Métrico",
|
|
1629
1655
|
chartTypeTable: "Mesa",
|
|
1656
|
+
chartTypeExtension: "Extensión",
|
|
1630
1657
|
failedToSavePanel: "No se pudo guardar el panel",
|
|
1631
1658
|
failedToFormatSql: "No se pudo formatear SQL",
|
|
1632
1659
|
title: "Título",
|
|
1633
1660
|
titlePlaceholder: "p.ej. Inscripciones semanales",
|
|
1634
1661
|
chartType: "Tipo de gráfico",
|
|
1635
1662
|
source: "Fuente",
|
|
1663
|
+
extensionDisplay: "Visualización de extensión",
|
|
1664
|
+
sharedExtension: "Extensión compartida",
|
|
1665
|
+
perViewerSlot: "Espacio por usuario",
|
|
1666
|
+
extension: "Extensión",
|
|
1667
|
+
loadingExtensions: "Cargando extensiones...",
|
|
1668
|
+
selectExtension: "Selecciona una extensión",
|
|
1669
|
+
noExtensions: "No hay extensiones visibles. Crea o comparte una primero.",
|
|
1670
|
+
sharedExtensionHelp:
|
|
1671
|
+
"La extensión seleccionada se comparte con este panel y aparece en los informes programados. Los usuarios aún necesitan acceso a ella.",
|
|
1672
|
+
slotIdOptional: "ID del espacio (opcional)",
|
|
1673
|
+
perViewerSlotHelp:
|
|
1674
|
+
"Cada usuario instala su propia extensión. Los informes programados pueden mostrar un espacio vacío. Déjalo en blanco para generar un ID estable.",
|
|
1636
1675
|
sectionColumns: "Columnas de sección",
|
|
1637
1676
|
format: "Formato",
|
|
1638
1677
|
filterInterpolation:
|
|
@@ -1918,12 +1957,25 @@ const analyticsSliceTranslations: {
|
|
|
1918
1957
|
chartTypePie: "Tarte",
|
|
1919
1958
|
chartTypeMetric: "Métrique",
|
|
1920
1959
|
chartTypeTable: "Tableau",
|
|
1960
|
+
chartTypeExtension: "Extension",
|
|
1921
1961
|
failedToSavePanel: "Échec de l'enregistrement du panneau",
|
|
1922
1962
|
failedToFormatSql: "Échec du formatage du SQL",
|
|
1923
1963
|
title: "Titre",
|
|
1924
1964
|
titlePlaceholder: "par ex. Inscriptions hebdomadaires",
|
|
1925
1965
|
chartType: "Type de graphique",
|
|
1926
1966
|
source: "Source de données",
|
|
1967
|
+
extensionDisplay: "Affichage de l'extension",
|
|
1968
|
+
sharedExtension: "Extension partagée",
|
|
1969
|
+
perViewerSlot: "Emplacement par utilisateur",
|
|
1970
|
+
extension: "Extension",
|
|
1971
|
+
loadingExtensions: "Chargement des extensions...",
|
|
1972
|
+
selectExtension: "Sélectionner une extension",
|
|
1973
|
+
noExtensions: "Aucune extension visible. Créez-en ou partagez-en une.",
|
|
1974
|
+
sharedExtensionHelp:
|
|
1975
|
+
"L'extension sélectionnée est partagée avec ce tableau de bord et apparaît dans les rapports planifiés. Les utilisateurs doivent toujours y avoir accès.",
|
|
1976
|
+
slotIdOptional: "ID de l'emplacement (facultatif)",
|
|
1977
|
+
perViewerSlotHelp:
|
|
1978
|
+
"Chaque utilisateur installe sa propre extension. Les rapports planifiés peuvent afficher un emplacement vide. Laissez ce champ vide pour générer un ID stable.",
|
|
1927
1979
|
sectionColumns: "Colonnes de section",
|
|
1928
1980
|
format: "Mettre en forme",
|
|
1929
1981
|
filterInterpolation:
|
|
@@ -2207,12 +2259,26 @@ const analyticsSliceTranslations: {
|
|
|
2207
2259
|
chartTypePie: "Torte",
|
|
2208
2260
|
chartTypeMetric: "Metrisch",
|
|
2209
2261
|
chartTypeTable: "Tisch",
|
|
2262
|
+
chartTypeExtension: "Erweiterung",
|
|
2210
2263
|
failedToSavePanel: "Das Panel konnte nicht gespeichert werden",
|
|
2211
2264
|
failedToFormatSql: "SQL konnte nicht formatiert werden",
|
|
2212
2265
|
title: "Titel",
|
|
2213
2266
|
titlePlaceholder: "z.B. Wöchentliche Anmeldungen",
|
|
2214
2267
|
chartType: "Diagrammtyp",
|
|
2215
2268
|
source: "Datenquelle",
|
|
2269
|
+
extensionDisplay: "Erweiterungsanzeige",
|
|
2270
|
+
sharedExtension: "Geteilte Erweiterung",
|
|
2271
|
+
perViewerSlot: "Slot pro Betrachter",
|
|
2272
|
+
extension: "Erweiterung",
|
|
2273
|
+
loadingExtensions: "Erweiterungen werden geladen...",
|
|
2274
|
+
selectExtension: "Erweiterung auswählen",
|
|
2275
|
+
noExtensions:
|
|
2276
|
+
"Keine sichtbaren Erweiterungen. Erstellen oder teilen Sie zuerst eine.",
|
|
2277
|
+
sharedExtensionHelp:
|
|
2278
|
+
"Die ausgewählte Erweiterung wird mit diesem Dashboard geteilt und erscheint in geplanten Berichten. Betrachter benötigen weiterhin Zugriff darauf.",
|
|
2279
|
+
slotIdOptional: "Slot-ID (optional)",
|
|
2280
|
+
perViewerSlotHelp:
|
|
2281
|
+
"Jeder Betrachter installiert eine eigene Erweiterung. Geplante Berichte können einen leeren Slot zeigen. Leer lassen, um eine stabile ID zu erzeugen.",
|
|
2216
2282
|
sectionColumns: "Abschnittsspalten",
|
|
2217
2283
|
format: "Formatieren",
|
|
2218
2284
|
filterInterpolation:
|
|
@@ -2492,12 +2558,26 @@ const analyticsSliceTranslations: {
|
|
|
2492
2558
|
chartTypePie: "パイ",
|
|
2493
2559
|
chartTypeMetric: "メトリック",
|
|
2494
2560
|
chartTypeTable: "テーブル",
|
|
2561
|
+
chartTypeExtension: "拡張機能",
|
|
2495
2562
|
failedToSavePanel: "パネルの保存に失敗しました",
|
|
2496
2563
|
failedToFormatSql: "SQLのフォーマットに失敗しました",
|
|
2497
2564
|
title: "タイトル",
|
|
2498
2565
|
titlePlaceholder: "例えば毎週のサインアップ",
|
|
2499
2566
|
chartType: "グラフの種類",
|
|
2500
2567
|
source: "ソース",
|
|
2568
|
+
extensionDisplay: "拡張機能の表示",
|
|
2569
|
+
sharedExtension: "共有拡張機能",
|
|
2570
|
+
perViewerSlot: "閲覧者ごとのスロット",
|
|
2571
|
+
extension: "拡張機能",
|
|
2572
|
+
loadingExtensions: "拡張機能を読み込んでいます...",
|
|
2573
|
+
selectExtension: "拡張機能を選択",
|
|
2574
|
+
noExtensions:
|
|
2575
|
+
"表示できる拡張機能がありません。先に作成または共有してください。",
|
|
2576
|
+
sharedExtensionHelp:
|
|
2577
|
+
"選択した拡張機能はこのダッシュボードと共有され、スケジュール済みレポートにも表示されます。閲覧者には拡張機能へのアクセス権が必要です。",
|
|
2578
|
+
slotIdOptional: "スロット ID(任意)",
|
|
2579
|
+
perViewerSlotHelp:
|
|
2580
|
+
"各閲覧者が自分の拡張機能をインストールします。スケジュール済みレポートでは空のスロットが表示される場合があります。空欄にすると安定した ID が生成されます。",
|
|
2501
2581
|
sectionColumns: "セクション列",
|
|
2502
2582
|
format: "形式",
|
|
2503
2583
|
filterInterpolation:
|
|
@@ -2771,12 +2851,26 @@ const analyticsSliceTranslations: {
|
|
|
2771
2851
|
chartTypePie: "파이",
|
|
2772
2852
|
chartTypeMetric: "미터법",
|
|
2773
2853
|
chartTypeTable: "테이블",
|
|
2854
|
+
chartTypeExtension: "확장 프로그램",
|
|
2774
2855
|
failedToSavePanel: "패널을 저장하지 못했습니다.",
|
|
2775
2856
|
failedToFormatSql: "SQL 포맷 실패",
|
|
2776
2857
|
title: "제목",
|
|
2777
2858
|
titlePlaceholder: "예를 들어 주간 가입",
|
|
2778
2859
|
chartType: "차트 종류",
|
|
2779
2860
|
source: "소스",
|
|
2861
|
+
extensionDisplay: "확장 프로그램 표시",
|
|
2862
|
+
sharedExtension: "공유 확장 프로그램",
|
|
2863
|
+
perViewerSlot: "사용자별 슬롯",
|
|
2864
|
+
extension: "확장 프로그램",
|
|
2865
|
+
loadingExtensions: "확장 프로그램을 불러오는 중...",
|
|
2866
|
+
selectExtension: "확장 프로그램 선택",
|
|
2867
|
+
noExtensions:
|
|
2868
|
+
"표시할 확장 프로그램이 없습니다. 먼저 만들거나 공유하세요.",
|
|
2869
|
+
sharedExtensionHelp:
|
|
2870
|
+
"선택한 확장 프로그램은 이 대시보드와 공유되며 예약 보고서에 표시됩니다. 사용자는 해당 확장 프로그램에 대한 액세스 권한이 필요합니다.",
|
|
2871
|
+
slotIdOptional: "슬롯 ID(선택 사항)",
|
|
2872
|
+
perViewerSlotHelp:
|
|
2873
|
+
"각 사용자가 자신의 확장 프로그램을 설치합니다. 예약 보고서에는 빈 슬롯이 표시될 수 있습니다. 비워 두면 안정적인 ID가 생성됩니다.",
|
|
2780
2874
|
sectionColumns: "섹션 열",
|
|
2781
2875
|
format: "체재",
|
|
2782
2876
|
filterInterpolation: "{{example}}를 사용하여 필터 값을 보간합니다.",
|
|
@@ -3049,12 +3143,26 @@ const analyticsSliceTranslations: {
|
|
|
3049
3143
|
chartTypePie: "Torta",
|
|
3050
3144
|
chartTypeMetric: "Métrica",
|
|
3051
3145
|
chartTypeTable: "Mesa",
|
|
3146
|
+
chartTypeExtension: "Extensão",
|
|
3052
3147
|
failedToSavePanel: "Falha ao salvar painel",
|
|
3053
3148
|
failedToFormatSql: "Falha ao formatar SQL",
|
|
3054
3149
|
title: "Título",
|
|
3055
3150
|
titlePlaceholder: "por exemplo Inscrições semanais",
|
|
3056
3151
|
chartType: "Tipo de gráfico",
|
|
3057
3152
|
source: "Fonte",
|
|
3153
|
+
extensionDisplay: "Exibição da extensão",
|
|
3154
|
+
sharedExtension: "Extensão compartilhada",
|
|
3155
|
+
perViewerSlot: "Slot por usuário",
|
|
3156
|
+
extension: "Extensão",
|
|
3157
|
+
loadingExtensions: "Carregando extensões...",
|
|
3158
|
+
selectExtension: "Selecione uma extensão",
|
|
3159
|
+
noExtensions:
|
|
3160
|
+
"Nenhuma extensão visível. Crie ou compartilhe uma primeiro.",
|
|
3161
|
+
sharedExtensionHelp:
|
|
3162
|
+
"A extensão selecionada é compartilhada com este painel e aparece nos relatórios agendados. Os usuários ainda precisam de acesso à extensão.",
|
|
3163
|
+
slotIdOptional: "ID do slot (opcional)",
|
|
3164
|
+
perViewerSlotHelp:
|
|
3165
|
+
"Cada usuário instala sua própria extensão. Relatórios agendados podem mostrar um slot vazio. Deixe em branco para gerar um ID estável.",
|
|
3058
3166
|
sectionColumns: "Colunas de seção",
|
|
3059
3167
|
format: "Formatar",
|
|
3060
3168
|
filterInterpolation: "Use {{example}} para interpolar valores de filtro.",
|
|
@@ -3330,12 +3438,25 @@ const analyticsSliceTranslations: {
|
|
|
3330
3438
|
chartTypePie: "पाई",
|
|
3331
3439
|
chartTypeMetric: "मीट्रिक",
|
|
3332
3440
|
chartTypeTable: "मेज़",
|
|
3441
|
+
chartTypeExtension: "एक्सटेंशन",
|
|
3333
3442
|
failedToSavePanel: "पैनल सहेजने में विफल",
|
|
3334
3443
|
failedToFormatSql: "SQL को फ़ॉर्मेट करने में विफल",
|
|
3335
3444
|
title: "शीर्षक",
|
|
3336
3445
|
titlePlaceholder: "जैसे साप्ताहिक साइनअप",
|
|
3337
3446
|
chartType: "चार्ट प्रकार",
|
|
3338
3447
|
source: "स्रोत",
|
|
3448
|
+
extensionDisplay: "एक्सटेंशन प्रदर्शन",
|
|
3449
|
+
sharedExtension: "साझा एक्सटेंशन",
|
|
3450
|
+
perViewerSlot: "प्रति-दर्शक स्लॉट",
|
|
3451
|
+
extension: "एक्सटेंशन",
|
|
3452
|
+
loadingExtensions: "एक्सटेंशन लोड हो रहे हैं...",
|
|
3453
|
+
selectExtension: "एक एक्सटेंशन चुनें",
|
|
3454
|
+
noExtensions: "कोई दृश्यमान एक्सटेंशन नहीं है। पहले एक बनाएं या साझा करें।",
|
|
3455
|
+
sharedExtensionHelp:
|
|
3456
|
+
"चुना गया एक्सटेंशन इस डैशबोर्ड के साथ साझा होता है और निर्धारित रिपोर्ट में दिखाई देता है। दर्शकों को फिर भी एक्सटेंशन की पहुंच चाहिए।",
|
|
3457
|
+
slotIdOptional: "स्लॉट ID (वैकल्पिक)",
|
|
3458
|
+
perViewerSlotHelp:
|
|
3459
|
+
"हर दर्शक अपना एक्सटेंशन इंस्टॉल करता है। निर्धारित रिपोर्ट में खाली स्लॉट दिख सकता है। स्थिर ID बनाने के लिए खाली छोड़ें।",
|
|
3339
3460
|
sectionColumns: "अनुभाग स्तंभ",
|
|
3340
3461
|
format: "प्रारूप",
|
|
3341
3462
|
filterInterpolation:
|
|
@@ -3605,12 +3726,25 @@ const analyticsSliceTranslations: {
|
|
|
3605
3726
|
chartTypePie: "فطيرة",
|
|
3606
3727
|
chartTypeMetric: "متري",
|
|
3607
3728
|
chartTypeTable: "طاولة",
|
|
3729
|
+
chartTypeExtension: "إضافة",
|
|
3608
3730
|
failedToSavePanel: "فشل حفظ اللوحة",
|
|
3609
3731
|
failedToFormatSql: "فشل تهيئة SQL",
|
|
3610
3732
|
title: "عنوان",
|
|
3611
3733
|
titlePlaceholder: "على سبيل المثال الاشتراكات الأسبوعية",
|
|
3612
3734
|
chartType: "نوع الرسم البياني",
|
|
3613
3735
|
source: "المصدر",
|
|
3736
|
+
extensionDisplay: "عرض الإضافة",
|
|
3737
|
+
sharedExtension: "إضافة مشتركة",
|
|
3738
|
+
perViewerSlot: "فتحة لكل مشاهد",
|
|
3739
|
+
extension: "إضافة",
|
|
3740
|
+
loadingExtensions: "جارٍ تحميل الإضافات...",
|
|
3741
|
+
selectExtension: "اختر إضافة",
|
|
3742
|
+
noExtensions: "لا توجد إضافات ظاهرة. أنشئ إضافة أو شاركها أولاً.",
|
|
3743
|
+
sharedExtensionHelp:
|
|
3744
|
+
"تتم مشاركة الإضافة المحددة مع لوحة المعلومات هذه وتظهر في التقارير المجدولة. لا يزال المشاهدون بحاجة إلى صلاحية الوصول إليها.",
|
|
3745
|
+
slotIdOptional: "معرّف الفتحة (اختياري)",
|
|
3746
|
+
perViewerSlotHelp:
|
|
3747
|
+
"يثبّت كل مشاهد إضافته الخاصة. قد تعرض التقارير المجدولة فتحة فارغة. اتركه فارغاً لإنشاء معرّف ثابت.",
|
|
3614
3748
|
sectionColumns: "أعمدة القسم",
|
|
3615
3749
|
format: "شكل",
|
|
3616
3750
|
filterInterpolation: "استخدم {{example}} لاستكمال قيم التصفية.",
|
|
@@ -41,6 +41,7 @@ import { Textarea } from "@/components/ui/textarea";
|
|
|
41
41
|
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
|
42
42
|
import { canFormatPanelSql, formatPanelSql } from "@/lib/format-sql";
|
|
43
43
|
|
|
44
|
+
import { dashboardExtensionSlotId } from "./extension-slot";
|
|
44
45
|
import {
|
|
45
46
|
clampDashboardColumns,
|
|
46
47
|
clampPanelWidth,
|
|
@@ -58,6 +59,7 @@ const CHART_TYPES: { value: ChartType; labelKey: string }[] = [
|
|
|
58
59
|
{ value: "pie", labelKey: "panelEditor.chartTypePie" },
|
|
59
60
|
{ value: "metric", labelKey: "panelEditor.chartTypeMetric" },
|
|
60
61
|
{ value: "table", labelKey: "panelEditor.chartTypeTable" },
|
|
62
|
+
{ value: "extension", labelKey: "panelEditor.chartTypeExtension" },
|
|
61
63
|
];
|
|
62
64
|
|
|
63
65
|
const SOURCES: { value: DataSourceType; label: string }[] = [
|
|
@@ -78,6 +80,22 @@ interface DataProgramSummary {
|
|
|
78
80
|
archivedAt: string | null;
|
|
79
81
|
}
|
|
80
82
|
|
|
83
|
+
export interface ExtensionSummary {
|
|
84
|
+
id: string;
|
|
85
|
+
name: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function extensionOptionsWithSelectedFallback(
|
|
89
|
+
extensions: ExtensionSummary[],
|
|
90
|
+
selectedId: string,
|
|
91
|
+
): ExtensionSummary[] {
|
|
92
|
+
const id = selectedId.trim();
|
|
93
|
+
if (!id || extensions.some((extension) => extension.id === id)) {
|
|
94
|
+
return extensions;
|
|
95
|
+
}
|
|
96
|
+
return [{ id, name: id }, ...extensions];
|
|
97
|
+
}
|
|
98
|
+
|
|
81
99
|
/** Parsed shape of a `program` panel's `sql` field: {programId, params?}. */
|
|
82
100
|
function parseProgramDescriptor(sql: string): {
|
|
83
101
|
programId: string;
|
|
@@ -136,9 +154,12 @@ export interface PanelFormValues {
|
|
|
136
154
|
columns: number;
|
|
137
155
|
sql: string;
|
|
138
156
|
description: string;
|
|
157
|
+
extensionMode: "shared" | "slot";
|
|
158
|
+
extensionId: string;
|
|
159
|
+
extensionSlotId: string;
|
|
139
160
|
}
|
|
140
161
|
|
|
141
|
-
function panelToForm(panel: SqlPanel | null): PanelFormValues {
|
|
162
|
+
export function panelToForm(panel: SqlPanel | null): PanelFormValues {
|
|
142
163
|
if (!panel) {
|
|
143
164
|
return {
|
|
144
165
|
title: "",
|
|
@@ -148,6 +169,9 @@ function panelToForm(panel: SqlPanel | null): PanelFormValues {
|
|
|
148
169
|
columns: DEFAULT_DASHBOARD_COLUMNS,
|
|
149
170
|
sql: "",
|
|
150
171
|
description: "",
|
|
172
|
+
extensionMode: "shared",
|
|
173
|
+
extensionId: "",
|
|
174
|
+
extensionSlotId: "",
|
|
151
175
|
};
|
|
152
176
|
}
|
|
153
177
|
return {
|
|
@@ -158,13 +182,17 @@ function panelToForm(panel: SqlPanel | null): PanelFormValues {
|
|
|
158
182
|
columns: clampDashboardColumns(panel.columns ?? DEFAULT_DASHBOARD_COLUMNS),
|
|
159
183
|
sql: panel.sql,
|
|
160
184
|
description: panel.config?.description ?? "",
|
|
185
|
+
extensionMode: panel.config?.extensionSlotId ? "slot" : "shared",
|
|
186
|
+
extensionId: panel.config?.extensionId ?? "",
|
|
187
|
+
extensionSlotId: panel.config?.extensionSlotId ?? "",
|
|
161
188
|
};
|
|
162
189
|
}
|
|
163
190
|
|
|
164
|
-
function formToPanel(
|
|
191
|
+
export function formToPanel(
|
|
165
192
|
form: PanelFormValues,
|
|
166
193
|
existing: SqlPanel | null,
|
|
167
194
|
untitledPanel: string,
|
|
195
|
+
dashboardId: string,
|
|
168
196
|
): SqlPanel {
|
|
169
197
|
const id = existing?.id ?? generatePanelId(form.title);
|
|
170
198
|
const description = form.description.trim();
|
|
@@ -175,11 +203,23 @@ function formToPanel(
|
|
|
175
203
|
} else {
|
|
176
204
|
delete config.description;
|
|
177
205
|
}
|
|
206
|
+
const isExtension = form.chartType === "extension";
|
|
207
|
+
if (isExtension && form.extensionMode === "slot") {
|
|
208
|
+
delete config.extensionId;
|
|
209
|
+
config.extensionSlotId =
|
|
210
|
+
form.extensionSlotId.trim() || dashboardExtensionSlotId(dashboardId, id);
|
|
211
|
+
} else if (isExtension) {
|
|
212
|
+
config.extensionId = form.extensionId.trim();
|
|
213
|
+
delete config.extensionSlotId;
|
|
214
|
+
} else {
|
|
215
|
+
delete config.extensionId;
|
|
216
|
+
delete config.extensionSlotId;
|
|
217
|
+
}
|
|
178
218
|
const isSection = form.chartType === "section";
|
|
179
219
|
return {
|
|
180
220
|
id,
|
|
181
221
|
title: form.title.trim() || untitledPanel,
|
|
182
|
-
sql: form.sql,
|
|
222
|
+
sql: isExtension ? "" : form.sql,
|
|
183
223
|
source: form.source,
|
|
184
224
|
chartType: form.chartType,
|
|
185
225
|
width: clampPanelWidth(form.width, MAX_DASHBOARD_COLUMNS),
|
|
@@ -249,6 +289,7 @@ function PanelEditorContent({
|
|
|
249
289
|
}, [open, panel]);
|
|
250
290
|
|
|
251
291
|
const isEdit = !!panel;
|
|
292
|
+
const isExtensionPanel = form.chartType === "extension";
|
|
252
293
|
const isProgramSource = form.source === "program";
|
|
253
294
|
const { programId, paramsText: initialParamsText } = useMemo(
|
|
254
295
|
() =>
|
|
@@ -276,11 +317,25 @@ function PanelEditorContent({
|
|
|
276
317
|
const availablePrograms = (programsData?.programs ?? []).filter(
|
|
277
318
|
(p) => !p.archivedAt,
|
|
278
319
|
);
|
|
320
|
+
const { data: extensionsData, isLoading: extensionsLoading } =
|
|
321
|
+
useActionQuery<{
|
|
322
|
+
ok: boolean;
|
|
323
|
+
count: number;
|
|
324
|
+
extensions: ExtensionSummary[];
|
|
325
|
+
}>("list-extensions", { limit: 100 }, { enabled: isExtensionPanel });
|
|
326
|
+
const availableExtensions = extensionsData?.extensions ?? [];
|
|
327
|
+
const extensionOptions = extensionOptionsWithSelectedFallback(
|
|
328
|
+
availableExtensions,
|
|
329
|
+
form.extensionId,
|
|
330
|
+
);
|
|
279
331
|
|
|
280
|
-
const canSave =
|
|
281
|
-
? form.title.trim().length > 0 &&
|
|
282
|
-
|
|
283
|
-
|
|
332
|
+
const canSave = isExtensionPanel
|
|
333
|
+
? form.title.trim().length > 0 &&
|
|
334
|
+
(form.extensionMode === "slot" || form.extensionId.trim().length > 0)
|
|
335
|
+
: isProgramSource
|
|
336
|
+
? form.title.trim().length > 0 && selectedProgramId.trim().length > 0
|
|
337
|
+
: form.title.trim().length > 0 && form.sql.trim().length > 0;
|
|
338
|
+
const canFormat = !isExtensionPanel && canFormatPanelSql(form.source);
|
|
284
339
|
|
|
285
340
|
const handleSubmit = async () => {
|
|
286
341
|
if (!canSave || saving) return;
|
|
@@ -305,6 +360,7 @@ function PanelEditorContent({
|
|
|
305
360
|
{ ...form, sql: sqlForSave },
|
|
306
361
|
panel,
|
|
307
362
|
t("panelEditor.untitledPanel"),
|
|
363
|
+
dashboardId,
|
|
308
364
|
),
|
|
309
365
|
);
|
|
310
366
|
onOpenChange(false);
|
|
@@ -327,18 +383,19 @@ function PanelEditorContent({
|
|
|
327
383
|
message: trimmed,
|
|
328
384
|
context:
|
|
329
385
|
`The user wants to add a new panel to SQL dashboard "${dashboardId}". ${titlesLine} ` +
|
|
330
|
-
`REAL_DATA_REQUIRED: before saving or answering, run at least one real data-source query action for this panel; \`data-source-status\`, \`list-data-dictionary\`, \`update-dashboard\`, \`mutate-dashboard\`, and dry-run validation do not count as data queries. ` +
|
|
386
|
+
`REAL_DATA_REQUIRED: before saving or answering with a data panel, run at least one real data-source query action for this panel; \`data-source-status\`, \`list-data-dictionary\`, \`update-dashboard\`, \`mutate-dashboard\`, and dry-run validation do not count as data queries. Embedding an existing extension without presenting new data does not require a data-source query. ` +
|
|
331
387
|
`The \`demo\` source is reserved for the built-in Node Exporter demo and does not satisfy REAL_DATA_REQUIRED unless the user explicitly asks to work on that demo dashboard. ` +
|
|
332
388
|
`If no source can answer, report the exact unavailable/error result instead of saving a panel with guessed schema or metrics. ` +
|
|
333
389
|
`Use the \`mutate-dashboard\` action with code like \`dashboard.insertPanel({"id":"new-panel","title":"New Panel","source":"first-party","chartType":"metric","width":1,"sql":"SELECT COUNT(*) AS value FROM analytics_events"}).atBottom();\` ` +
|
|
334
390
|
`to append, or \`.nextTo("panel-id")\`, \`.atRow(2)\`, \`.atRowStart(2)\`, \`.before("panel-id")\`, \`.after("panel-id")\`, or \`.atIndex(n)\` to place the panel. Prefer \`.nextTo("panel-id")\` or \`.atRow(rowNumber)\` for visible row placement requests; they keep the chart in the intended rendered row and expand/rebalance that row when needed. ` +
|
|
335
|
-
`Panel shape: { id (unique slug), title, sql, source ('bigquery'|'ga4'|'amplitude'|'first-party'|'demo'|'prometheus'|'program'), chartType ('line'|'area'|'bar'|'metric'|'table'|'pie'|'section'), width (legacy integer 1..6; set to 1 unless editing existing data), tab? (use 'Group / Tab' for grouped tabs), columns? (section panels only - 1..6 max panels per row for panels following this section), config? }. ` +
|
|
391
|
+
`Panel shape: { id (unique slug), title, sql, source ('bigquery'|'ga4'|'amplitude'|'first-party'|'demo'|'prometheus'|'program'), chartType ('line'|'area'|'bar'|'metric'|'table'|'pie'|'section'|'extension'), width (legacy integer 1..6; set to 1 unless editing existing data), tab? (use 'Group / Tab' for grouped tabs), columns? (section panels only - 1..6 max panels per row for panels following this section), config? }. ` +
|
|
336
392
|
`Visible layout auto-fits by row: one panel in a row spans the row, two split it, three split it into thirds, up to the section column limit. ` +
|
|
337
393
|
`For amplitude panels, sql is a JSON descriptor: {"event":"event name","groupBy":"property","days":30}. ` +
|
|
338
394
|
`For first-party panels, sql is read-only SQL over analytics_events only; use source 'first-party' and do not call db-query for this datasource. ` +
|
|
339
395
|
`For demo panels, sql uses the same Prometheus JSON descriptor shape as source 'prometheus': {"promql":"rate(http_requests_total[5m])","mode":"range","range":"1h","step":"30s"}. ` +
|
|
340
396
|
`For prometheus panels, sql is a JSON descriptor: {"promql":"rate(http_requests_total[5m])","mode":"range","range":"1h","step":"30s"}. mode defaults to "range"; range defaults to "1h"; step is auto if omitted. Returned rows have shape {timestamp, series, value} — set config.xKey="timestamp", config.yKey="value", and a single series in config.yKeys for clean charting. ` +
|
|
341
397
|
`For program panels (arbitrary provider data joins/cohorts not expressible in the other sources), first save-data-program (or reuse an existing one via list-data-programs), then set sql to a JSON descriptor: {"programId":"<id>","params":{...}}. See the data-programs skill for the emit(rows, schema) contract and the Risk Meeting worked example. ` +
|
|
398
|
+
`For extension panels, use config.extensionId by default so every dashboard viewer and scheduled report renders the author-selected shared extension. Use config.extensionSlotId only when the user explicitly asks for a personal/per-viewer slot; slot installs are per-user and automated report identities may have no install. ` +
|
|
342
399
|
`Config is optional: { xKey, yKey, yKeys, yFormatter ('number'|'currency'|'percent'), description, columns, pivot, limit, color, colors, stacked, legend, valueLabels }. ` +
|
|
343
400
|
`Chart legends render automatically; set config.legend=false only when the user explicitly asks to hide the legend. ` +
|
|
344
401
|
`Use \`get-sql-dashboard.layout.groups[].rows[].rowNumber/panelIds\` to identify and verify visible rows. ` +
|
|
@@ -397,26 +454,28 @@ function PanelEditorContent({
|
|
|
397
454
|
</Select>
|
|
398
455
|
</div>
|
|
399
456
|
|
|
400
|
-
|
|
401
|
-
<
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
<
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
{s.
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
457
|
+
{!isExtensionPanel ? (
|
|
458
|
+
<div className="grid gap-1.5">
|
|
459
|
+
<Label htmlFor="panel-source">{t("panelEditor.source")}</Label>
|
|
460
|
+
<Select
|
|
461
|
+
value={form.source}
|
|
462
|
+
onValueChange={(v: DataSourceType) =>
|
|
463
|
+
setForm((f) => ({ ...f, source: v }))
|
|
464
|
+
}
|
|
465
|
+
>
|
|
466
|
+
<SelectTrigger id="panel-source" className="h-9 text-sm">
|
|
467
|
+
<SelectValue />
|
|
468
|
+
</SelectTrigger>
|
|
469
|
+
<SelectContent>
|
|
470
|
+
{SOURCES.map((s) => (
|
|
471
|
+
<SelectItem key={s.value} value={s.value}>
|
|
472
|
+
{s.label}
|
|
473
|
+
</SelectItem>
|
|
474
|
+
))}
|
|
475
|
+
</SelectContent>
|
|
476
|
+
</Select>
|
|
477
|
+
</div>
|
|
478
|
+
) : null}
|
|
420
479
|
|
|
421
480
|
{form.chartType === "section" ? (
|
|
422
481
|
<div className="grid gap-1.5">
|
|
@@ -448,7 +507,99 @@ function PanelEditorContent({
|
|
|
448
507
|
) : null}
|
|
449
508
|
</div>
|
|
450
509
|
|
|
451
|
-
{
|
|
510
|
+
{isExtensionPanel ? (
|
|
511
|
+
<div className="grid gap-4 rounded-lg border p-4">
|
|
512
|
+
<div className="grid gap-1.5">
|
|
513
|
+
<Label htmlFor="panel-extension-mode">
|
|
514
|
+
{t("panelEditor.extensionDisplay")}
|
|
515
|
+
</Label>
|
|
516
|
+
<Select
|
|
517
|
+
value={form.extensionMode}
|
|
518
|
+
onValueChange={(value: "shared" | "slot") =>
|
|
519
|
+
setForm((current) => ({
|
|
520
|
+
...current,
|
|
521
|
+
extensionMode: value,
|
|
522
|
+
}))
|
|
523
|
+
}
|
|
524
|
+
>
|
|
525
|
+
<SelectTrigger id="panel-extension-mode" className="h-9 text-sm">
|
|
526
|
+
<SelectValue />
|
|
527
|
+
</SelectTrigger>
|
|
528
|
+
<SelectContent>
|
|
529
|
+
<SelectItem value="shared">
|
|
530
|
+
{t("panelEditor.sharedExtension")}
|
|
531
|
+
</SelectItem>
|
|
532
|
+
<SelectItem value="slot">
|
|
533
|
+
{t("panelEditor.perViewerSlot")}
|
|
534
|
+
</SelectItem>
|
|
535
|
+
</SelectContent>
|
|
536
|
+
</Select>
|
|
537
|
+
</div>
|
|
538
|
+
|
|
539
|
+
{form.extensionMode === "shared" ? (
|
|
540
|
+
<div className="grid gap-1.5">
|
|
541
|
+
<Label htmlFor="panel-extension">
|
|
542
|
+
{t("panelEditor.extension")}
|
|
543
|
+
</Label>
|
|
544
|
+
<Select
|
|
545
|
+
value={form.extensionId || undefined}
|
|
546
|
+
onValueChange={(extensionId) =>
|
|
547
|
+
setForm((current) => ({ ...current, extensionId }))
|
|
548
|
+
}
|
|
549
|
+
>
|
|
550
|
+
<SelectTrigger id="panel-extension" className="h-9 text-sm">
|
|
551
|
+
<SelectValue
|
|
552
|
+
placeholder={
|
|
553
|
+
extensionsLoading
|
|
554
|
+
? t("panelEditor.loadingExtensions")
|
|
555
|
+
: t("panelEditor.selectExtension")
|
|
556
|
+
}
|
|
557
|
+
/>
|
|
558
|
+
</SelectTrigger>
|
|
559
|
+
<SelectContent>
|
|
560
|
+
{extensionOptions.map((extension) => (
|
|
561
|
+
<SelectItem key={extension.id} value={extension.id}>
|
|
562
|
+
{extension.name}
|
|
563
|
+
</SelectItem>
|
|
564
|
+
))}
|
|
565
|
+
</SelectContent>
|
|
566
|
+
</Select>
|
|
567
|
+
{!extensionsLoading && availableExtensions.length === 0 ? (
|
|
568
|
+
<p className="text-xs text-muted-foreground">
|
|
569
|
+
{t("panelEditor.noExtensions")}
|
|
570
|
+
</p>
|
|
571
|
+
) : null}
|
|
572
|
+
<p className="text-xs text-muted-foreground">
|
|
573
|
+
{t("panelEditor.sharedExtensionHelp")}
|
|
574
|
+
</p>
|
|
575
|
+
</div>
|
|
576
|
+
) : (
|
|
577
|
+
<div className="grid gap-1.5">
|
|
578
|
+
<Label htmlFor="panel-extension-slot">
|
|
579
|
+
{t("panelEditor.slotIdOptional")}
|
|
580
|
+
</Label>
|
|
581
|
+
<Input
|
|
582
|
+
id="panel-extension-slot"
|
|
583
|
+
value={form.extensionSlotId}
|
|
584
|
+
onChange={(event) =>
|
|
585
|
+
setForm((current) => ({
|
|
586
|
+
...current,
|
|
587
|
+
extensionSlotId: event.target.value,
|
|
588
|
+
}))
|
|
589
|
+
}
|
|
590
|
+
placeholder={dashboardExtensionSlotId(
|
|
591
|
+
dashboardId,
|
|
592
|
+
panel?.id ?? "generated-panel-id",
|
|
593
|
+
)}
|
|
594
|
+
className="font-mono text-xs"
|
|
595
|
+
/>
|
|
596
|
+
<p className="text-xs text-muted-foreground">
|
|
597
|
+
{t("panelEditor.perViewerSlotHelp")}
|
|
598
|
+
</p>
|
|
599
|
+
</div>
|
|
600
|
+
)}
|
|
601
|
+
</div>
|
|
602
|
+
) : isProgramSource ? (
|
|
452
603
|
<div className="grid gap-4">
|
|
453
604
|
<div className="grid gap-1.5">
|
|
454
605
|
<Label htmlFor="panel-program">
|
|
@@ -404,6 +404,12 @@ export function SqlChartCard({
|
|
|
404
404
|
{editable ? (
|
|
405
405
|
<>
|
|
406
406
|
<DropdownMenuSeparator />
|
|
407
|
+
{onEdit ? (
|
|
408
|
+
<DropdownMenuItem onSelect={() => onEdit()}>
|
|
409
|
+
<IconPencil className="h-4 w-4 mr-2" />
|
|
410
|
+
{t("sidebar.edit")}
|
|
411
|
+
</DropdownMenuItem>
|
|
412
|
+
) : null}
|
|
407
413
|
<DropdownMenuItem
|
|
408
414
|
onSelect={(e) => {
|
|
409
415
|
e.preventDefault();
|
|
@@ -99,12 +99,13 @@ export interface SqlPanelConfig {
|
|
|
99
99
|
/**
|
|
100
100
|
* Extension panels only (`chartType: "extension"`): id of the extension to
|
|
101
101
|
* render inline as a sandboxed iframe instead of running the SQL pipeline.
|
|
102
|
-
*
|
|
102
|
+
* This is the default for author-selected dashboard content because the
|
|
103
|
+
* selection is shared with the dashboard and available to report captures.
|
|
103
104
|
*/
|
|
104
105
|
extensionId?: string;
|
|
105
106
|
/**
|
|
106
|
-
* Extension panels only:
|
|
107
|
-
*
|
|
107
|
+
* Extension panels only: an opt-in named extension-point slot. Each viewer's
|
|
108
|
+
* personal installs render in the box and receive dashboard context.
|
|
108
109
|
*/
|
|
109
110
|
extensionSlotId?: string;
|
|
110
111
|
}
|