@agent-native/core 0.120.0 → 0.120.2

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.
Files changed (207) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +16 -0
  3. package/corpus/core/docs/content/extensions.mdx +23 -4
  4. package/corpus/core/package.json +1 -1
  5. package/corpus/core/src/agent/production-agent.ts +4 -0
  6. package/corpus/core/src/agent/run-manager.ts +36 -10
  7. package/corpus/core/src/agent/types.ts +2 -0
  8. package/corpus/core/src/client/MultiTabAssistantChat.tsx +45 -0
  9. package/corpus/core/src/client/extensions/ExtensionsListPage.tsx +16 -3
  10. package/corpus/core/src/client/settings/ExtensionsSettingsContent.tsx +24 -0
  11. package/corpus/core/src/client/settings/SettingsPanel.tsx +10 -0
  12. package/corpus/core/src/client/use-chat-models.ts +45 -0
  13. package/corpus/core/src/deploy/build.ts +3 -0
  14. package/corpus/core/src/server/analytics.ts +164 -20
  15. package/corpus/core/src/server/auth.ts +17 -13
  16. package/corpus/core/src/server/better-auth-instance.ts +13 -1
  17. package/corpus/core/src/templates/chat/app/components/layout/Sidebar.tsx +35 -6
  18. package/corpus/core/src/templates/chat/app/routes/extensions._index.tsx +2 -2
  19. package/corpus/core/src/templates/chat/netlify.toml +1 -0
  20. package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +16 -0
  21. package/corpus/core/src/vite/client.ts +6 -0
  22. package/corpus/templates/analytics/.agents/skills/adhoc-analysis/SKILL.md +27 -43
  23. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +19 -8
  24. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +2 -2
  25. package/corpus/templates/analytics/AGENTS.md +20 -8
  26. package/corpus/templates/analytics/actions/get-explorer-dashboard.ts +3 -0
  27. package/corpus/templates/analytics/actions/list-dashboard-usage-stats.ts +140 -46
  28. package/corpus/templates/analytics/actions/migrate-analytics-artifacts.ts +48 -0
  29. package/corpus/templates/analytics/actions/save-analysis.ts +2 -3
  30. package/corpus/templates/analytics/actions/view-screen.ts +1 -1
  31. package/corpus/templates/analytics/app/components/dashboard/DashboardMetadata.tsx +77 -0
  32. package/corpus/templates/analytics/app/components/dashboard/DashboardPanelSkeleton.tsx +7 -1
  33. package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +1 -0
  34. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +103 -502
  35. package/corpus/templates/analytics/app/global.css +30 -0
  36. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +2 -2
  37. package/corpus/templates/analytics/app/i18n-data.ts +80 -0
  38. package/corpus/templates/analytics/app/pages/Agents.tsx +49 -2
  39. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +54 -11
  40. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +3 -53
  41. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +23 -25
  42. package/corpus/templates/analytics/app/pages/analyses/AnalysisDetail.tsx +2 -2
  43. package/corpus/templates/analytics/app/routes/analyses._index.tsx +3 -2
  44. package/corpus/templates/analytics/app/routes/extensions._index.tsx +2 -2
  45. package/corpus/templates/analytics/changelog/2026-07-23-analytics-now-groups-saved-analyses-and-embedded-extensions-.md +6 -0
  46. package/corpus/templates/analytics/changelog/2026-07-23-dashboard-menus-show-who-created-and-last-updated-each-dashb.md +6 -0
  47. package/corpus/templates/analytics/changelog/2026-07-23-dashboard-usage-now-loads-reliably-for-organizations-with-ma.md +6 -0
  48. package/corpus/templates/analytics/changelog/2026-07-23-long-dashboard-building-requests-now-continue-without-stoppi.md +6 -0
  49. package/corpus/templates/analytics/netlify.toml +4 -0
  50. package/corpus/templates/analytics/server/db/schema.ts +4 -0
  51. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +0 -1
  52. package/corpus/templates/analytics/server/lib/agent-readable-resource-context.ts +1 -0
  53. package/corpus/templates/analytics/server/lib/migrate-analytics-artifacts.ts +1062 -0
  54. package/corpus/templates/analytics/server/plugins/agent-chat.ts +6 -52
  55. package/corpus/templates/analytics/server/plugins/core-routes.ts +1 -1
  56. package/corpus/templates/analytics/server/plugins/db.ts +10 -0
  57. package/corpus/templates/assets/actions/generate-image-batch.ts +36 -1
  58. package/corpus/templates/assets/actions/generate-image.ts +28 -1
  59. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +47 -9
  60. package/corpus/templates/assets/app/routes/extensions._index.tsx +2 -2
  61. package/corpus/templates/assets/changelog/2026-07-23-assets-image-generation-now-recovers-after-a-completed-tool-.md +6 -0
  62. package/corpus/templates/assets/changelog/2026-07-23-new-chat-aligns-with-sidebar-controls.md +6 -0
  63. package/corpus/templates/assets/netlify.toml +1 -0
  64. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +38 -8
  65. package/corpus/templates/brain/app/routes/extensions._index.tsx +2 -2
  66. package/corpus/templates/brain/netlify.toml +1 -0
  67. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +43 -5
  68. package/corpus/templates/calendar/app/routes/_app.extensions._index.tsx +2 -16
  69. package/corpus/templates/calendar/netlify.toml +1 -0
  70. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +35 -6
  71. package/corpus/templates/chat/app/routes/extensions._index.tsx +2 -2
  72. package/corpus/templates/chat/netlify.toml +1 -0
  73. package/corpus/templates/clips/app/components/library/library-layout.tsx +52 -6
  74. package/corpus/templates/clips/app/routes/_app.extensions._index.tsx +2 -16
  75. package/corpus/templates/clips/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
  76. package/corpus/templates/clips/changelog/2026-07-23-meeting-recording-meters-and-dismissed-prompts.md +6 -0
  77. package/corpus/templates/clips/desktop/src/hooks/useMicMeter.ts +1 -1
  78. package/corpus/templates/clips/desktop/src/lib/meeting-notification-dismissal.ts +2 -0
  79. package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +1 -3
  80. package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +86 -0
  81. package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +24 -0
  82. package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +5 -69
  83. package/corpus/templates/clips/desktop/src/styles.css +35 -3
  84. package/corpus/templates/clips/desktop/src-tauri/src/adhoc_meetings_watcher.rs +13 -44
  85. package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +119 -17
  86. package/corpus/templates/clips/netlify.toml +1 -0
  87. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +3 -7
  88. package/corpus/templates/content/app/routes/_app.extensions._index.tsx +2 -2
  89. package/corpus/templates/content/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
  90. package/corpus/templates/content/netlify.toml +1 -0
  91. package/corpus/templates/design/app/components/layout/Sidebar.tsx +55 -17
  92. package/corpus/templates/design/app/routes/extensions._index.tsx +2 -2
  93. package/corpus/templates/design/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
  94. package/corpus/templates/design/netlify.toml +1 -0
  95. package/corpus/templates/dispatch/app/dispatch-extensions.tsx +1 -1
  96. package/corpus/templates/dispatch/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
  97. package/corpus/templates/dispatch/netlify.toml +1 -0
  98. package/corpus/templates/forms/.agents/skills/form-publishing/SKILL.md +9 -3
  99. package/corpus/templates/forms/AGENTS.md +11 -1
  100. package/corpus/templates/forms/README.md +24 -1
  101. package/corpus/templates/forms/actions/update-form.ts +12 -5
  102. package/corpus/templates/forms/app/components/builder/FieldPropertiesPanel.tsx +199 -1
  103. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +41 -45
  104. package/corpus/templates/forms/app/i18n/en-US.ts +13 -1
  105. package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +35 -4
  106. package/corpus/templates/forms/app/pages/FormFillPage.tsx +7 -16
  107. package/corpus/templates/forms/app/routes/_app.extensions._index.tsx +2 -2
  108. package/corpus/templates/forms/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
  109. package/corpus/templates/forms/changelog/2026-07-23-forms-can-branch-into-follow-up-questions-and-route-response.md +6 -0
  110. package/corpus/templates/forms/netlify.toml +1 -0
  111. package/corpus/templates/forms/server/handlers/submissions.ts +22 -31
  112. package/corpus/templates/forms/server/lib/integrations.ts +11 -2
  113. package/corpus/templates/forms/server/lib/public-form-ssr.ts +26 -5
  114. package/corpus/templates/forms/server/lib/validate-fields.ts +48 -11
  115. package/corpus/templates/forms/server/plugins/agent-chat.ts +1 -0
  116. package/corpus/templates/forms/shared/conditional.ts +67 -0
  117. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +36 -5
  118. package/corpus/templates/macros/app/routes/extensions._index.tsx +2 -2
  119. package/corpus/templates/macros/netlify.toml +1 -0
  120. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +0 -9
  121. package/corpus/templates/mail/app/routes/extensions._index.tsx +2 -2
  122. package/corpus/templates/mail/netlify.toml +1 -0
  123. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +38 -5
  124. package/corpus/templates/plan/app/routes/extensions._index.tsx +2 -2
  125. package/corpus/templates/plan/netlify.toml +1 -0
  126. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +47 -4
  127. package/corpus/templates/slides/app/routes/extensions._index.tsx +2 -2
  128. package/corpus/templates/slides/netlify.toml +1 -0
  129. package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +37 -6
  130. package/corpus/templates/tasks/app/routes/extensions._index.tsx +2 -2
  131. package/corpus/templates/tasks/app/routes/settings.tsx +31 -0
  132. package/corpus/templates/tasks/netlify.toml +1 -0
  133. package/dist/agent/production-agent.d.ts.map +1 -1
  134. package/dist/agent/production-agent.js +4 -0
  135. package/dist/agent/production-agent.js.map +1 -1
  136. package/dist/agent/run-manager.d.ts +9 -0
  137. package/dist/agent/run-manager.d.ts.map +1 -1
  138. package/dist/agent/run-manager.js +25 -10
  139. package/dist/agent/run-manager.js.map +1 -1
  140. package/dist/agent/types.d.ts +2 -2
  141. package/dist/agent/types.d.ts.map +1 -1
  142. package/dist/agent/types.js.map +1 -1
  143. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  144. package/dist/client/MultiTabAssistantChat.js +35 -0
  145. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  146. package/dist/client/extensions/ExtensionsListPage.d.ts +5 -1
  147. package/dist/client/extensions/ExtensionsListPage.d.ts.map +1 -1
  148. package/dist/client/extensions/ExtensionsListPage.js +5 -3
  149. package/dist/client/extensions/ExtensionsListPage.js.map +1 -1
  150. package/dist/client/settings/ExtensionsSettingsContent.d.ts +2 -0
  151. package/dist/client/settings/ExtensionsSettingsContent.d.ts.map +1 -0
  152. package/dist/client/settings/ExtensionsSettingsContent.js +10 -0
  153. package/dist/client/settings/ExtensionsSettingsContent.js.map +1 -0
  154. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  155. package/dist/client/settings/SettingsPanel.js +10 -1
  156. package/dist/client/settings/SettingsPanel.js.map +1 -1
  157. package/dist/client/use-chat-models.d.ts +1 -0
  158. package/dist/client/use-chat-models.d.ts.map +1 -1
  159. package/dist/client/use-chat-models.js +33 -0
  160. package/dist/client/use-chat-models.js.map +1 -1
  161. package/dist/collab/awareness.d.ts +2 -2
  162. package/dist/collab/awareness.d.ts.map +1 -1
  163. package/dist/deploy/build.js +1 -0
  164. package/dist/deploy/build.js.map +1 -1
  165. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  166. package/dist/observability/routes.d.ts +3 -3
  167. package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
  168. package/dist/provider-api/actions/provider-api.d.ts +2 -2
  169. package/dist/server/analytics.d.ts +17 -4
  170. package/dist/server/analytics.d.ts.map +1 -1
  171. package/dist/server/analytics.js +122 -17
  172. package/dist/server/analytics.js.map +1 -1
  173. package/dist/server/auth.d.ts.map +1 -1
  174. package/dist/server/auth.js +5 -4
  175. package/dist/server/auth.js.map +1 -1
  176. package/dist/server/better-auth-instance.d.ts +8 -0
  177. package/dist/server/better-auth-instance.d.ts.map +1 -1
  178. package/dist/server/better-auth-instance.js +10 -1
  179. package/dist/server/better-auth-instance.js.map +1 -1
  180. package/dist/templates/chat/app/components/layout/Sidebar.tsx +35 -6
  181. package/dist/templates/chat/app/routes/extensions._index.tsx +2 -2
  182. package/dist/templates/chat/netlify.toml +1 -0
  183. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +16 -0
  184. package/dist/vite/client.d.ts.map +1 -1
  185. package/dist/vite/client.js +2 -0
  186. package/dist/vite/client.js.map +1 -1
  187. package/docs/content/extensions.mdx +23 -4
  188. package/package.json +1 -1
  189. package/src/agent/production-agent.ts +4 -0
  190. package/src/agent/run-manager.ts +36 -10
  191. package/src/agent/types.ts +2 -0
  192. package/src/client/MultiTabAssistantChat.tsx +45 -0
  193. package/src/client/extensions/ExtensionsListPage.tsx +16 -3
  194. package/src/client/settings/ExtensionsSettingsContent.tsx +24 -0
  195. package/src/client/settings/SettingsPanel.tsx +10 -0
  196. package/src/client/use-chat-models.ts +45 -0
  197. package/src/deploy/build.ts +3 -0
  198. package/src/server/analytics.ts +164 -20
  199. package/src/server/auth.ts +17 -13
  200. package/src/server/better-auth-instance.ts +13 -1
  201. package/src/templates/chat/app/components/layout/Sidebar.tsx +35 -6
  202. package/src/templates/chat/app/routes/extensions._index.tsx +2 -2
  203. package/src/templates/chat/netlify.toml +1 -0
  204. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +16 -0
  205. package/src/vite/client.ts +6 -0
  206. package/corpus/templates/analytics/app/components/layout/NewAnalysisDialog.tsx +0 -165
  207. package/corpus/templates/analytics/app/pages/analyses/AnalysesList.tsx +0 -175
@@ -138,6 +138,36 @@
138
138
  }
139
139
  }
140
140
 
141
+ .dashboard-panel-skeleton {
142
+ background-color: hsl(var(--muted-foreground) / 0.24);
143
+ background-image: linear-gradient(
144
+ 105deg,
145
+ transparent 24%,
146
+ hsl(var(--foreground) / 0.06) 42%,
147
+ hsl(var(--foreground) / 0.16) 50%,
148
+ hsl(var(--foreground) / 0.06) 58%,
149
+ transparent 76%
150
+ );
151
+ background-size: 220% 100%;
152
+ animation: dashboard-panel-skeleton-shimmer 1.8s linear infinite;
153
+ }
154
+
155
+ @keyframes dashboard-panel-skeleton-shimmer {
156
+ from {
157
+ background-position: 120% 0;
158
+ }
159
+
160
+ to {
161
+ background-position: -120% 0;
162
+ }
163
+ }
164
+
165
+ @media (prefers-reduced-motion: reduce) {
166
+ .dashboard-panel-skeleton {
167
+ animation: none;
168
+ }
169
+ }
170
+
141
171
  .analytics-mobile-nav {
142
172
  height: 2.75rem;
143
173
  min-height: 2.75rem;
@@ -111,10 +111,10 @@ export function useNavigationState() {
111
111
  return `/dashboards/${cmd.dashboardId}`;
112
112
  if (cmd.view === "analyses" && cmd.analysisId)
113
113
  return `/analyses/${cmd.analysisId}`;
114
- if (cmd.view === "analyses") return "/analyses";
114
+ if (cmd.view === "analyses") return "/dashboards";
115
115
  if (cmd.view === "extensions" && cmd.extensionId)
116
116
  return `/extensions/${cmd.extensionId}`;
117
- if (cmd.view === "extensions") return "/extensions";
117
+ if (cmd.view === "extensions") return "/settings#extensions";
118
118
  if (cmd.view === "sessions" && cmd.recordingId)
119
119
  return `/sessions/${encodeURIComponent(cmd.recordingId)}`;
120
120
  if (cmd.view === "sessions") return "/sessions";
@@ -410,6 +410,10 @@ const enUS = {
410
410
  dashboardUsageTotal: "Dashboards",
411
411
  dashboardUsageActive: "{{count}} active",
412
412
  dashboardUsageViews: "Views",
413
+ dashboardUsageEdits: "Edits",
414
+ dashboardUsageSort: "Sort dashboards",
415
+ dashboardUsageMostViewed: "Most viewed",
416
+ dashboardUsageMostEdited: "Most edited",
413
417
  dashboardUsageTop: "Top: {{name}}",
414
418
  dashboardUsageEngagements: "Engagements",
415
419
  dashboardUsageEngagementsHint: "Non-pageview events plus saved views",
@@ -420,6 +424,10 @@ const enUS = {
420
424
  dashboardUsageUsers: "Users",
421
425
  dashboardUsageModified: "Modified",
422
426
  dashboardUsageCreated: "Created",
427
+ dashboardMetadataCreated: "Created",
428
+ dashboardMetadataCreatedBy: "Created by",
429
+ dashboardMetadataUpdated: "Updated",
430
+ dashboardMetadataUpdatedBy: "Updated by",
423
431
  dashboardUsageState: "State",
424
432
  dashboardUsagePanels: "{{count}} panels",
425
433
  dashboardUsageSavedViews: "{{count}} saved views",
@@ -11293,6 +11301,10 @@ const translatedDashboardAdminTranslations = {
11293
11301
  dashboardUsageTotal: "仪表板",
11294
11302
  dashboardUsageActive: "{{count}} 个活跃",
11295
11303
  dashboardUsageViews: "浏览量",
11304
+ dashboardUsageEdits: "编辑次数",
11305
+ dashboardUsageSort: "排序仪表板",
11306
+ dashboardUsageMostViewed: "浏览最多",
11307
+ dashboardUsageMostEdited: "编辑最多",
11296
11308
  dashboardUsageTop: "最高:{{name}}",
11297
11309
  dashboardUsageEngagements: "互动",
11298
11310
  dashboardUsageEngagementsHint: "非页面浏览事件加已保存视图",
@@ -11303,6 +11315,10 @@ const translatedDashboardAdminTranslations = {
11303
11315
  dashboardUsageUsers: "用户",
11304
11316
  dashboardUsageModified: "修改时间",
11305
11317
  dashboardUsageCreated: "创建时间",
11318
+ dashboardMetadataCreated: "创建时间",
11319
+ dashboardMetadataCreatedBy: "创建者",
11320
+ dashboardMetadataUpdated: "更新时间",
11321
+ dashboardMetadataUpdatedBy: "更新者",
11306
11322
  dashboardUsageState: "状态",
11307
11323
  dashboardUsagePanels: "{{count}} 个面板",
11308
11324
  dashboardUsageSavedViews: "{{count}} 个已保存视图",
@@ -11332,6 +11348,10 @@ const translatedDashboardAdminTranslations = {
11332
11348
  dashboardUsageTotal: "Paneles",
11333
11349
  dashboardUsageActive: "{{count}} activos",
11334
11350
  dashboardUsageViews: "Vistas",
11351
+ dashboardUsageEdits: "Ediciones",
11352
+ dashboardUsageSort: "Ordenar paneles",
11353
+ dashboardUsageMostViewed: "Más vistas",
11354
+ dashboardUsageMostEdited: "Más editados",
11335
11355
  dashboardUsageTop: "Principal: {{name}}",
11336
11356
  dashboardUsageEngagements: "Interacciones",
11337
11357
  dashboardUsageEngagementsHint:
@@ -11343,6 +11363,10 @@ const translatedDashboardAdminTranslations = {
11343
11363
  dashboardUsageUsers: "Usuarios",
11344
11364
  dashboardUsageModified: "Modificado",
11345
11365
  dashboardUsageCreated: "Creado",
11366
+ dashboardMetadataCreated: "Creado",
11367
+ dashboardMetadataCreatedBy: "Creado por",
11368
+ dashboardMetadataUpdated: "Modificado",
11369
+ dashboardMetadataUpdatedBy: "Modificado por",
11346
11370
  dashboardUsageState: "Estado",
11347
11371
  dashboardUsagePanels: "{{count}} paneles",
11348
11372
  dashboardUsageSavedViews: "{{count}} vistas guardadas",
@@ -11372,6 +11396,10 @@ const translatedDashboardAdminTranslations = {
11372
11396
  dashboardUsageTotal: "Tableaux de bord",
11373
11397
  dashboardUsageActive: "{{count}} actifs",
11374
11398
  dashboardUsageViews: "Vues",
11399
+ dashboardUsageEdits: "Modifications",
11400
+ dashboardUsageSort: "Trier les tableaux",
11401
+ dashboardUsageMostViewed: "Les plus consultés",
11402
+ dashboardUsageMostEdited: "Les plus modifiés",
11375
11403
  dashboardUsageTop: "Meilleur : {{name}}",
11376
11404
  dashboardUsageEngagements: "Engagements",
11377
11405
  dashboardUsageEngagementsHint:
@@ -11383,6 +11411,10 @@ const translatedDashboardAdminTranslations = {
11383
11411
  dashboardUsageUsers: "Utilisateurs",
11384
11412
  dashboardUsageModified: "Modifié",
11385
11413
  dashboardUsageCreated: "Créé",
11414
+ dashboardMetadataCreated: "Créé",
11415
+ dashboardMetadataCreatedBy: "Créé par",
11416
+ dashboardMetadataUpdated: "Modifié",
11417
+ dashboardMetadataUpdatedBy: "Modifié par",
11386
11418
  dashboardUsageState: "État",
11387
11419
  dashboardUsagePanels: "{{count}} panneaux",
11388
11420
  dashboardUsageSavedViews: "{{count}} vues enregistrées",
@@ -11412,6 +11444,10 @@ const translatedDashboardAdminTranslations = {
11412
11444
  dashboardUsageTotal: "Dashboards",
11413
11445
  dashboardUsageActive: "{{count}} aktiv",
11414
11446
  dashboardUsageViews: "Aufrufe",
11447
+ dashboardUsageEdits: "Bearbeitungen",
11448
+ dashboardUsageSort: "Dashboards sortieren",
11449
+ dashboardUsageMostViewed: "Am häufigsten aufgerufen",
11450
+ dashboardUsageMostEdited: "Am häufigsten bearbeitet",
11415
11451
  dashboardUsageTop: "Top: {{name}}",
11416
11452
  dashboardUsageEngagements: "Interaktionen",
11417
11453
  dashboardUsageEngagementsHint:
@@ -11423,6 +11459,10 @@ const translatedDashboardAdminTranslations = {
11423
11459
  dashboardUsageUsers: "Benutzer",
11424
11460
  dashboardUsageModified: "Geändert",
11425
11461
  dashboardUsageCreated: "Erstellt",
11462
+ dashboardMetadataCreated: "Erstellt",
11463
+ dashboardMetadataCreatedBy: "Erstellt von",
11464
+ dashboardMetadataUpdated: "Geändert",
11465
+ dashboardMetadataUpdatedBy: "Geändert von",
11426
11466
  dashboardUsageState: "Status",
11427
11467
  dashboardUsagePanels: "{{count}} Panels",
11428
11468
  dashboardUsageSavedViews: "{{count}} gespeicherte Ansichten",
@@ -11452,6 +11492,10 @@ const translatedDashboardAdminTranslations = {
11452
11492
  dashboardUsageTotal: "ダッシュボード",
11453
11493
  dashboardUsageActive: "{{count}} 件がアクティブ",
11454
11494
  dashboardUsageViews: "閲覧数",
11495
+ dashboardUsageEdits: "編集数",
11496
+ dashboardUsageSort: "ダッシュボードを並べ替え",
11497
+ dashboardUsageMostViewed: "閲覧数が多い順",
11498
+ dashboardUsageMostEdited: "編集数が多い順",
11455
11499
  dashboardUsageTop: "トップ:{{name}}",
11456
11500
  dashboardUsageEngagements: "エンゲージメント",
11457
11501
  dashboardUsageEngagementsHint:
@@ -11463,6 +11507,10 @@ const translatedDashboardAdminTranslations = {
11463
11507
  dashboardUsageUsers: "ユーザー",
11464
11508
  dashboardUsageModified: "更新日",
11465
11509
  dashboardUsageCreated: "作成日",
11510
+ dashboardMetadataCreated: "作成日",
11511
+ dashboardMetadataCreatedBy: "作成者",
11512
+ dashboardMetadataUpdated: "更新日",
11513
+ dashboardMetadataUpdatedBy: "更新者",
11466
11514
  dashboardUsageState: "状態",
11467
11515
  dashboardUsagePanels: "{{count}} パネル",
11468
11516
  dashboardUsageSavedViews: "{{count}} 件の保存済みビュー",
@@ -11492,6 +11540,10 @@ const translatedDashboardAdminTranslations = {
11492
11540
  dashboardUsageTotal: "대시보드",
11493
11541
  dashboardUsageActive: "{{count}}개 활성",
11494
11542
  dashboardUsageViews: "조회수",
11543
+ dashboardUsageEdits: "편집 횟수",
11544
+ dashboardUsageSort: "대시보드 정렬",
11545
+ dashboardUsageMostViewed: "조회수 많은 순",
11546
+ dashboardUsageMostEdited: "편집 많은 순",
11495
11547
  dashboardUsageTop: "상위: {{name}}",
11496
11548
  dashboardUsageEngagements: "참여",
11497
11549
  dashboardUsageEngagementsHint: "페이지뷰 외 이벤트와 저장된 보기",
@@ -11502,6 +11554,10 @@ const translatedDashboardAdminTranslations = {
11502
11554
  dashboardUsageUsers: "사용자",
11503
11555
  dashboardUsageModified: "수정됨",
11504
11556
  dashboardUsageCreated: "생성됨",
11557
+ dashboardMetadataCreated: "생성됨",
11558
+ dashboardMetadataCreatedBy: "생성자",
11559
+ dashboardMetadataUpdated: "수정됨",
11560
+ dashboardMetadataUpdatedBy: "수정자",
11505
11561
  dashboardUsageState: "상태",
11506
11562
  dashboardUsagePanels: "{{count}}개 패널",
11507
11563
  dashboardUsageSavedViews: "{{count}}개 저장된 보기",
@@ -11531,6 +11587,10 @@ const translatedDashboardAdminTranslations = {
11531
11587
  dashboardUsageTotal: "Painéis",
11532
11588
  dashboardUsageActive: "{{count}} ativos",
11533
11589
  dashboardUsageViews: "Visualizações",
11590
+ dashboardUsageEdits: "Edições",
11591
+ dashboardUsageSort: "Ordenar painéis",
11592
+ dashboardUsageMostViewed: "Mais visualizados",
11593
+ dashboardUsageMostEdited: "Mais editados",
11534
11594
  dashboardUsageTop: "Principal: {{name}}",
11535
11595
  dashboardUsageEngagements: "Engajamentos",
11536
11596
  dashboardUsageEngagementsHint:
@@ -11542,6 +11602,10 @@ const translatedDashboardAdminTranslations = {
11542
11602
  dashboardUsageUsers: "Usuários",
11543
11603
  dashboardUsageModified: "Modificado",
11544
11604
  dashboardUsageCreated: "Criado",
11605
+ dashboardMetadataCreated: "Criado",
11606
+ dashboardMetadataCreatedBy: "Criado por",
11607
+ dashboardMetadataUpdated: "Modificado",
11608
+ dashboardMetadataUpdatedBy: "Modificado por",
11545
11609
  dashboardUsageState: "Estado",
11546
11610
  dashboardUsagePanels: "{{count}} painéis",
11547
11611
  dashboardUsageSavedViews: "{{count}} visualizações salvas",
@@ -11571,6 +11635,10 @@ const translatedDashboardAdminTranslations = {
11571
11635
  dashboardUsageTotal: "डैशबोर्ड",
11572
11636
  dashboardUsageActive: "{{count}} सक्रिय",
11573
11637
  dashboardUsageViews: "व्यू",
11638
+ dashboardUsageEdits: "संपादन",
11639
+ dashboardUsageSort: "डैशबोर्ड क्रमित करें",
11640
+ dashboardUsageMostViewed: "सबसे अधिक देखे गए",
11641
+ dashboardUsageMostEdited: "सबसे अधिक संपादित",
11574
11642
  dashboardUsageTop: "शीर्ष: {{name}}",
11575
11643
  dashboardUsageEngagements: "एंगेजमेंट",
11576
11644
  dashboardUsageEngagementsHint: "Non-pageview events और saved views",
@@ -11581,6 +11649,10 @@ const translatedDashboardAdminTranslations = {
11581
11649
  dashboardUsageUsers: "यूज़र",
11582
11650
  dashboardUsageModified: "संशोधित",
11583
11651
  dashboardUsageCreated: "बनाया गया",
11652
+ dashboardMetadataCreated: "बनाया गया",
11653
+ dashboardMetadataCreatedBy: "इसके द्वारा बनाया गया",
11654
+ dashboardMetadataUpdated: "संशोधित",
11655
+ dashboardMetadataUpdatedBy: "इसके द्वारा संशोधित",
11584
11656
  dashboardUsageState: "स्थिति",
11585
11657
  dashboardUsagePanels: "{{count}} पैनल",
11586
11658
  dashboardUsageSavedViews: "{{count}} saved views",
@@ -11610,6 +11682,10 @@ const translatedDashboardAdminTranslations = {
11610
11682
  dashboardUsageTotal: "لوحات المعلومات",
11611
11683
  dashboardUsageActive: "{{count}} نشطة",
11612
11684
  dashboardUsageViews: "المشاهدات",
11685
+ dashboardUsageEdits: "التعديلات",
11686
+ dashboardUsageSort: "فرز لوحات المعلومات",
11687
+ dashboardUsageMostViewed: "الأكثر مشاهدة",
11688
+ dashboardUsageMostEdited: "الأكثر تعديلاً",
11613
11689
  dashboardUsageTop: "الأعلى: {{name}}",
11614
11690
  dashboardUsageEngagements: "التفاعلات",
11615
11691
  dashboardUsageEngagementsHint:
@@ -11621,6 +11697,10 @@ const translatedDashboardAdminTranslations = {
11621
11697
  dashboardUsageUsers: "المستخدمون",
11622
11698
  dashboardUsageModified: "عُدّلت",
11623
11699
  dashboardUsageCreated: "أُنشئت",
11700
+ dashboardMetadataCreated: "أُنشئت",
11701
+ dashboardMetadataCreatedBy: "أنشأها",
11702
+ dashboardMetadataUpdated: "عُدّلت",
11703
+ dashboardMetadataUpdatedBy: "عدّلها",
11624
11704
  dashboardUsageState: "الحالة",
11625
11705
  dashboardUsagePanels: "{{count}} لوحات",
11626
11706
  dashboardUsageSavedViews: "{{count}} طرق عرض محفوظة",
@@ -106,6 +106,7 @@ interface DashboardUsageStats {
106
106
  viewCount: number;
107
107
  engagementCount: number;
108
108
  eventEngagementCount: number;
109
+ editCount: number;
109
110
  savedViewCount: number;
110
111
  uniqueUserCount: number;
111
112
  lastViewedAt: string | null;
@@ -135,6 +136,7 @@ function DashboardUsageAdminPanel() {
135
136
  const t = useT();
136
137
  const { formatDate } = useFormatters();
137
138
  const numberFormat = useMemo(() => new Intl.NumberFormat(), []);
139
+ const [sortBy, setSortBy] = useState<"views" | "edits">("views");
138
140
  const {
139
141
  data: dashboards = [],
140
142
  isLoading,
@@ -172,7 +174,25 @@ function DashboardUsageAdminPanel() {
172
174
  const staleDashboards = dashboards.filter(
173
175
  (dashboard) => dashboard.viewCount === 0 && !dashboard.archivedAt,
174
176
  );
175
- const mostViewedDashboard = dashboards[0] ?? null;
177
+ const mostViewedDashboard = dashboards.reduce<DashboardUsageStats | null>(
178
+ (mostViewed, dashboard) =>
179
+ !mostViewed || dashboard.viewCount > mostViewed.viewCount
180
+ ? dashboard
181
+ : mostViewed,
182
+ null,
183
+ );
184
+ const sortedDashboards = useMemo(
185
+ () =>
186
+ [...dashboards].sort((a, b) => {
187
+ const primary =
188
+ sortBy === "views"
189
+ ? b.viewCount - a.viewCount
190
+ : b.editCount - a.editCount;
191
+ if (primary !== 0) return primary;
192
+ return b.updatedAt.localeCompare(a.updatedAt);
193
+ }),
194
+ [dashboards, sortBy],
195
+ );
176
196
 
177
197
  return (
178
198
  <div className="flex min-w-0 flex-1 flex-col gap-4">
@@ -185,6 +205,27 @@ function DashboardUsageAdminPanel() {
185
205
  {t("agents.dashboardUsageDescription")}
186
206
  </p>
187
207
  </div>
208
+ <Select
209
+ value={sortBy}
210
+ onValueChange={(value) => {
211
+ if (value === "views" || value === "edits") setSortBy(value);
212
+ }}
213
+ >
214
+ <SelectTrigger
215
+ className="w-44"
216
+ aria-label={t("agents.dashboardUsageSort")}
217
+ >
218
+ <SelectValue />
219
+ </SelectTrigger>
220
+ <SelectContent>
221
+ <SelectItem value="views">
222
+ {t("agents.dashboardUsageMostViewed")}
223
+ </SelectItem>
224
+ <SelectItem value="edits">
225
+ {t("agents.dashboardUsageMostEdited")}
226
+ </SelectItem>
227
+ </SelectContent>
228
+ </Select>
188
229
  </div>
189
230
 
190
231
  {error ? (
@@ -260,6 +301,7 @@ function DashboardUsageAdminPanel() {
260
301
  <TableHead>{t("agents.dashboardUsageDashboard")}</TableHead>
261
302
  <TableHead>{t("agents.dashboardUsageOwner")}</TableHead>
262
303
  <TableHead>{t("agents.dashboardUsageViews")}</TableHead>
304
+ <TableHead>{t("agents.dashboardUsageEdits")}</TableHead>
263
305
  <TableHead>
264
306
  {t("agents.dashboardUsageEngagements")}
265
307
  </TableHead>
@@ -270,7 +312,7 @@ function DashboardUsageAdminPanel() {
270
312
  </TableRow>
271
313
  </TableHeader>
272
314
  <TableBody>
273
- {dashboards.map((dashboard) => (
315
+ {sortedDashboards.map((dashboard) => (
274
316
  <TableRow key={dashboard.id}>
275
317
  <TableCell className="min-w-[240px]">
276
318
  <div className="flex min-w-0 flex-col gap-1">
@@ -303,6 +345,11 @@ function DashboardUsageAdminPanel() {
303
345
  {formatMaybeDate(dashboard.lastViewedAt)}
304
346
  </div>
305
347
  </TableCell>
348
+ <TableCell>
349
+ <div className="font-medium">
350
+ {formatCount(dashboard.editCount)}
351
+ </div>
352
+ </TableCell>
306
353
  <TableCell>
307
354
  <div className="font-medium">
308
355
  {formatCount(dashboard.engagementCount)}
@@ -48,6 +48,7 @@ import { useSearchParams, useNavigate } from "react-router";
48
48
  import { toast } from "sonner";
49
49
 
50
50
  import { DashboardHistoryPanel } from "@/components/dashboard/DashboardHistoryPanel";
51
+ import { DashboardMetadata } from "@/components/dashboard/DashboardMetadata";
51
52
  import {
52
53
  DashboardTitleSkeleton,
53
54
  useSetPageTitle,
@@ -75,6 +76,7 @@ import {
75
76
  import {
76
77
  DropdownMenu,
77
78
  DropdownMenuContent,
79
+ DropdownMenuLabel,
78
80
  DropdownMenuItem,
79
81
  DropdownMenuSeparator,
80
82
  DropdownMenuTrigger,
@@ -115,6 +117,10 @@ const TAB_ID = generateTabId();
115
117
 
116
118
  type FetchedExplorerDashboard = {
117
119
  data: ExplorerDashboardData;
120
+ ownerEmail: string | null;
121
+ createdAt: string | null;
122
+ updatedAt: string | null;
123
+ updatedBy: string | null;
118
124
  archivedAt: string | null;
119
125
  hiddenAt: string | null;
120
126
  hiddenBy: string | null;
@@ -145,6 +151,10 @@ async function fetchDashboard(
145
151
  name: raw.name ?? "Untitled Dashboard",
146
152
  charts: raw.charts ?? [],
147
153
  },
154
+ ownerEmail: typeof raw.ownerEmail === "string" ? raw.ownerEmail : null,
155
+ createdAt: typeof raw.createdAt === "string" ? raw.createdAt : null,
156
+ updatedAt: typeof raw.updatedAt === "string" ? raw.updatedAt : null,
157
+ updatedBy: typeof raw.updatedBy === "string" ? raw.updatedBy : null,
148
158
  archivedAt: typeof raw.archivedAt === "string" ? raw.archivedAt : null,
149
159
  hiddenAt: typeof raw.hiddenAt === "string" ? raw.hiddenAt : null,
150
160
  hiddenBy: typeof raw.hiddenBy === "string" ? raw.hiddenBy : null,
@@ -178,6 +188,16 @@ export default function ExplorerDashboardPage() {
178
188
  const [dashboard, setDashboard] = useState<ExplorerDashboardData | null>(
179
189
  null,
180
190
  );
191
+ const [dashboardOwner, setDashboardOwner] = useState<string | null>(null);
192
+ const [dashboardCreatedAt, setDashboardCreatedAt] = useState<string | null>(
193
+ null,
194
+ );
195
+ const [dashboardUpdatedAt, setDashboardUpdatedAt] = useState<string | null>(
196
+ null,
197
+ );
198
+ const [dashboardUpdatedBy, setDashboardUpdatedBy] = useState<string | null>(
199
+ null,
200
+ );
181
201
  const [archivedAt, setArchivedAt] = useState<string | null>(null);
182
202
  const [hiddenAt, setHiddenAt] = useState<string | null>(null);
183
203
  const [hiddenBy, setHiddenBy] = useState<string | null>(null);
@@ -307,6 +327,10 @@ export default function ExplorerDashboardPage() {
307
327
  if (!dashboardId) return;
308
328
  setLoaded(false);
309
329
  setDashboard(null);
330
+ setDashboardOwner(null);
331
+ setDashboardCreatedAt(null);
332
+ setDashboardUpdatedAt(null);
333
+ setDashboardUpdatedBy(null);
310
334
  setHiddenAt(null);
311
335
  setHiddenBy(null);
312
336
  setResourceAccess(null);
@@ -318,6 +342,10 @@ export default function ExplorerDashboardPage() {
318
342
  const d = dashboardQuery.data;
319
343
  if (d) {
320
344
  setDashboard(d.data);
345
+ setDashboardOwner(d.ownerEmail);
346
+ setDashboardCreatedAt(d.createdAt);
347
+ setDashboardUpdatedAt(d.updatedAt);
348
+ setDashboardUpdatedBy(d.updatedBy);
321
349
  setArchivedAt(d.archivedAt);
322
350
  setHiddenAt(d.hiddenAt);
323
351
  setHiddenBy(d.hiddenBy);
@@ -331,6 +359,10 @@ export default function ExplorerDashboardPage() {
331
359
  name: t("explorerDashboard.untitledDashboard"),
332
360
  charts: [],
333
361
  });
362
+ setDashboardOwner(null);
363
+ setDashboardCreatedAt(null);
364
+ setDashboardUpdatedAt(null);
365
+ setDashboardUpdatedBy(null);
334
366
  setArchivedAt(null);
335
367
  setHiddenAt(null);
336
368
  setHiddenBy(null);
@@ -644,18 +676,29 @@ export default function ExplorerDashboardPage() {
644
676
  {t("explorerDashboard.moreActions")}
645
677
  </TooltipContent>
646
678
  </Tooltip>
647
- <DropdownMenuContent align="end" className="w-44">
679
+ <DropdownMenuContent align="end" className="w-72">
648
680
  {dashboardId ? (
649
- <DropdownMenuItem
650
- onSelect={(event) => {
651
- event.preventDefault();
652
- setDashboardActionsOpen(false);
653
- setHistoryOpen(true);
654
- }}
655
- >
656
- <IconHistory className="mr-2 h-3.5 w-3.5" />
657
- {t("dashboard.historyTitle")}
658
- </DropdownMenuItem>
681
+ <>
682
+ <DropdownMenuLabel className="font-normal">
683
+ <DashboardMetadata
684
+ createdAt={dashboardCreatedAt}
685
+ createdBy={dashboardOwner}
686
+ updatedAt={dashboardUpdatedAt}
687
+ updatedBy={dashboardUpdatedBy}
688
+ />
689
+ </DropdownMenuLabel>
690
+ <DropdownMenuSeparator />
691
+ <DropdownMenuItem
692
+ onSelect={(event) => {
693
+ event.preventDefault();
694
+ setDashboardActionsOpen(false);
695
+ setHistoryOpen(true);
696
+ }}
697
+ >
698
+ <IconHistory className="mr-2 h-3.5 w-3.5" />
699
+ {t("dashboard.historyTitle")}
700
+ </DropdownMenuItem>
701
+ </>
659
702
  ) : null}
660
703
  {dashboardId && canEdit && !archivedAt ? (
661
704
  <DropdownMenuSeparator />
@@ -4,7 +4,6 @@ import { useDraggable } from "@dnd-kit/core";
4
4
  import {
5
5
  IconGripVertical,
6
6
  IconDotsVertical,
7
- IconExternalLink,
8
7
  IconMaximize,
9
8
  IconPencil,
10
9
  IconRefresh,
@@ -14,9 +13,8 @@ import {
14
13
  IconMessageCircle,
15
14
  IconBrandGoogle,
16
15
  } from "@tabler/icons-react";
17
- import { useIsFetching, useQueryClient } from "@tanstack/react-query";
16
+ import { useQueryClient } from "@tanstack/react-query";
18
17
  import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
19
- import { useNavigate } from "react-router";
20
18
  import { toast } from "sonner";
21
19
 
22
20
  import { ChartFillHeight, SqlChart } from "@/components/dashboard/SqlChart";
@@ -44,7 +42,6 @@ import {
44
42
  DropdownMenuSeparator,
45
43
  DropdownMenuTrigger,
46
44
  } from "@/components/ui/dropdown-menu";
47
- import { Spinner } from "@/components/ui/spinner";
48
45
  import {
49
46
  Tooltip,
50
47
  TooltipContent,
@@ -143,7 +140,6 @@ export function SqlChartCard({
143
140
  const [confirmOpen, setConfirmOpen] = useState(false);
144
141
  const [expanded, setExpanded] = useState(false);
145
142
  const [extRefreshKey, setExtRefreshKey] = useState(0);
146
- const navigate = useNavigate();
147
143
  const [exportCsv, setExportCsv] = useState<(() => void) | null>(null);
148
144
  const [shouldLoadData, setShouldLoadData] = useState(
149
145
  eagerLoad ||
@@ -161,17 +157,6 @@ export function SqlChartCard({
161
157
  ] as const,
162
158
  [panel.id, panel.source, panel.sql, resolvedSql],
163
159
  );
164
- const chartFetchCount = useIsFetching({ queryKey: chartQueryKey });
165
- const chartHasCachedData =
166
- queryClient.getQueryData(chartQueryKey) !== undefined;
167
- const isChartRefreshing = chartHasCachedData && chartFetchCount > 0;
168
- const extensionId =
169
- panel.chartType === "extension"
170
- ? ((panel.config as Record<string, unknown> | undefined)?.extensionId as
171
- | string
172
- | undefined)
173
- : undefined;
174
-
175
160
  const setCardNodeRef = useCallback((node: HTMLDivElement | null) => {
176
161
  cardRef.current = node;
177
162
  }, []);
@@ -373,7 +358,7 @@ export function SqlChartCard({
373
358
 
374
359
  // Extension panels render their sandboxed iframe full-bleed with no card chrome
375
360
  // or title — the extension owns its own UI. All viewers get the read-only
376
- // actions (full screen, refresh, open embedded extension); editable
361
+ // actions (full screen and refresh); editable
377
362
  // dashboards also get delete and drag.
378
363
  if (panel.chartType === "extension") {
379
364
  return (
@@ -429,22 +414,6 @@ export function SqlChartCard({
429
414
  <IconMaximize className="h-4 w-4 mr-2" />
430
415
  {t("sqlDashboard.fullScreen")}
431
416
  </DropdownMenuItem>
432
- {extensionId ? (
433
- <DropdownMenuItem
434
- onSelect={() =>
435
- navigate(
436
- `/extensions/${extensionId}/${encodeURIComponent(
437
- (panel.title ?? "extension")
438
- .toLowerCase()
439
- .replace(/[^a-z0-9]+/g, "-"),
440
- )}`,
441
- )
442
- }
443
- >
444
- <IconExternalLink className="h-4 w-4 mr-2" />
445
- Open embedded extension {/* i18n-ignore */}
446
- </DropdownMenuItem>
447
- ) : null}
448
417
  <DropdownMenuSeparator />
449
418
  <DropdownMenuItem onSelect={() => setExtRefreshKey((k) => k + 1)}>
450
419
  <IconRefresh className="h-4 w-4 mr-2" />
@@ -556,26 +525,7 @@ export function SqlChartCard({
556
525
  <CardTitle className="text-sm font-medium flex-1 truncate">
557
526
  {panel.title}
558
527
  </CardTitle>
559
- <div
560
- className={`flex items-center gap-1 transition-opacity ${
561
- isChartRefreshing
562
- ? "opacity-100"
563
- : "opacity-0 group-hover:opacity-100 focus-within:opacity-100"
564
- }`}
565
- >
566
- {isChartRefreshing ? (
567
- <Tooltip>
568
- <TooltipTrigger asChild>
569
- <span className="inline-flex size-6 items-center justify-center rounded text-muted-foreground">
570
- <Spinner
571
- className="size-3.5"
572
- aria-label={t("sqlDashboard.refreshing")}
573
- />
574
- </span>
575
- </TooltipTrigger>
576
- <TooltipContent>{t("sqlDashboard.refreshing")}</TooltipContent>
577
- </Tooltip>
578
- ) : null}
528
+ <div className="flex items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100 focus-within:opacity-100">
579
529
  {editable && onSaveSql ? (
580
530
  <ViewSqlPopover
581
531
  panel={panel}