@burdenoff/microfe-bigconsole 2026.805.2 → 2026.812.1

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 (253) hide show
  1. package/dist/bigconsole/components/DrilldownDashboardRenderer.js +118 -106
  2. package/dist/bigconsole/components/DrilldownDashboardRenderer.js.map +1 -1
  3. package/dist/bigconsole/components/DrilldownModal.js +54 -50
  4. package/dist/bigconsole/components/DrilldownModal.js.map +1 -1
  5. package/dist/bigconsole/components/builder/BuilderCanvas.js +2 -2
  6. package/dist/bigconsole/components/builder/BuilderCanvas.js.map +1 -1
  7. package/dist/bigconsole/components/builder/BuilderTopbar.js +3 -3
  8. package/dist/bigconsole/components/builder/BuilderTopbar.js.map +1 -1
  9. package/dist/bigconsole/components/builder/inspector/AdvancedSection.js +24 -25
  10. package/dist/bigconsole/components/builder/inspector/AdvancedSection.js.map +1 -1
  11. package/dist/bigconsole/components/builder/inspector/AppearanceSection.js +40 -29
  12. package/dist/bigconsole/components/builder/inspector/AppearanceSection.js.map +1 -1
  13. package/dist/bigconsole/components/builder/inspector/DataBindingSection.js +145 -111
  14. package/dist/bigconsole/components/builder/inspector/DataBindingSection.js.map +1 -1
  15. package/dist/bigconsole/components/builder/inspector/GeneralSection.js +58 -44
  16. package/dist/bigconsole/components/builder/inspector/GeneralSection.js.map +1 -1
  17. package/dist/bigconsole/components/common/Section.js +70 -0
  18. package/dist/bigconsole/components/common/Section.js.map +1 -0
  19. package/dist/bigconsole/components/common/index.js +2 -0
  20. package/dist/bigconsole/components/common/sectionStyles.js +42 -0
  21. package/dist/bigconsole/components/common/sectionStyles.js.map +1 -0
  22. package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js +269 -251
  23. package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js.map +1 -1
  24. package/dist/bigconsole/components/dashboard/DashboardCanvas.js +214 -223
  25. package/dist/bigconsole/components/dashboard/DashboardCanvas.js.map +1 -1
  26. package/dist/bigconsole/components/dashboard/DashboardGrid.js +12 -18
  27. package/dist/bigconsole/components/dashboard/DashboardGrid.js.map +1 -1
  28. package/dist/bigconsole/components/dashboard/DashboardToolbar.js +110 -102
  29. package/dist/bigconsole/components/dashboard/DashboardToolbar.js.map +1 -1
  30. package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js +81 -68
  31. package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js.map +1 -1
  32. package/dist/bigconsole/components/dashboard/ExportDashboardDialog.js +125 -159
  33. package/dist/bigconsole/components/dashboard/ExportDashboardDialog.js.map +1 -1
  34. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterChip.js +147 -144
  35. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterChip.js.map +1 -1
  36. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js +154 -153
  37. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js.map +1 -1
  38. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js +82 -79
  39. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js.map +1 -1
  40. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js +171 -284
  41. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js.map +1 -1
  42. package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js +250 -273
  43. package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js.map +1 -1
  44. package/dist/bigconsole/components/dashboard/LiveBoardBanner.js +45 -53
  45. package/dist/bigconsole/components/dashboard/LiveBoardBanner.js.map +1 -1
  46. package/dist/bigconsole/components/dashboard/PageTabsManager/PageTabsManager.js +157 -148
  47. package/dist/bigconsole/components/dashboard/PageTabsManager/PageTabsManager.js.map +1 -1
  48. package/dist/bigconsole/components/dashboard/PublishToStoreDialog.js +75 -83
  49. package/dist/bigconsole/components/dashboard/PublishToStoreDialog.js.map +1 -1
  50. package/dist/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.js +167 -161
  51. package/dist/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.js.map +1 -1
  52. package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js +181 -190
  53. package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js.map +1 -1
  54. package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js +101 -95
  55. package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js.map +1 -1
  56. package/dist/bigconsole/components/dashboard/StoreTemplatePicker.js +20 -18
  57. package/dist/bigconsole/components/dashboard/StoreTemplatePicker.js.map +1 -1
  58. package/dist/bigconsole/components/dashboard/TemplatePicker/TemplatePicker.js +1 -0
  59. package/dist/bigconsole/components/dashboard/TemplateSetupBanner.js +26 -58
  60. package/dist/bigconsole/components/dashboard/TemplateSetupBanner.js.map +1 -1
  61. package/dist/bigconsole/components/dashboard/WidgetPalette.js +307 -229
  62. package/dist/bigconsole/components/dashboard/WidgetPalette.js.map +1 -1
  63. package/dist/bigconsole/components/datasink/CacheTTLSelector.js +128 -129
  64. package/dist/bigconsole/components/datasink/CacheTTLSelector.js.map +1 -1
  65. package/dist/bigconsole/components/datasink/DataSinkCard.js +78 -79
  66. package/dist/bigconsole/components/datasink/DataSinkCard.js.map +1 -1
  67. package/dist/bigconsole/components/datasink/DataSinkDataViewer.js +33 -34
  68. package/dist/bigconsole/components/datasink/DataSinkDataViewer.js.map +1 -1
  69. package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js +79 -61
  70. package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js.map +1 -1
  71. package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js +75 -64
  72. package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js.map +1 -1
  73. package/dist/bigconsole/components/datasink/DataSinkStatusBadge.js +1 -1
  74. package/dist/bigconsole/components/datasink/DataSinkStatusBadge.js.map +1 -1
  75. package/dist/bigconsole/components/datasink/DataSinkTableViewer.js +20 -19
  76. package/dist/bigconsole/components/datasink/DataSinkTableViewer.js.map +1 -1
  77. package/dist/bigconsole/components/datasink/ExportDataSinkDialog.js +127 -171
  78. package/dist/bigconsole/components/datasink/ExportDataSinkDialog.js.map +1 -1
  79. package/dist/bigconsole/components/datasink/ImportDataGuideDialog.js +113 -117
  80. package/dist/bigconsole/components/datasink/ImportDataGuideDialog.js.map +1 -1
  81. package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js +312 -307
  82. package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js.map +1 -1
  83. package/dist/bigconsole/components/datasink/LinkedParsersPanel.js +65 -66
  84. package/dist/bigconsole/components/datasink/LinkedParsersPanel.js.map +1 -1
  85. package/dist/bigconsole/components/datasink/LinkedWorkflowsPanel.js +121 -127
  86. package/dist/bigconsole/components/datasink/LinkedWorkflowsPanel.js.map +1 -1
  87. package/dist/bigconsole/components/datasink/RefreshTypeSelector.js +194 -189
  88. package/dist/bigconsole/components/datasink/RefreshTypeSelector.js.map +1 -1
  89. package/dist/bigconsole/components/datasink/SetupStateBadge.js +3 -3
  90. package/dist/bigconsole/components/datasink/SetupStateBadge.js.map +1 -1
  91. package/dist/bigconsole/components/datasink/WorkflowStatusPanel.js +95 -95
  92. package/dist/bigconsole/components/datasink/WorkflowStatusPanel.js.map +1 -1
  93. package/dist/bigconsole/components/parser/DataSinkSelector.js +163 -131
  94. package/dist/bigconsole/components/parser/DataSinkSelector.js.map +1 -1
  95. package/dist/bigconsole/components/parser/ExpressionEditor.js +3 -3
  96. package/dist/bigconsole/components/parser/ExpressionEditor.js.map +1 -1
  97. package/dist/bigconsole/components/parser/ImportParserDialog.js +205 -260
  98. package/dist/bigconsole/components/parser/ImportParserDialog.js.map +1 -1
  99. package/dist/bigconsole/components/parser/ParserCard.js +133 -114
  100. package/dist/bigconsole/components/parser/ParserCard.js.map +1 -1
  101. package/dist/bigconsole/components/parser/ParserSelector.js +193 -174
  102. package/dist/bigconsole/components/parser/ParserSelector.js.map +1 -1
  103. package/dist/bigconsole/components/parser/ParserStatusBadge.js +2 -2
  104. package/dist/bigconsole/components/parser/ParserStatusBadge.js.map +1 -1
  105. package/dist/bigconsole/components/parser/ParserTypeBadge.js +4 -4
  106. package/dist/bigconsole/components/parser/ParserTypeBadge.js.map +1 -1
  107. package/dist/bigconsole/components/pipeline/PipelineCard.js +134 -89
  108. package/dist/bigconsole/components/pipeline/PipelineCard.js.map +1 -1
  109. package/dist/bigconsole/components/pipeline/PipelineDeleteDialog.js +77 -64
  110. package/dist/bigconsole/components/pipeline/PipelineDeleteDialog.js.map +1 -1
  111. package/dist/bigconsole/components/pipeline/PipelineStatusBadge.js +7 -10
  112. package/dist/bigconsole/components/pipeline/PipelineStatusBadge.js.map +1 -1
  113. package/dist/bigconsole/components/preview/AiPreviewContent.js +31 -32
  114. package/dist/bigconsole/components/preview/AiPreviewContent.js.map +1 -1
  115. package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js +152 -103
  116. package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js.map +1 -1
  117. package/dist/bigconsole/components/preview/AiPreviewPanel.js +193 -148
  118. package/dist/bigconsole/components/preview/AiPreviewPanel.js.map +1 -1
  119. package/dist/bigconsole/components/preview/previewShared.js +41 -23
  120. package/dist/bigconsole/components/preview/previewShared.js.map +1 -1
  121. package/dist/bigconsole/components/widgets/ActionConfigDialog.js +405 -364
  122. package/dist/bigconsole/components/widgets/ActionConfigDialog.js.map +1 -1
  123. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js +265 -237
  124. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js.map +1 -1
  125. package/dist/bigconsole/components/widgets/PropertiesPanel.js +764 -821
  126. package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
  127. package/dist/bigconsole/components/widgets/WidgetErrorBoundary.js +7 -5
  128. package/dist/bigconsole/components/widgets/WidgetErrorBoundary.js.map +1 -1
  129. package/dist/bigconsole/components/widgets/WidgetHeader.js +7 -8
  130. package/dist/bigconsole/components/widgets/WidgetHeader.js.map +1 -1
  131. package/dist/bigconsole/components/widgets/WidgetWrapper.js +8 -7
  132. package/dist/bigconsole/components/widgets/WidgetWrapper.js.map +1 -1
  133. package/dist/bigconsole/components/widgets/adaptive-card/AdaptiveCardWidget.js +1 -1
  134. package/dist/bigconsole/components/widgets/adaptive-card/AdaptiveCardWidget.js.map +1 -1
  135. package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js +46 -49
  136. package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js.map +1 -1
  137. package/dist/bigconsole/components/widgets/chart/ChartConfig.js +154 -147
  138. package/dist/bigconsole/components/widgets/chart/ChartConfig.js.map +1 -1
  139. package/dist/bigconsole/components/widgets/comments/WidgetComments.js +118 -101
  140. package/dist/bigconsole/components/widgets/comments/WidgetComments.js.map +1 -1
  141. package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js +244 -191
  142. package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js.map +1 -1
  143. package/dist/bigconsole/components/widgets/form/FormWidget.js +167 -159
  144. package/dist/bigconsole/components/widgets/form/FormWidget.js.map +1 -1
  145. package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js +92 -76
  146. package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js.map +1 -1
  147. package/dist/bigconsole/components/widgets/gauge/GaugeWidget.js +1 -1
  148. package/dist/bigconsole/components/widgets/gauge/GaugeWidget.js.map +1 -1
  149. package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js +89 -86
  150. package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js.map +1 -1
  151. package/dist/bigconsole/components/widgets/iframe-widget/IframeWidget.js +2 -2
  152. package/dist/bigconsole/components/widgets/iframe-widget/IframeWidget.js.map +1 -1
  153. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +64 -63
  154. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js.map +1 -1
  155. package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js +2 -2
  156. package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js.map +1 -1
  157. package/dist/bigconsole/components/widgets/list/ListConfig.js +65 -58
  158. package/dist/bigconsole/components/widgets/list/ListConfig.js.map +1 -1
  159. package/dist/bigconsole/components/widgets/list/ListItem.js +1 -1
  160. package/dist/bigconsole/components/widgets/list/ListItem.js.map +1 -1
  161. package/dist/bigconsole/components/widgets/map-widget/MapWidget.js +1 -1
  162. package/dist/bigconsole/components/widgets/map-widget/MapWidget.js.map +1 -1
  163. package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js +79 -72
  164. package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js.map +1 -1
  165. package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js +35 -34
  166. package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js.map +1 -1
  167. package/dist/bigconsole/components/widgets/metric-card/TrendIndicator.js +20 -19
  168. package/dist/bigconsole/components/widgets/metric-card/TrendIndicator.js.map +1 -1
  169. package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js +181 -180
  170. package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js.map +1 -1
  171. package/dist/bigconsole/components/widgets/progress/ProgressConfig.js +100 -90
  172. package/dist/bigconsole/components/widgets/progress/ProgressConfig.js.map +1 -1
  173. package/dist/bigconsole/components/widgets/retention/RetentionWidget.js +3 -3
  174. package/dist/bigconsole/components/widgets/retention/RetentionWidget.js.map +1 -1
  175. package/dist/bigconsole/components/widgets/states/EmptyState.js +6 -4
  176. package/dist/bigconsole/components/widgets/states/EmptyState.js.map +1 -1
  177. package/dist/bigconsole/components/widgets/states/ErrorState.js +7 -5
  178. package/dist/bigconsole/components/widgets/states/ErrorState.js.map +1 -1
  179. package/dist/bigconsole/components/widgets/states/LoadingState.js +5 -4
  180. package/dist/bigconsole/components/widgets/states/LoadingState.js.map +1 -1
  181. package/dist/bigconsole/components/widgets/table/TableConfig.js +193 -172
  182. package/dist/bigconsole/components/widgets/table/TableConfig.js.map +1 -1
  183. package/dist/bigconsole/components/widgets/table/TableHeader.js +1 -1
  184. package/dist/bigconsole/components/widgets/table/TableHeader.js.map +1 -1
  185. package/dist/bigconsole/components/widgets/table/TableWidget.js +1 -1
  186. package/dist/bigconsole/components/widgets/table/TableWidget.js.map +1 -1
  187. package/dist/bigconsole/components/widgets/text-widget/TextWidget.js +1 -1
  188. package/dist/bigconsole/components/widgets/text-widget/TextWidget.js.map +1 -1
  189. package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js +3 -3
  190. package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js.map +1 -1
  191. package/dist/bigconsole/components/widgets/utils/conditionalFormat.js +2 -2
  192. package/dist/bigconsole/components/widgets/utils/conditionalFormat.js.map +1 -1
  193. package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js +283 -249
  194. package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js.map +1 -1
  195. package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js +28 -20
  196. package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js.map +1 -1
  197. package/dist/bigconsole/components/workflow/WorkflowCard.js +92 -77
  198. package/dist/bigconsole/components/workflow/WorkflowCard.js.map +1 -1
  199. package/dist/bigconsole/components/workflow/WorkflowDeleteDialog.js +70 -51
  200. package/dist/bigconsole/components/workflow/WorkflowDeleteDialog.js.map +1 -1
  201. package/dist/bigconsole/components/workflow/WorkflowStatusBadge.js +16 -17
  202. package/dist/bigconsole/components/workflow/WorkflowStatusBadge.js.map +1 -1
  203. package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js +46 -42
  204. package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js.map +1 -1
  205. package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js +372 -348
  206. package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js.map +1 -1
  207. package/dist/bigconsole/hooks/useModalFocusTrap.js +53 -0
  208. package/dist/bigconsole/hooks/useModalFocusTrap.js.map +1 -0
  209. package/dist/bigconsole/pages/DashboardBuilderPage.js +153 -142
  210. package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
  211. package/dist/bigconsole/pages/DashboardViewPage.js +230 -220
  212. package/dist/bigconsole/pages/DashboardViewPage.js.map +1 -1
  213. package/dist/bigconsole/pages/DashboardsPage.js +832 -790
  214. package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
  215. package/dist/bigconsole/pages/DataParsersPage.js +249 -304
  216. package/dist/bigconsole/pages/DataParsersPage.js.map +1 -1
  217. package/dist/bigconsole/pages/DataSinkBuilderPage.js +324 -349
  218. package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
  219. package/dist/bigconsole/pages/DataSinkViewPage.js +336 -323
  220. package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
  221. package/dist/bigconsole/pages/DataSinksPage.js +356 -458
  222. package/dist/bigconsole/pages/DataSinksPage.js.map +1 -1
  223. package/dist/bigconsole/pages/DataSourcesPage.js +14 -8
  224. package/dist/bigconsole/pages/DataSourcesPage.js.map +1 -1
  225. package/dist/bigconsole/pages/HomePage.js +186 -193
  226. package/dist/bigconsole/pages/HomePage.js.map +1 -1
  227. package/dist/bigconsole/pages/InsightsPage.js +901 -724
  228. package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
  229. package/dist/bigconsole/pages/ParserBuilderPage.js +769 -675
  230. package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
  231. package/dist/bigconsole/pages/ParserViewPage.js +382 -354
  232. package/dist/bigconsole/pages/ParserViewPage.js.map +1 -1
  233. package/dist/bigconsole/pages/PipelineBuilderPage.js +540 -420
  234. package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
  235. package/dist/bigconsole/pages/PipelineViewPage.js +416 -384
  236. package/dist/bigconsole/pages/PipelineViewPage.js.map +1 -1
  237. package/dist/bigconsole/pages/PipelinesPage.js +260 -309
  238. package/dist/bigconsole/pages/PipelinesPage.js.map +1 -1
  239. package/dist/bigconsole/pages/SettingsPage.js +177 -172
  240. package/dist/bigconsole/pages/SettingsPage.js.map +1 -1
  241. package/dist/bigconsole/pages/WidgetDemoPage.js +278 -142
  242. package/dist/bigconsole/pages/WidgetDemoPage.js.map +1 -1
  243. package/dist/bigconsole/pages/WorkflowViewPage.js +382 -366
  244. package/dist/bigconsole/pages/WorkflowViewPage.js.map +1 -1
  245. package/dist/bigconsole/pages/WorkflowsPage.js +202 -316
  246. package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
  247. package/dist/bigconsole/renderers/adapters/AdaptiveCardRenderer.js +111 -109
  248. package/dist/bigconsole/renderers/adapters/AdaptiveCardRenderer.js.map +1 -1
  249. package/dist/bigconsole/renderers/adapters/BlockKitRenderer.js +127 -126
  250. package/dist/bigconsole/renderers/adapters/BlockKitRenderer.js.map +1 -1
  251. package/dist/bigconsole/renderers/adapters/CustomRenderer.js +103 -103
  252. package/dist/bigconsole/renderers/adapters/CustomRenderer.js.map +1 -1
  253. package/package.json +2 -1
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardCanvas.js","names":[],"sources":["../../../../src/bigconsole/components/dashboard/DashboardCanvas.tsx"],"sourcesContent":["/**\n * DashboardCanvas Component\n *\n * Main canvas for dashboard with grid layout and widget rendering.\n * Phase 2: Added GlobalFiltersBar and PageTabsManager integration.\n * Phase 3: Added WidgetPalette sidebar for drag-and-drop widget creation.\n */\n\nimport { type FC, memo, useRef, useState, useCallback, useEffect, useMemo } from 'react';\nimport type { Layout } from 'react-grid-layout';\nimport type { Widget, WidgetType } from '../../types';\nimport { useDashboardStore, useWidgetStore } from '../../store';\nimport { useWidgetOperations } from '../../hooks/useWidgetOperations';\nimport { useInstalledWidgets } from '../../hooks/useInstalledWidgets';\nimport { useWidgetCatalog } from '../../hooks/useWidgetCatalog';\nimport { useDashboardImageExport } from '../../hooks/useDashboardImageExport';\nimport { useBigConsole } from '../../context';\nimport { DashboardGrid } from './DashboardGrid';\nimport { DashboardToolbar } from './DashboardToolbar';\nimport { GlobalFiltersBar } from './GlobalFiltersBar';\nimport { LiveBoardBanner } from './LiveBoardBanner';\nimport { TemplateSetupBanner } from './TemplateSetupBanner';\nimport { PageTabsManager, type DashboardPageTab } from './PageTabsManager';\nimport { ShareDialog } from './ShareDialog';\nimport { WidgetPalette } from './WidgetPalette';\nimport { WidgetInspector } from '../builder';\nimport { getWidgetDefinition, type WidgetDefinition } from '../widgets/WidgetRegistry';\n// Phase 2: Cross-filtering context\nimport { CrossFilterProvider } from '../../contexts';\n// Smart widget positioning\nimport { findNextAvailablePosition, calculatePositionFromDrop } from '../../utils/widgetPositioning';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface DashboardCanvasProps {\n /** Dashboard ID */\n dashboardId: string;\n /** Page ID (for loading widgets) */\n pageId?: string;\n /** Dashboard title */\n title?: string;\n /** Callback to paste widget */\n onPaste?: () => void;\n /** Callback when dashboard is saved */\n onSave?: () => void;\n /** Whether save is in progress */\n isSaving?: boolean;\n /** Callback to export dashboard */\n onExport?: () => void;\n onPublishTemplate?: () => void;\n /** Dashboard pages for PageTabsManager */\n pages?: DashboardPageTab[];\n /** Active page ID */\n activePageId?: string;\n /** Callback when page changes */\n onPageChange?: (pageId: string) => void;\n /** Callback when pages are reordered */\n onPagesReorder?: (pages: DashboardPageTab[]) => void;\n /** Callback when page is added */\n onPageAdd?: () => void;\n /** Callback when page is renamed */\n onPageRename?: (pageId: string, newName: string) => void;\n /** Callback when page is duplicated */\n onPageDuplicate?: (pageId: string) => void;\n /** Callback when page is deleted */\n onPageDelete?: (pageId: string) => void;\n /** Whether to show global filters bar */\n showFilters?: boolean;\n /** Whether to show page tabs */\n showPageTabs?: boolean;\n /** Whether to enable cross-filtering (widget clicks update filters) */\n enableCrossFilter?: boolean;\n}\n\ninterface WidgetPlacement {\n position: { x: number; y: number; width: number; height: number };\n definition?: WidgetDefinition | null;\n}\n\ninterface PaletteDropData {\n type: WidgetType;\n name?: string;\n category?: WidgetDefinition['category'];\n defaultConfig?: Record<string, unknown>;\n defaultSize?: WidgetDefinition['defaultSize'];\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const DashboardCanvas: FC<DashboardCanvasProps> = memo(function DashboardCanvas({\n dashboardId,\n pageId,\n title,\n onPaste,\n onSave,\n isSaving = false,\n onExport,\n onPublishTemplate,\n pages = [],\n activePageId,\n onPageChange,\n onPagesReorder,\n onPageAdd,\n onPageRename,\n onPageDuplicate,\n onPageDelete,\n showFilters = true,\n showPageTabs = true,\n enableCrossFilter = true,\n}) {\n const containerRef = useRef<HTMLDivElement>(null);\n // Inner board element (the grid surface) — rasterized for PNG/PDF board-pack export.\n const boardRef = useRef<HTMLDivElement>(null);\n const [containerWidth, setContainerWidth] = useState(1200);\n const [isShareDialogOpen, setIsShareDialogOpen] = useState(false);\n const [widgetCreateError, setWidgetCreateError] = useState<string | null>(null);\n const [isDraggingWidget, setIsDraggingWidget] = useState(false);\n const [dragWidgetType, setDragWidgetType] = useState<WidgetType | null>(null);\n\n // Store state\n const isEditMode = useDashboardStore((state) => state.viewMode === 'edit');\n\n // Fetch installed widgets only in edit mode — the palette and add-widget dialog\n // are not usable in read-only view, so skip the request for viewer-only sessions.\n const { workspaceId, apiGatewayUrl, authToken } = useBigConsole();\n const { installedWidgets, loading: installedWidgetsLoading } = useInstalledWidgets({\n workspaceId,\n apiGatewayUrl,\n authToken,\n enabled: isEditMode,\n });\n // Built-in widget catalog from the backend (getWidgetTypes); falls back to the\n // bundled registry while loading or if the supergraph hasn't adopted it yet.\n const { definitions: widgetCatalog } = useWidgetCatalog({\n workspaceId,\n apiGatewayUrl,\n authToken,\n enabled: isEditMode,\n });\n const zoomLevel = useDashboardStore((state) => state.zoomLevel);\n const sidebarCollapsed = useDashboardStore((state) => state.sidebarCollapsed);\n const toggleSidebar = useDashboardStore((state) => state.toggleSidebar);\n const isPaletteOpen = !sidebarCollapsed;\n const setGlobalFilterValues = useDashboardStore((state) => state.setGlobalFilterValues);\n\n // Handle filter changes - update store for widget access\n const handleFilterChange = useCallback(\n (filterValues: Record<string, unknown>) => {\n // Update global filter values in dashboard store\n setGlobalFilterValues(filterValues);\n\n // Widgets can now access filter values via useGlobalFilterValues() hook\n // When backend supports filter parameters, widget queries will include these values\n },\n [setGlobalFilterValues]\n );\n\n // Widget operations hook (connects to backend) - skipFetch since parent page fetches\n const { createWidget: createWidgetApi } = useWidgetOperations(pageId, dashboardId, { skipFetch: true });\n\n const widgetsMap = useWidgetStore((state) => state.widgets);\n // Filter widgets to only show widgets for the current page\n const widgetsArray = useMemo(() => {\n const allWidgets = Array.from(widgetsMap.values());\n if (!pageId) return allWidgets;\n return allWidgets.filter((widget) => widget.pageId === pageId);\n }, [widgetsMap, pageId]);\n const selectedWidgetId = useWidgetStore((state) => state.selectedWidgetId);\n const selectWidget = useWidgetStore((state) => state.selectWidget);\n const addWidgetToStore = useWidgetStore((state) => state.addWidget);\n const updateWidgetPosition = useWidgetStore((state) => state.updateWidgetPosition);\n const configPanelOpen = useWidgetStore((state) => state.configPanelOpen);\n const closeConfigPanel = useWidgetStore((state) => state.closeConfigPanel);\n\n // Keep react-grid-layout's explicit width in sync with the actual canvas.\n // A ResizeObserver is required because opening the docked inspector or widget\n // palette resizes this element without resizing the browser window.\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const updateWidth = () => {\n setContainerWidth(container.offsetWidth);\n };\n\n updateWidth();\n\n if (typeof ResizeObserver !== 'undefined') {\n const observer = new ResizeObserver(updateWidth);\n observer.observe(container);\n return () => observer.disconnect();\n }\n\n window.addEventListener('resize', updateWidth);\n return () => window.removeEventListener('resize', updateWidth);\n }, []);\n\n // Handle layout change\n const handleLayoutChange = useCallback(\n (layout: Layout[]) => {\n layout.forEach((item) => {\n updateWidgetPosition(item.i, {\n x: item.x,\n y: item.y,\n width: item.w,\n height: item.h,\n });\n });\n },\n [updateWidgetPosition]\n );\n\n // Handle widget select\n const handleWidgetSelect = useCallback(\n (widgetId: string) => {\n selectWidget(widgetId);\n },\n [selectWidget]\n );\n\n // Create with defaults, select the result, then configure it in the inspector.\n const handleAddWidget = useCallback(\n async (widgetData: Partial<Widget>, placement?: WidgetPlacement) => {\n setWidgetCreateError(null);\n const definition = placement?.definition || (widgetData.type ? getWidgetDefinition(widgetData.type) : null);\n const widgetSize = {\n width: definition?.defaultSize?.width ?? 4,\n height: definition?.defaultSize?.height ?? 4,\n };\n\n let position: { x: number; y: number; width: number; height: number };\n if (placement?.position) {\n position = placement.position;\n } else {\n // Use smart placement algorithm - horizontal first, then next row\n const { x, y } = findNextAvailablePosition(widgetsArray, widgetSize, { cols: 12 });\n position = {\n x,\n y,\n width: widgetSize.width,\n height: widgetSize.height,\n };\n }\n\n // Preserve legacy binding fields when creating from imported/default data.\n const extendedData = widgetData as Partial<Widget> & { dataSinkId?: string; parserId?: string };\n\n // Try to create via API first\n if (pageId) {\n const widget = await createWidgetApi({\n pageId,\n dashboardId,\n type: widgetData.type!,\n title: widgetData.title || 'Untitled Widget',\n description: widgetData.description,\n // v2.0: Renderer and template support\n renderer: widgetData.renderer,\n template: widgetData.template,\n config: widgetData.config || {},\n position,\n refreshInterval: widgetData.refreshInterval ?? undefined,\n // v2.0: Data source fields (DataSink → Parser → Widget)\n dataSinkId: extendedData.dataSinkId,\n parserId: extendedData.parserId,\n });\n\n if (widget) {\n selectWidget(widget.id);\n return;\n }\n\n setWidgetCreateError('Could not create the widget. Check the connection and try again.');\n return;\n }\n\n // Fallback to local store if API fails or no pageId\n const newWidget: Widget = {\n id: crypto.randomUUID(),\n dashboardId,\n pageId: pageId || 'local',\n type: widgetData.type!,\n title: widgetData.title || 'Untitled Widget',\n description: widgetData.description,\n // v2.0: Renderer and template support\n renderer: widgetData.renderer,\n template: widgetData.template,\n refreshInterval: widgetData.refreshInterval,\n config: widgetData.config || {},\n position,\n positionX: position.x,\n positionY: position.y,\n positionWidth: position.width,\n positionHeight: position.height,\n // v2.0: Data source fields (DataSink → Parser → Widget)\n dataSinkId: extendedData.dataSinkId,\n parserId: extendedData.parserId,\n translations: [],\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n\n addWidgetToStore(newWidget);\n selectWidget(newWidget.id);\n },\n [dashboardId, pageId, createWidgetApi, addWidgetToStore, selectWidget, widgetsArray]\n );\n\n // Handle drag start from palette\n const handlePaletteDragStart = useCallback((type: WidgetType) => {\n setIsDraggingWidget(true);\n setDragWidgetType(type);\n }, []);\n\n // Handle drag end from palette\n const handlePaletteDragEnd = useCallback(() => {\n setIsDraggingWidget(false);\n setDragWidgetType(null);\n }, []);\n\n // Handle drop on canvas - create immediately with defaults.\n const handleCanvasDrop = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n setIsDraggingWidget(false);\n setDragWidgetType(null);\n\n try {\n const data = e.dataTransfer.getData('application/json');\n if (!data) return;\n\n const parsedData: unknown = JSON.parse(data);\n if (!parsedData || typeof parsedData !== 'object' || !('type' in parsedData)) return;\n const widgetData = parsedData as PaletteDropData;\n const definition = getWidgetDefinition(widgetData.type);\n\n // If the dropped data includes defaultConfig (from WidgetPalette drag serialization),\n // reconstruct a full WidgetDefinition so installed/store widget identity is preserved.\n let droppedDefinition: WidgetDefinition | null = null;\n if (widgetData.defaultConfig && widgetData.category) {\n droppedDefinition = {\n ...definition,\n name: widgetData.name || definition.name,\n category: widgetData.category,\n defaultConfig: widgetData.defaultConfig,\n defaultSize: widgetData.defaultSize || definition.defaultSize,\n };\n }\n\n // Calculate drop position relative to canvas\n const canvasRect = containerRef.current?.getBoundingClientRect();\n if (!canvasRect) return;\n\n // Use utility to calculate grid position from drop coordinates\n const widgetSize = {\n width: definition.defaultSize.width,\n height: definition.defaultSize.height,\n };\n\n const { x: gridX, y: gridY } = calculatePositionFromDrop(\n e.clientX,\n e.clientY,\n canvasRect,\n containerWidth,\n widgetSize,\n { cols: 12 }\n );\n\n const position = {\n x: gridX,\n y: gridY,\n width: widgetSize.width,\n height: widgetSize.height,\n };\n\n void handleAddWidget(\n {\n type: widgetData.type,\n title: widgetData.name || definition.name,\n config: widgetData.defaultConfig || definition.defaultConfig,\n },\n { position, definition: droppedDefinition }\n );\n } catch (error) {\n console.error('Failed to handle widget drop:', error);\n }\n },\n [containerWidth, handleAddWidget]\n );\n\n // Handle drag over to allow drop\n const handleCanvasDragOver = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.dataTransfer.dropEffect = 'copy';\n }, []);\n\n // Handle widget select from palette (quick add without drag)\n const handlePaletteWidgetSelect = useCallback(\n (type: WidgetType, paletteDefinition?: WidgetDefinition) => {\n const definition = paletteDefinition || getWidgetDefinition(type);\n handleAddWidget({\n type,\n title: definition.name,\n config: definition.defaultConfig,\n });\n },\n [handleAddWidget]\n );\n\n // Toggle palette\n const togglePalette = useCallback(() => {\n toggleSidebar();\n }, [toggleSidebar]);\n\n const openWidgetPalette = useCallback(() => {\n if (sidebarCollapsed) toggleSidebar();\n window.requestAnimationFrame(() => {\n document.querySelector<HTMLInputElement>('input[placeholder=\"Search widgets...\"]')?.focus();\n });\n }, [sidebarCollapsed, toggleSidebar]);\n\n // Board-pack export (PNG + PDF) — rasterizes the inner board element.\n const {\n exportPNG,\n exportPDF,\n isExporting: isExportingImage,\n } = useDashboardImageExport({ containerRef: boardRef, name: title || 'dashboard' });\n const handleExportImage = useCallback(() => {\n void exportPNG();\n }, [exportPNG]);\n const handleExportPdf = useCallback(() => {\n void exportPDF();\n }, [exportPDF]);\n\n return (\n <div className=\"flex flex-col h-full min-w-0 overflow-hidden\">\n {/* Toolbar */}\n <DashboardToolbar\n dashboardId={dashboardId}\n title={title}\n onAddWidget={openWidgetPalette}\n onTogglePalette={togglePalette}\n isPaletteOpen={isPaletteOpen}\n onPaste={onPaste}\n onSave={onSave}\n isSaving={isSaving}\n onExport={onExport}\n onPublishTemplate={onPublishTemplate}\n onExportImage={handleExportImage}\n onExportPdf={handleExportPdf}\n isExportingImage={isExportingImage}\n onShare={() => setIsShareDialogOpen(true)}\n />\n\n {widgetCreateError && (\n <div\n className=\"flex items-center justify-between gap-3 border-b border-status-error-border bg-status-error-bg px-4 py-2 text-sm text-status-error-text\"\n role=\"alert\"\n >\n <span>{widgetCreateError}</span>\n <button\n type=\"button\"\n className=\"font-medium underline underline-offset-2\"\n onClick={() => setWidgetCreateError(null)}\n >\n Dismiss\n </button>\n </div>\n )}\n\n {/* Live wall-board freshness banner — renders only when the page has\n auto-refreshing widgets (e.g. the Live Bed Board) and not in edit mode. */}\n <TemplateSetupBanner widgets={widgetsArray} isEditMode={isEditMode} />\n <LiveBoardBanner widgets={widgetsArray} isEditMode={isEditMode} />\n\n {/* Global Filters Bar */}\n {showFilters && <GlobalFiltersBar dashboardId={dashboardId} onFilterChange={handleFilterChange} collapsible />}\n\n {/* Page Tabs - always show in edit mode so user can add first page */}\n {showPageTabs && (isEditMode || pages.length > 0) && (\n <PageTabsManager\n pages={pages}\n activePageId={activePageId || pages[0]?.id}\n editable={isEditMode}\n onPageSelect={onPageChange || (() => {})}\n onPagesReorder={\n onPagesReorder\n ? (pageIds) => {\n // Convert string[] to DashboardPageTab[] for the callback\n const reorderedPages = pageIds.map((id) => pages.find((p) => p.id === id)!).filter(Boolean);\n onPagesReorder(reorderedPages);\n }\n : undefined\n }\n onPageCreate={onPageAdd}\n onPageRename={onPageRename}\n onPageDuplicate={onPageDuplicate}\n onPageDelete={onPageDelete}\n />\n )}\n\n {/* Main content area with palette and canvas.\n When the properties inspector is open we reserve equal space on the\n right so the (fixed, non-modal) panel docks beside the canvas instead\n of overlaying the selected widget. */}\n <div\n className=\"flex flex-1 min-w-0 overflow-hidden\"\n style={{\n marginRight: configPanelOpen ? 'var(--bc-inspector-width, 420px)' : undefined,\n transition: 'margin-right 0.2s ease',\n }}\n >\n {/* Widget Palette Sidebar */}\n {isEditMode && (\n <WidgetPalette\n isOpen={isPaletteOpen}\n onClose={togglePalette}\n onWidgetSelect={handlePaletteWidgetSelect}\n onDragStart={handlePaletteDragStart}\n onDragEnd={handlePaletteDragEnd}\n installedWidgets={installedWidgets}\n installedWidgetsLoading={installedWidgetsLoading}\n definitions={widgetCatalog}\n />\n )}\n\n {/* Canvas area */}\n <div\n ref={containerRef}\n className=\"flex-1 min-w-0 overflow-auto bg-bg-sunken\"\n onDrop={handleCanvasDrop}\n onDragOver={handleCanvasDragOver}\n onClick={() => {\n if (isEditMode) {\n selectWidget(null);\n }\n }}\n style={{\n position: 'relative',\n border: isDraggingWidget ? '2px dashed var(--color-action-primary-bg)' : 'none',\n backgroundColor: isDraggingWidget ? 'var(--color-bg-hover)' : undefined,\n transition: 'border-color 0.2s, background-color 0.2s',\n }}\n >\n {/* Drop zone indicator */}\n {isDraggingWidget && (\n <div\n style={{\n position: 'absolute',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n padding: 'var(--space-pagePadding)',\n backgroundColor: 'var(--color-bg-surface)',\n borderRadius: 'var(--radius-card)',\n boxShadow: 'var(--shadow-elevation-2)',\n textAlign: 'center',\n pointerEvents: 'none',\n zIndex: 100,\n }}\n >\n <p style={{ fontSize: 'var(--font-size-body-md)', color: 'var(--color-text-primary)', margin: 0 }}>\n Drop to add <strong>{dragWidgetType}</strong> widget\n </p>\n </div>\n )}\n\n <div\n ref={boardRef}\n className=\"min-h-full origin-top-left transition-transform\"\n style={{\n transform: `scale(${zoomLevel / 100})`,\n width: `${100 / (zoomLevel / 100)}%`,\n }}\n >\n {widgetsArray.length > 0 ? (\n <CrossFilterProvider\n enabled={enableCrossFilter}\n onCrossFilter={(_filters) => {\n // Cross-filter applied - widget queries can access filter values\n }}\n >\n <DashboardGrid\n widgets={widgetsArray}\n isEditMode={isEditMode}\n width={containerWidth}\n onLayoutChange={handleLayoutChange}\n onWidgetSelect={handleWidgetSelect}\n selectedWidgetId={selectedWidgetId}\n />\n </CrossFilterProvider>\n ) : (\n <div className=\"flex flex-col items-center justify-center min-h-[400px] p-8\">\n <div className=\"w-16 h-16 mb-4 flex items-center justify-center rounded-full bg-bg-surface\">\n <svg className=\"w-8 h-8 text-text-secondary\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z\"\n />\n </svg>\n </div>\n <h3 className=\"text-lg font-medium text-text-primary mb-2\">No widgets yet</h3>\n <p className=\"text-sm text-text-secondary mb-4 text-center max-w-[300px]\">\n Add widgets to build your dashboard. Click the &quot;Add Widget&quot; button to get started.\n </p>\n {isEditMode && (\n <button\n type=\"button\"\n onClick={openWidgetPalette}\n className=\"\n inline-flex items-center gap-2\n px-4 py-2\n text-sm font-medium\n text-action-primary-fg\n bg-action-primary-bg\n hover:bg-action-primary-bgHover\n rounded-md\n transition-colors\n \"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 4v16m8-8H4\" />\n </svg>\n Add Widget\n </button>\n )}\n </div>\n )}\n </div>\n </div>\n </div>\n\n {/* Properties Panel */}\n <WidgetInspector isOpen={configPanelOpen} onClose={closeConfigPanel} />\n\n {/* Share Dialog */}\n <ShareDialog\n dashboardId={dashboardId}\n dashboardName={title || 'Dashboard'}\n isOpen={isShareDialogOpen}\n onClose={() => setIsShareDialogOpen(false)}\n />\n </div>\n );\n});\n\nexport default DashboardCanvas;\n"],"mappings":"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"}
1
+ {"version":3,"file":"DashboardCanvas.js","names":[],"sources":["../../../../src/bigconsole/components/dashboard/DashboardCanvas.tsx"],"sourcesContent":["/**\n * DashboardCanvas Component\n *\n * Main canvas for dashboard with grid layout and widget rendering.\n * Phase 2: Added GlobalFiltersBar and PageTabsManager integration.\n * Phase 3: Added WidgetPalette sidebar for drag-and-drop widget creation.\n */\n\nimport { type FC, memo, useRef, useState, useCallback, useEffect, useMemo } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Plus } from 'lucide-react';\nimport type { Layout } from 'react-grid-layout';\nimport type { Widget, WidgetType } from '../../types';\nimport { useDashboardStore, useWidgetStore } from '../../store';\nimport { useWidgetOperations } from '../../hooks/useWidgetOperations';\nimport { useInstalledWidgets } from '../../hooks/useInstalledWidgets';\nimport { useWidgetCatalog } from '../../hooks/useWidgetCatalog';\nimport { useDashboardImageExport } from '../../hooks/useDashboardImageExport';\nimport { useBigConsole } from '../../context';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Section } from '../common';\nimport { DashboardGrid } from './DashboardGrid';\nimport { DashboardToolbar } from './DashboardToolbar';\nimport { GlobalFiltersBar } from './GlobalFiltersBar';\nimport { LiveBoardBanner } from './LiveBoardBanner';\nimport { TemplateSetupBanner } from './TemplateSetupBanner';\nimport { PageTabsManager, type DashboardPageTab } from './PageTabsManager';\nimport { ShareDialog } from './ShareDialog';\nimport { WidgetPalette } from './WidgetPalette';\nimport { WidgetInspector } from '../builder';\nimport { getWidgetDefinition, type WidgetDefinition } from '../widgets/WidgetRegistry';\n// Phase 2: Cross-filtering context\nimport { CrossFilterProvider } from '../../contexts';\n// Smart widget positioning\nimport { findNextAvailablePosition, calculatePositionFromDrop } from '../../utils/widgetPositioning';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface DashboardCanvasProps {\n /** Dashboard ID */\n dashboardId: string;\n /** Page ID (for loading widgets) */\n pageId?: string;\n /** Dashboard title */\n title?: string;\n /** Callback to paste widget */\n onPaste?: () => void;\n /** Callback when dashboard is saved */\n onSave?: () => void;\n /** Whether save is in progress */\n isSaving?: boolean;\n /** Callback to export dashboard */\n onExport?: () => void;\n onPublishTemplate?: () => void;\n /** Dashboard pages for PageTabsManager */\n pages?: DashboardPageTab[];\n /** Active page ID */\n activePageId?: string;\n /** Callback when page changes */\n onPageChange?: (pageId: string) => void;\n /** Callback when pages are reordered */\n onPagesReorder?: (pages: DashboardPageTab[]) => void;\n /** Callback when page is added */\n onPageAdd?: () => void;\n /** Callback when page is renamed */\n onPageRename?: (pageId: string, newName: string) => void;\n /** Callback when page is duplicated */\n onPageDuplicate?: (pageId: string) => void;\n /** Callback when page is deleted */\n onPageDelete?: (pageId: string) => void;\n /** Whether to show global filters bar */\n showFilters?: boolean;\n /** Whether to show page tabs */\n showPageTabs?: boolean;\n /** Whether to enable cross-filtering (widget clicks update filters) */\n enableCrossFilter?: boolean;\n}\n\ninterface WidgetPlacement {\n position: { x: number; y: number; width: number; height: number };\n definition?: WidgetDefinition | null;\n}\n\ninterface PaletteDropData {\n type: WidgetType;\n name?: string;\n category?: WidgetDefinition['category'];\n defaultConfig?: Record<string, unknown>;\n defaultSize?: WidgetDefinition['defaultSize'];\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const DashboardCanvas: FC<DashboardCanvasProps> = memo(function DashboardCanvas({\n dashboardId,\n pageId,\n title,\n onPaste,\n onSave,\n isSaving = false,\n onExport,\n onPublishTemplate,\n pages = [],\n activePageId,\n onPageChange,\n onPagesReorder,\n onPageAdd,\n onPageRename,\n onPageDuplicate,\n onPageDelete,\n showFilters = true,\n showPageTabs = true,\n enableCrossFilter = true,\n}) {\n const { t } = useI18n();\n const containerRef = useRef<HTMLDivElement>(null);\n // Inner board element (the grid surface) — rasterized for PNG/PDF board-pack export.\n const boardRef = useRef<HTMLDivElement>(null);\n const [containerWidth, setContainerWidth] = useState(1200);\n const [isShareDialogOpen, setIsShareDialogOpen] = useState(false);\n const [widgetCreateError, setWidgetCreateError] = useState<string | null>(null);\n const [isDraggingWidget, setIsDraggingWidget] = useState(false);\n const [dragWidgetType, setDragWidgetType] = useState<WidgetType | null>(null);\n\n // Store state\n const isEditMode = useDashboardStore((state) => state.viewMode === 'edit');\n\n // Fetch installed widgets only in edit mode — the palette and add-widget dialog\n // are not usable in read-only view, so skip the request for viewer-only sessions.\n const { workspaceId, apiGatewayUrl, authToken } = useBigConsole();\n const { installedWidgets, loading: installedWidgetsLoading } = useInstalledWidgets({\n workspaceId,\n apiGatewayUrl,\n authToken,\n enabled: isEditMode,\n });\n // Built-in widget catalog from the backend (getWidgetTypes); falls back to the\n // bundled registry while loading or if the supergraph hasn't adopted it yet.\n const { definitions: widgetCatalog } = useWidgetCatalog({\n workspaceId,\n apiGatewayUrl,\n authToken,\n enabled: isEditMode,\n });\n const zoomLevel = useDashboardStore((state) => state.zoomLevel);\n const sidebarCollapsed = useDashboardStore((state) => state.sidebarCollapsed);\n const toggleSidebar = useDashboardStore((state) => state.toggleSidebar);\n const isPaletteOpen = !sidebarCollapsed;\n const setGlobalFilterValues = useDashboardStore((state) => state.setGlobalFilterValues);\n\n // Handle filter changes - update store for widget access\n const handleFilterChange = useCallback(\n (filterValues: Record<string, unknown>) => {\n // Update global filter values in dashboard store\n setGlobalFilterValues(filterValues);\n\n // Widgets can now access filter values via useGlobalFilterValues() hook\n // When backend supports filter parameters, widget queries will include these values\n },\n [setGlobalFilterValues]\n );\n\n // Widget operations hook (connects to backend) - skipFetch since parent page fetches\n const { createWidget: createWidgetApi } = useWidgetOperations(pageId, dashboardId, { skipFetch: true });\n\n const widgetsMap = useWidgetStore((state) => state.widgets);\n // Filter widgets to only show widgets for the current page\n const widgetsArray = useMemo(() => {\n const allWidgets = Array.from(widgetsMap.values());\n if (!pageId) return allWidgets;\n return allWidgets.filter((widget) => widget.pageId === pageId);\n }, [widgetsMap, pageId]);\n const selectedWidgetId = useWidgetStore((state) => state.selectedWidgetId);\n const selectWidget = useWidgetStore((state) => state.selectWidget);\n const addWidgetToStore = useWidgetStore((state) => state.addWidget);\n const updateWidgetPosition = useWidgetStore((state) => state.updateWidgetPosition);\n const configPanelOpen = useWidgetStore((state) => state.configPanelOpen);\n const closeConfigPanel = useWidgetStore((state) => state.closeConfigPanel);\n\n // Keep react-grid-layout's explicit width in sync with the actual canvas.\n // A ResizeObserver is required because opening the docked inspector or widget\n // palette resizes this element without resizing the browser window.\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const updateWidth = () => {\n setContainerWidth(container.offsetWidth);\n };\n\n updateWidth();\n\n if (typeof ResizeObserver !== 'undefined') {\n const observer = new ResizeObserver(updateWidth);\n observer.observe(container);\n return () => observer.disconnect();\n }\n\n window.addEventListener('resize', updateWidth);\n return () => window.removeEventListener('resize', updateWidth);\n }, []);\n\n // Handle layout change\n const handleLayoutChange = useCallback(\n (layout: Layout[]) => {\n layout.forEach((item) => {\n updateWidgetPosition(item.i, {\n x: item.x,\n y: item.y,\n width: item.w,\n height: item.h,\n });\n });\n },\n [updateWidgetPosition]\n );\n\n // Handle widget select\n const handleWidgetSelect = useCallback(\n (widgetId: string) => {\n selectWidget(widgetId);\n },\n [selectWidget]\n );\n\n // Create with defaults, select the result, then configure it in the inspector.\n const handleAddWidget = useCallback(\n async (widgetData: Partial<Widget>, placement?: WidgetPlacement) => {\n setWidgetCreateError(null);\n const definition = placement?.definition || (widgetData.type ? getWidgetDefinition(widgetData.type) : null);\n const widgetSize = {\n width: definition?.defaultSize?.width ?? 4,\n height: definition?.defaultSize?.height ?? 4,\n };\n\n let position: { x: number; y: number; width: number; height: number };\n if (placement?.position) {\n position = placement.position;\n } else {\n // Use smart placement algorithm - horizontal first, then next row\n const { x, y } = findNextAvailablePosition(widgetsArray, widgetSize, { cols: 12 });\n position = {\n x,\n y,\n width: widgetSize.width,\n height: widgetSize.height,\n };\n }\n\n // Preserve legacy binding fields when creating from imported/default data.\n const extendedData = widgetData as Partial<Widget> & { dataSinkId?: string; parserId?: string };\n\n // Try to create via API first\n if (pageId) {\n const widget = await createWidgetApi({\n pageId,\n dashboardId,\n type: widgetData.type!,\n title: widgetData.title || t('bigconsole.dashboards.canvas.untitledWidget', 'Untitled Widget'),\n description: widgetData.description,\n // v2.0: Renderer and template support\n renderer: widgetData.renderer,\n template: widgetData.template,\n config: widgetData.config || {},\n position,\n refreshInterval: widgetData.refreshInterval ?? undefined,\n // v2.0: Data source fields (DataSink → Parser → Widget)\n dataSinkId: extendedData.dataSinkId,\n parserId: extendedData.parserId,\n });\n\n if (widget) {\n selectWidget(widget.id);\n return;\n }\n\n setWidgetCreateError(\n t(\n 'bigconsole.dashboards.canvas.widgetCreateError',\n 'Could not create the widget. Check the connection and try again.'\n )\n );\n return;\n }\n\n // Fallback to local store if API fails or no pageId\n const newWidget: Widget = {\n id: crypto.randomUUID(),\n dashboardId,\n pageId: pageId || 'local',\n type: widgetData.type!,\n title: widgetData.title || t('bigconsole.dashboards.canvas.untitledWidget', 'Untitled Widget'),\n description: widgetData.description,\n // v2.0: Renderer and template support\n renderer: widgetData.renderer,\n template: widgetData.template,\n refreshInterval: widgetData.refreshInterval,\n config: widgetData.config || {},\n position,\n positionX: position.x,\n positionY: position.y,\n positionWidth: position.width,\n positionHeight: position.height,\n // v2.0: Data source fields (DataSink → Parser → Widget)\n dataSinkId: extendedData.dataSinkId,\n parserId: extendedData.parserId,\n translations: [],\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n\n addWidgetToStore(newWidget);\n selectWidget(newWidget.id);\n },\n [dashboardId, pageId, createWidgetApi, addWidgetToStore, selectWidget, widgetsArray, t]\n );\n\n // Handle drag start from palette\n const handlePaletteDragStart = useCallback((type: WidgetType) => {\n setIsDraggingWidget(true);\n setDragWidgetType(type);\n }, []);\n\n // Handle drag end from palette\n const handlePaletteDragEnd = useCallback(() => {\n setIsDraggingWidget(false);\n setDragWidgetType(null);\n }, []);\n\n // Handle drop on canvas - create immediately with defaults.\n const handleCanvasDrop = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n setIsDraggingWidget(false);\n setDragWidgetType(null);\n\n try {\n const data = e.dataTransfer.getData('application/json');\n if (!data) return;\n\n const parsedData: unknown = JSON.parse(data);\n if (!parsedData || typeof parsedData !== 'object' || !('type' in parsedData)) return;\n const widgetData = parsedData as PaletteDropData;\n const definition = getWidgetDefinition(widgetData.type);\n\n // If the dropped data includes defaultConfig (from WidgetPalette drag serialization),\n // reconstruct a full WidgetDefinition so installed/store widget identity is preserved.\n let droppedDefinition: WidgetDefinition | null = null;\n if (widgetData.defaultConfig && widgetData.category) {\n droppedDefinition = {\n ...definition,\n name: widgetData.name || definition.name,\n category: widgetData.category,\n defaultConfig: widgetData.defaultConfig,\n defaultSize: widgetData.defaultSize || definition.defaultSize,\n };\n }\n\n // Calculate drop position relative to canvas\n const canvasRect = containerRef.current?.getBoundingClientRect();\n if (!canvasRect) return;\n\n // Use utility to calculate grid position from drop coordinates\n const widgetSize = {\n width: definition.defaultSize.width,\n height: definition.defaultSize.height,\n };\n\n const { x: gridX, y: gridY } = calculatePositionFromDrop(\n e.clientX,\n e.clientY,\n canvasRect,\n containerWidth,\n widgetSize,\n { cols: 12 }\n );\n\n const position = {\n x: gridX,\n y: gridY,\n width: widgetSize.width,\n height: widgetSize.height,\n };\n\n void handleAddWidget(\n {\n type: widgetData.type,\n title: widgetData.name || definition.name,\n config: widgetData.defaultConfig || definition.defaultConfig,\n },\n { position, definition: droppedDefinition }\n );\n } catch (error) {\n console.error('Failed to handle widget drop:', error);\n }\n },\n [containerWidth, handleAddWidget]\n );\n\n // Handle drag over to allow drop\n const handleCanvasDragOver = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.dataTransfer.dropEffect = 'copy';\n }, []);\n\n // Handle widget select from palette (quick add without drag)\n const handlePaletteWidgetSelect = useCallback(\n (type: WidgetType, paletteDefinition?: WidgetDefinition) => {\n const definition = paletteDefinition || getWidgetDefinition(type);\n handleAddWidget({\n type,\n title: definition.name,\n config: definition.defaultConfig,\n });\n },\n [handleAddWidget]\n );\n\n // Toggle palette\n const togglePalette = useCallback(() => {\n toggleSidebar();\n }, [toggleSidebar]);\n\n const openWidgetPalette = useCallback(() => {\n if (sidebarCollapsed) toggleSidebar();\n window.requestAnimationFrame(() => {\n const searchPlaceholder = t('bigconsole.dashboards.widgetPalette.searchPlaceholder', 'Search widgets...');\n document.querySelector<HTMLInputElement>(`input[placeholder=\"${searchPlaceholder}\"]`)?.focus();\n });\n }, [sidebarCollapsed, toggleSidebar, t]);\n\n // Board-pack export (PNG + PDF) — rasterizes the inner board element.\n const {\n exportPNG,\n exportPDF,\n isExporting: isExportingImage,\n } = useDashboardImageExport({ containerRef: boardRef, name: title || 'dashboard' });\n const handleExportImage = useCallback(() => {\n void exportPNG();\n }, [exportPNG]);\n const handleExportPdf = useCallback(() => {\n void exportPDF();\n }, [exportPDF]);\n\n return (\n <div className=\"flex flex-col h-full min-w-0 overflow-hidden\">\n {/* Toolbar */}\n <DashboardToolbar\n dashboardId={dashboardId}\n title={title}\n onAddWidget={openWidgetPalette}\n onTogglePalette={togglePalette}\n isPaletteOpen={isPaletteOpen}\n onPaste={onPaste}\n onSave={onSave}\n isSaving={isSaving}\n onExport={onExport}\n onPublishTemplate={onPublishTemplate}\n onExportImage={handleExportImage}\n onExportPdf={handleExportPdf}\n isExportingImage={isExportingImage}\n onShare={() => setIsShareDialogOpen(true)}\n />\n\n {widgetCreateError && (\n <div role=\"alert\" className=\"mx-card-padding mt-control-gap flex-shrink-0\">\n {/* The section title has no catalog key — BOFF-6004 translated only the\n message and the Dismiss action — so it stays a literal until a key\n lands in src/translations/en.ts. */}\n <Section\n tone=\"danger\"\n padding=\"compact\"\n headingLevel={3}\n data-testid=\"widget-create-error\"\n title=\"Widget not created\"\n description={widgetCreateError}\n actions={\n <Button variant=\"outline\" size=\"sm\" onClick={() => setWidgetCreateError(null)}>\n {t('bigconsole.dashboards.canvas.dismiss', 'Dismiss')}\n </Button>\n }\n />\n </div>\n )}\n\n {/* Live wall-board freshness banner — renders only when the page has\n auto-refreshing widgets (e.g. the Live Bed Board) and not in edit mode. */}\n <TemplateSetupBanner widgets={widgetsArray} isEditMode={isEditMode} />\n <LiveBoardBanner widgets={widgetsArray} isEditMode={isEditMode} />\n\n {/* Global Filters Bar */}\n {showFilters && <GlobalFiltersBar dashboardId={dashboardId} onFilterChange={handleFilterChange} collapsible />}\n\n {/* Page Tabs - always show in edit mode so user can add first page */}\n {showPageTabs && (isEditMode || pages.length > 0) && (\n <PageTabsManager\n pages={pages}\n activePageId={activePageId || pages[0]?.id}\n editable={isEditMode}\n onPageSelect={onPageChange || (() => {})}\n onPagesReorder={\n onPagesReorder\n ? (pageIds) => {\n // Convert string[] to DashboardPageTab[] for the callback\n const reorderedPages = pageIds.map((id) => pages.find((p) => p.id === id)!).filter(Boolean);\n onPagesReorder(reorderedPages);\n }\n : undefined\n }\n onPageCreate={onPageAdd}\n onPageRename={onPageRename}\n onPageDuplicate={onPageDuplicate}\n onPageDelete={onPageDelete}\n />\n )}\n\n {/* Main content area with palette and canvas.\n When the properties inspector is open we reserve equal space on the\n right so the (fixed, non-modal) panel docks beside the canvas instead\n of overlaying the selected widget. */}\n <div\n data-testid=\"dashboard-canvas-panes\"\n className={`flex flex-1 min-w-0 overflow-hidden ${\n // Only reserve the inspector gutter where there is room for both. The\n // panel is `min(420px, 100vw)` wide, so below `lg` it overlays the\n // board instead — reserving 420px there left the canvas a sliver.\n configPanelOpen ? 'lg:mr-[var(--bc-inspector-width,420px)]' : ''\n }`}\n >\n {/* Widget Palette Sidebar */}\n {isEditMode && (\n <WidgetPalette\n isOpen={isPaletteOpen}\n onClose={togglePalette}\n onWidgetSelect={handlePaletteWidgetSelect}\n onDragStart={handlePaletteDragStart}\n onDragEnd={handlePaletteDragEnd}\n installedWidgets={installedWidgets}\n installedWidgetsLoading={installedWidgetsLoading}\n definitions={widgetCatalog}\n />\n )}\n\n {/*\n The board. This is the one `primary` region on the route — everything\n above it is bare chrome or a compact status strip, so the widgets are\n what the eye lands on. It keeps the recessed canvas surface on purpose:\n the widgets are the raised cards, the board is the well they sit in.\n The drop border is always 2px (transparent when idle) so drag-over\n highlights without nudging the whole board.\n */}\n <div\n ref={containerRef}\n role=\"region\"\n aria-label=\"Dashboard board\"\n data-section-emphasis=\"primary\"\n data-testid=\"dashboard-board\"\n className=\"relative min-w-0 flex-1 overflow-auto border-2 border-transparent bg-bg-sunken motion-safe:transition-[border-color,background-color]\"\n onDrop={handleCanvasDrop}\n onDragOver={handleCanvasDragOver}\n onClick={() => {\n if (isEditMode) {\n selectWidget(null);\n }\n }}\n style={\n isDraggingWidget\n ? {\n borderStyle: 'dashed',\n borderColor: 'var(--color-action-primary-bg)',\n backgroundColor: 'var(--color-bg-accentSubtle)',\n }\n : undefined\n }\n >\n {/* Drop zone indicator */}\n {isDraggingWidget && (\n <div\n style={{\n position: 'absolute',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n padding: 'var(--space-pagePadding)',\n backgroundColor: 'var(--color-bg-surface)',\n borderRadius: 'var(--radius-card)',\n boxShadow: 'var(--shadow-elevation-2)',\n textAlign: 'center',\n pointerEvents: 'none',\n zIndex: 100,\n }}\n >\n <p style={{ fontSize: 'var(--font-size-body-md)', color: 'var(--color-text-primary)', margin: 0 }}>\n {t('bigconsole.dashboards.canvas.dropToAddBefore', 'Drop to add')} <strong>{dragWidgetType}</strong>{' '}\n {t('bigconsole.dashboards.canvas.dropToAddAfter', 'widget')}\n </p>\n </div>\n )}\n\n <div\n ref={boardRef}\n className=\"min-h-full origin-top-left transition-transform\"\n style={{\n transform: `scale(${zoomLevel / 100})`,\n width: `${100 / (zoomLevel / 100)}%`,\n }}\n >\n {widgetsArray.length > 0 ? (\n <CrossFilterProvider\n enabled={enableCrossFilter}\n onCrossFilter={(_filters) => {\n // Cross-filter applied - widget queries can access filter values\n }}\n >\n <DashboardGrid\n widgets={widgetsArray}\n isEditMode={isEditMode}\n width={containerWidth}\n onLayoutChange={handleLayoutChange}\n onWidgetSelect={handleWidgetSelect}\n selectedWidgetId={selectedWidgetId}\n />\n </CrossFilterProvider>\n ) : (\n <div className=\"flex min-h-[min(400px,60vh)] items-center justify-center p-card-padding\">\n <Section\n headingLevel={3}\n className=\"w-full max-w-md\"\n data-testid=\"dashboard-empty-board\"\n headerClassName=\"mb-form-gap\"\n title={t('bigconsole.dashboards.canvas.noWidgetsTitle', 'No widgets yet')}\n description={t(\n 'bigconsole.dashboards.canvas.noWidgetsDescription',\n 'Add widgets to build your dashboard. Click the \"Add Widget\" button to get started.'\n )}\n >\n {isEditMode && (\n <Button onClick={openWidgetPalette}>\n <Plus className=\"size-4\" />\n {t('bigconsole.dashboards.canvas.addWidget', 'Add Widget')}\n </Button>\n )}\n </Section>\n </div>\n )}\n </div>\n </div>\n </div>\n\n {/* Properties Panel */}\n <WidgetInspector isOpen={configPanelOpen} onClose={closeConfigPanel} />\n\n {/* Share Dialog */}\n <ShareDialog\n dashboardId={dashboardId}\n dashboardName={title || t('bigconsole.dashboards.canvas.dashboardFallbackName', 'Dashboard')}\n isOpen={isShareDialogOpen}\n onClose={() => setIsShareDialogOpen(false)}\n />\n </div>\n );\n});\n\nexport default DashboardCanvas;\n"],"mappings":"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"}
@@ -23,13 +23,13 @@ function c(e) {
23
23
  };
24
24
  }
25
25
  var l = r(function({ widgets: r, isEditMode: l, width: u, cols: d = 12, rowHeight: f = 60, onLayoutChange: p, onWidgetSelect: m, selectedWidgetId: h }) {
26
- let g = e(), { emitEvent: _ } = t({}), v = a(() => r.map(c), [r]), y = i((e, t) => {
26
+ let g = e(), { emitEvent: _ } = t({}), v = a(() => r.map(c), [r]), y = u < 480 ? 8 : 16, b = i((e, t) => {
27
27
  l && m && m(e);
28
- }, [m, l]), b = i((e) => {
28
+ }, [m, l]), x = i((e) => {
29
29
  p && l && p(e);
30
- }, [p, l]), x = i((e) => {
30
+ }, [p, l]), S = i((e) => {
31
31
  p && l && p(e);
32
- }, [p, l]), S = i(async (e, t) => {
32
+ }, [p, l]), C = i(async (e, t) => {
33
33
  let n = typeof e?.name == "string" ? e.name : "unknown", r = `widget:${n.toLowerCase().replace(/\s+/g, "_")}:clicked`, i = await _({
34
34
  widgetId: t.widgetId,
35
35
  actionName: n,
@@ -50,32 +50,26 @@ var l = r(function({ widgets: r, isEditMode: l, width: u, cols: d = 12, rowHeigh
50
50
  cols: d,
51
51
  rowHeight: f,
52
52
  width: u,
53
- margin: [16, 16],
54
- containerPadding: [16, 16],
53
+ margin: [y, y],
54
+ containerPadding: [y, y],
55
55
  isDraggable: l,
56
56
  isResizable: l,
57
57
  draggableHandle: ".widget-drag-handle",
58
- onDragStop: b,
59
- onResizeStop: x,
58
+ onDragStop: x,
59
+ onResizeStop: S,
60
60
  useCSSTransforms: !0,
61
61
  compactType: null,
62
62
  preventCollision: !1,
63
63
  children: r.map((e) => {
64
64
  let t = e.actions || [];
65
65
  return /* @__PURE__ */ o("div", {
66
- onClick: (t) => y(e.id, t),
67
- className: `
68
- overflow-visible h-full
69
- ${h === e.id && l ? "ring-2 ring-action-primary-bg rounded-lg" : ""}
70
- `,
71
- style: {
72
- display: "flex",
73
- flexDirection: "column"
74
- },
66
+ onClick: (t) => b(e.id, t),
67
+ "data-selected": h === e.id && l ? "true" : void 0,
68
+ className: `flex h-full min-w-0 flex-col overflow-visible ${h === e.id && l ? "rounded-card ring-2 ring-action-primary-bg ring-offset-2 ring-offset-bg-sunken" : ""}`,
75
69
  children: /* @__PURE__ */ o(n, {
76
70
  widget: e,
77
71
  actions: t,
78
- onAction: S,
72
+ onAction: C,
79
73
  filterValues: g
80
74
  })
81
75
  }, e.id);
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardGrid.js","names":[],"sources":["../../../../src/bigconsole/components/dashboard/DashboardGrid.tsx"],"sourcesContent":["/**\n * DashboardGrid Component\n *\n * Grid layout for widgets using react-grid-layout.\n * v2.0: Added widget event emission support\n */\n\nimport { type FC, memo, useMemo, useCallback } from 'react';\nimport GridLayout, { type Layout } from 'react-grid-layout';\nimport type { Widget } from '../../types';\nimport { WidgetWrapper } from '../widgets/WidgetWrapper';\nimport { useWidgetEvents } from '../../hooks/useWidgetEvents';\nimport { useGlobalFilterValues } from '../../store';\nimport type { WidgetAction, ActionContext, ActionResult } from '../../renderers/types/renderer';\n\n// Import react-grid-layout styles\nimport 'react-grid-layout/css/styles.css';\nimport 'react-resizable/css/styles.css';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface DashboardGridProps {\n /** Widgets to display */\n widgets: Widget[];\n /** Whether in edit mode */\n isEditMode: boolean;\n /** Container width */\n width: number;\n /** Number of columns */\n cols?: number;\n /** Row height in pixels */\n rowHeight?: number;\n /** Callback when layout changes */\n onLayoutChange?: (layout: Layout[]) => void;\n /** Callback when widget is selected */\n onWidgetSelect?: (widgetId: string) => void;\n /** Currently selected widget ID */\n selectedWidgetId?: string | null;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction widgetToLayout(widget: Widget): Layout {\n const x = widget.position?.x ?? widget.positionX ?? 0;\n const y = widget.position?.y ?? widget.positionY ?? 0;\n const w = widget.position?.width ?? widget.positionWidth ?? 4;\n const h = widget.position?.height ?? widget.positionHeight ?? 4;\n\n return {\n i: widget.id,\n x,\n y,\n w,\n h,\n minW: 1,\n minH: 1,\n maxW: 12,\n maxH: 12,\n };\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const DashboardGrid: FC<DashboardGridProps> = memo(function DashboardGrid({\n widgets,\n isEditMode,\n width,\n cols = 12,\n rowHeight = 60,\n onLayoutChange,\n onWidgetSelect,\n selectedWidgetId,\n}) {\n // Phase 2: Get global filter values\n const globalFilterValues = useGlobalFilterValues();\n\n // v2.0: Widget event emission hook\n const { emitEvent } = useWidgetEvents({});\n\n // Build layout from widgets\n const layout = useMemo(() => widgets.map(widgetToLayout), [widgets]);\n\n // Handle widget click - only select in edit mode\n const handleWidgetClick = useCallback(\n (widgetId: string, _event: React.MouseEvent) => {\n // Only select widget in edit mode\n // In view mode, let WidgetWrapper handle drilldown\n if (isEditMode && onWidgetSelect) {\n onWidgetSelect(widgetId);\n }\n },\n [onWidgetSelect, isEditMode]\n );\n\n // Handle drag/resize stop - only update when user finishes interaction\n const handleDragStop = useCallback(\n (layout: Layout[]) => {\n if (onLayoutChange && isEditMode) {\n onLayoutChange(layout);\n }\n },\n [onLayoutChange, isEditMode]\n );\n\n const handleResizeStop = useCallback(\n (layout: Layout[]) => {\n if (onLayoutChange && isEditMode) {\n onLayoutChange(layout);\n }\n },\n [onLayoutChange, isEditMode]\n );\n\n // v2.0: Handle widget action - emit event to backend\n const handleWidgetAction = useCallback(\n async (action: WidgetAction, context: ActionContext): Promise<ActionResult | void> => {\n // Safety check: ensure action.name is a string\n const actionName = typeof action?.name === 'string' ? action.name : 'unknown';\n\n // Build event name from action name (e.g., \"Edit Profile\" -> \"widget:edit_profile:clicked\")\n const eventName = `widget:${actionName.toLowerCase().replace(/\\s+/g, '_')}:clicked`;\n\n // Emit event to backend (triggers webhook if configured)\n const eventLog = await emitEvent({\n widgetId: context.widgetId,\n actionName: actionName,\n event: eventName,\n payload: context.data || {},\n });\n\n if (eventLog) {\n return {\n success: eventLog.status !== 'FAILED',\n message: eventLog.status === 'DELIVERED' ? 'Action completed' : `Event status: ${eventLog.status}`,\n };\n }\n\n return { success: false, message: 'Failed to emit event' };\n },\n [emitEvent]\n );\n\n return (\n <GridLayout\n className=\"dashboard-grid\"\n layout={layout}\n cols={cols}\n rowHeight={rowHeight}\n width={width}\n margin={[16, 16]}\n containerPadding={[16, 16]}\n isDraggable={isEditMode}\n isResizable={isEditMode}\n draggableHandle=\".widget-drag-handle\"\n onDragStop={handleDragStop}\n onResizeStop={handleResizeStop}\n useCSSTransforms\n compactType={null}\n preventCollision={false}\n >\n {widgets.map((widget) => {\n // v2.0: Extract actions from widget\n const widgetWithActions = widget as Widget & { actions?: WidgetAction[] };\n const widgetActions = widgetWithActions.actions || [];\n\n return (\n <div\n key={widget.id}\n onClick={(e) => handleWidgetClick(widget.id, e)}\n className={`\n overflow-visible h-full\n ${selectedWidgetId === widget.id && isEditMode ? 'ring-2 ring-action-primary-bg rounded-lg' : ''}\n `}\n style={{ display: 'flex', flexDirection: 'column' }}\n >\n <WidgetWrapper\n widget={widget}\n actions={widgetActions}\n onAction={handleWidgetAction}\n filterValues={globalFilterValues}\n />\n </div>\n );\n })}\n </GridLayout>\n );\n});\n\nexport default DashboardGrid;\n"],"mappings":";;;;;;;;;;AA8CA,SAAS,EAAe,GAAwB;CAC9C,IAAM,IAAI,EAAO,UAAU,KAAK,EAAO,aAAa,GAC9C,IAAI,EAAO,UAAU,KAAK,EAAO,aAAa,GAC9C,IAAI,EAAO,UAAU,SAAS,EAAO,iBAAiB,GACtD,IAAI,EAAO,UAAU,UAAU,EAAO,kBAAkB;AAE9D,QAAO;EACL,GAAG,EAAO;EACV;EACA;EACA;EACA;EACA,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACP;;AAOH,IAAa,IAAwC,EAAK,SAAuB,EAC/E,YACA,eACA,UACA,UAAO,IACP,eAAY,IACZ,mBACA,mBACA,uBACC;CAED,IAAM,IAAqB,GAAuB,EAG5C,EAAE,iBAAc,EAAgB,EAAE,CAAC,EAGnC,IAAS,QAAc,EAAQ,IAAI,EAAe,EAAE,CAAC,EAAQ,CAAC,EAG9D,IAAoB,GACvB,GAAkB,MAA6B;AAG9C,EAAI,KAAc,KAChB,EAAe,EAAS;IAG5B,CAAC,GAAgB,EAAW,CAC7B,EAGK,IAAiB,GACpB,MAAqB;AACpB,EAAI,KAAkB,KACpB,EAAe,EAAO;IAG1B,CAAC,GAAgB,EAAW,CAC7B,EAEK,IAAmB,GACtB,MAAqB;AACpB,EAAI,KAAkB,KACpB,EAAe,EAAO;IAG1B,CAAC,GAAgB,EAAW,CAC7B,EAGK,IAAqB,EACzB,OAAO,GAAsB,MAAyD;EAEpF,IAAM,IAAa,OAAO,GAAQ,QAAS,WAAW,EAAO,OAAO,WAG9D,IAAY,UAAU,EAAW,aAAa,CAAC,QAAQ,QAAQ,IAAI,CAAC,WAGpE,IAAW,MAAM,EAAU;GAC/B,UAAU,EAAQ;GACN;GACZ,OAAO;GACP,SAAS,EAAQ,QAAQ,EAAE;GAC5B,CAAC;AASF,SAPI,IACK;GACL,SAAS,EAAS,WAAW;GAC7B,SAAS,EAAS,WAAW,cAAc,qBAAqB,iBAAiB,EAAS;GAC3F,GAGI;GAAE,SAAS;GAAO,SAAS;GAAwB;IAE5D,CAAC,EAAU,CACZ;AAED,QACE,kBAAC,GAAD;EACE,WAAU;EACF;EACF;EACK;EACJ;EACP,QAAQ,CAAC,IAAI,GAAG;EAChB,kBAAkB,CAAC,IAAI,GAAG;EAC1B,aAAa;EACb,aAAa;EACb,iBAAgB;EAChB,YAAY;EACZ,cAAc;EACd,kBAAA;EACA,aAAa;EACb,kBAAkB;YAEjB,EAAQ,KAAK,MAAW;GAGvB,IAAM,IADoB,EACc,WAAW,EAAE;AAErD,UACE,kBAAC,OAAD;IAEE,UAAU,MAAM,EAAkB,EAAO,IAAI,EAAE;IAC/C,WAAW;;kBAEL,MAAqB,EAAO,MAAM,IAAa,6CAA6C,GAAG;;IAErG,OAAO;KAAE,SAAS;KAAQ,eAAe;KAAU;cAEnD,kBAAC,GAAD;KACU;KACR,SAAS;KACT,UAAU;KACV,cAAc;KACd,CAAA;IACE,EAdC,EAAO,GAcR;IAER;EACS,CAAA;EAEf"}
1
+ {"version":3,"file":"DashboardGrid.js","names":[],"sources":["../../../../src/bigconsole/components/dashboard/DashboardGrid.tsx"],"sourcesContent":["/**\n * DashboardGrid Component\n *\n * Grid layout for widgets using react-grid-layout.\n * v2.0: Added widget event emission support\n */\n\nimport { type FC, memo, useMemo, useCallback } from 'react';\nimport GridLayout, { type Layout } from 'react-grid-layout';\nimport type { Widget } from '../../types';\nimport { WidgetWrapper } from '../widgets/WidgetWrapper';\nimport { useWidgetEvents } from '../../hooks/useWidgetEvents';\nimport { useGlobalFilterValues } from '../../store';\nimport type { WidgetAction, ActionContext, ActionResult } from '../../renderers/types/renderer';\n\n// Import react-grid-layout styles\nimport 'react-grid-layout/css/styles.css';\nimport 'react-resizable/css/styles.css';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface DashboardGridProps {\n /** Widgets to display */\n widgets: Widget[];\n /** Whether in edit mode */\n isEditMode: boolean;\n /** Container width */\n width: number;\n /** Number of columns */\n cols?: number;\n /** Row height in pixels */\n rowHeight?: number;\n /** Callback when layout changes */\n onLayoutChange?: (layout: Layout[]) => void;\n /** Callback when widget is selected */\n onWidgetSelect?: (widgetId: string) => void;\n /** Currently selected widget ID */\n selectedWidgetId?: string | null;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction widgetToLayout(widget: Widget): Layout {\n const x = widget.position?.x ?? widget.positionX ?? 0;\n const y = widget.position?.y ?? widget.positionY ?? 0;\n const w = widget.position?.width ?? widget.positionWidth ?? 4;\n const h = widget.position?.height ?? widget.positionHeight ?? 4;\n\n return {\n i: widget.id,\n x,\n y,\n w,\n h,\n minW: 1,\n minH: 1,\n maxW: 12,\n maxH: 12,\n };\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const DashboardGrid: FC<DashboardGridProps> = memo(function DashboardGrid({\n widgets,\n isEditMode,\n width,\n cols = 12,\n rowHeight = 60,\n onLayoutChange,\n onWidgetSelect,\n selectedWidgetId,\n}) {\n // Phase 2: Get global filter values\n const globalFilterValues = useGlobalFilterValues();\n\n // v2.0: Widget event emission hook\n const { emitEvent } = useWidgetEvents({});\n\n // Build layout from widgets\n const layout = useMemo(() => widgets.map(widgetToLayout), [widgets]);\n\n // Gutters are a fixed 16px in react-grid-layout, which on a 390px canvas spends\n // ~32px of the board on padding alone. Shrink them on narrow canvases — this is\n // purely visual and never touches the stored x/y/w/h.\n const gutter = width < 480 ? 8 : 16;\n\n // Handle widget click - only select in edit mode\n const handleWidgetClick = useCallback(\n (widgetId: string, _event: React.MouseEvent) => {\n // Only select widget in edit mode\n // In view mode, let WidgetWrapper handle drilldown\n if (isEditMode && onWidgetSelect) {\n onWidgetSelect(widgetId);\n }\n },\n [onWidgetSelect, isEditMode]\n );\n\n // Handle drag/resize stop - only update when user finishes interaction\n const handleDragStop = useCallback(\n (layout: Layout[]) => {\n if (onLayoutChange && isEditMode) {\n onLayoutChange(layout);\n }\n },\n [onLayoutChange, isEditMode]\n );\n\n const handleResizeStop = useCallback(\n (layout: Layout[]) => {\n if (onLayoutChange && isEditMode) {\n onLayoutChange(layout);\n }\n },\n [onLayoutChange, isEditMode]\n );\n\n // v2.0: Handle widget action - emit event to backend\n const handleWidgetAction = useCallback(\n async (action: WidgetAction, context: ActionContext): Promise<ActionResult | void> => {\n // Safety check: ensure action.name is a string\n const actionName = typeof action?.name === 'string' ? action.name : 'unknown';\n\n // Build event name from action name (e.g., \"Edit Profile\" -> \"widget:edit_profile:clicked\")\n const eventName = `widget:${actionName.toLowerCase().replace(/\\s+/g, '_')}:clicked`;\n\n // Emit event to backend (triggers webhook if configured)\n const eventLog = await emitEvent({\n widgetId: context.widgetId,\n actionName: actionName,\n event: eventName,\n payload: context.data || {},\n });\n\n if (eventLog) {\n return {\n success: eventLog.status !== 'FAILED',\n message: eventLog.status === 'DELIVERED' ? 'Action completed' : `Event status: ${eventLog.status}`,\n };\n }\n\n return { success: false, message: 'Failed to emit event' };\n },\n [emitEvent]\n );\n\n return (\n <GridLayout\n className=\"dashboard-grid\"\n layout={layout}\n cols={cols}\n rowHeight={rowHeight}\n width={width}\n margin={[gutter, gutter]}\n containerPadding={[gutter, gutter]}\n isDraggable={isEditMode}\n isResizable={isEditMode}\n draggableHandle=\".widget-drag-handle\"\n onDragStop={handleDragStop}\n onResizeStop={handleResizeStop}\n useCSSTransforms\n compactType={null}\n preventCollision={false}\n >\n {widgets.map((widget) => {\n // v2.0: Extract actions from widget\n const widgetWithActions = widget as Widget & { actions?: WidgetAction[] };\n const widgetActions = widgetWithActions.actions || [];\n\n return (\n <div\n key={widget.id}\n onClick={(e) => handleWidgetClick(widget.id, e)}\n data-selected={selectedWidgetId === widget.id && isEditMode ? 'true' : undefined}\n className={`flex h-full min-w-0 flex-col overflow-visible ${\n selectedWidgetId === widget.id && isEditMode\n ? 'rounded-card ring-2 ring-action-primary-bg ring-offset-2 ring-offset-bg-sunken'\n : ''\n }`}\n >\n <WidgetWrapper\n widget={widget}\n actions={widgetActions}\n onAction={handleWidgetAction}\n filterValues={globalFilterValues}\n />\n </div>\n );\n })}\n </GridLayout>\n );\n});\n\nexport default DashboardGrid;\n"],"mappings":";;;;;;;;;;AA8CA,SAAS,EAAe,GAAwB;CAC9C,IAAM,IAAI,EAAO,UAAU,KAAK,EAAO,aAAa,GAC9C,IAAI,EAAO,UAAU,KAAK,EAAO,aAAa,GAC9C,IAAI,EAAO,UAAU,SAAS,EAAO,iBAAiB,GACtD,IAAI,EAAO,UAAU,UAAU,EAAO,kBAAkB;AAE9D,QAAO;EACL,GAAG,EAAO;EACV;EACA;EACA;EACA;EACA,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACP;;AAOH,IAAa,IAAwC,EAAK,SAAuB,EAC/E,YACA,eACA,UACA,UAAO,IACP,eAAY,IACZ,mBACA,mBACA,uBACC;CAED,IAAM,IAAqB,GAAuB,EAG5C,EAAE,iBAAc,EAAgB,EAAE,CAAC,EAGnC,IAAS,QAAc,EAAQ,IAAI,EAAe,EAAE,CAAC,EAAQ,CAAC,EAK9D,IAAS,IAAQ,MAAM,IAAI,IAG3B,IAAoB,GACvB,GAAkB,MAA6B;AAG9C,EAAI,KAAc,KAChB,EAAe,EAAS;IAG5B,CAAC,GAAgB,EAAW,CAC7B,EAGK,IAAiB,GACpB,MAAqB;AACpB,EAAI,KAAkB,KACpB,EAAe,EAAO;IAG1B,CAAC,GAAgB,EAAW,CAC7B,EAEK,IAAmB,GACtB,MAAqB;AACpB,EAAI,KAAkB,KACpB,EAAe,EAAO;IAG1B,CAAC,GAAgB,EAAW,CAC7B,EAGK,IAAqB,EACzB,OAAO,GAAsB,MAAyD;EAEpF,IAAM,IAAa,OAAO,GAAQ,QAAS,WAAW,EAAO,OAAO,WAG9D,IAAY,UAAU,EAAW,aAAa,CAAC,QAAQ,QAAQ,IAAI,CAAC,WAGpE,IAAW,MAAM,EAAU;GAC/B,UAAU,EAAQ;GACN;GACZ,OAAO;GACP,SAAS,EAAQ,QAAQ,EAAE;GAC5B,CAAC;AASF,SAPI,IACK;GACL,SAAS,EAAS,WAAW;GAC7B,SAAS,EAAS,WAAW,cAAc,qBAAqB,iBAAiB,EAAS;GAC3F,GAGI;GAAE,SAAS;GAAO,SAAS;GAAwB;IAE5D,CAAC,EAAU,CACZ;AAED,QACE,kBAAC,GAAD;EACE,WAAU;EACF;EACF;EACK;EACJ;EACP,QAAQ,CAAC,GAAQ,EAAO;EACxB,kBAAkB,CAAC,GAAQ,EAAO;EAClC,aAAa;EACb,aAAa;EACb,iBAAgB;EAChB,YAAY;EACZ,cAAc;EACd,kBAAA;EACA,aAAa;EACb,kBAAkB;YAEjB,EAAQ,KAAK,MAAW;GAGvB,IAAM,IADoB,EACc,WAAW,EAAE;AAErD,UACE,kBAAC,OAAD;IAEE,UAAU,MAAM,EAAkB,EAAO,IAAI,EAAE;IAC/C,iBAAe,MAAqB,EAAO,MAAM,IAAa,SAAS,KAAA;IACvE,WAAW,iDACT,MAAqB,EAAO,MAAM,IAC9B,mFACA;cAGN,kBAAC,GAAD;KACU;KACR,SAAS;KACT,UAAU;KACV,cAAc;KACd,CAAA;IACE,EAfC,EAAO,GAeR;IAER;EACS,CAAA;EAEf"}
@@ -1,179 +1,187 @@
1
1
  import { useWidgetStore as e } from "../../store/widgetStore.js";
2
2
  import { useDashboardStore as t } from "../../store/dashboardStore.js";
3
3
  import "../../store/index.js";
4
- import { BIGCONSOLE_PERMISSIONS as n } from "../../../constants/permissions.js";
5
- import r from "./SavedViewsDropdown/SavedViewsDropdown.js";
4
+ import { Section as n } from "../common/Section.js";
5
+ import "../common/index.js";
6
+ import { BIGCONSOLE_PERMISSIONS as r } from "../../../constants/permissions.js";
7
+ import i from "./SavedViewsDropdown/SavedViewsDropdown.js";
6
8
  import "./SavedViewsDropdown/index.js";
7
- import { memo as i, useCallback as a } from "react";
8
- import { PermissionButton as o } from "@burdenoff/fe-libs/shared/components";
9
- import { usePermissions as s } from "@burdenoff/fe-libs/shared/providers/shell";
10
- import { Clipboard as c, Download as l, Eye as u, FileText as d, Image as f, Minus as p, PanelLeft as m, PanelLeftClose as h, Pencil as g, Plus as _, RotateCcw as v, Save as y, Share2 as b, Store as x } from "lucide-react";
11
- import { Button as S, Spinner as C, Tooltip as w, TooltipContent as T, TooltipProvider as E, TooltipTrigger as D } from "@burdenoff/fe-libs/ui";
12
- import { Fragment as O, jsx as k, jsxs as A } from "react/jsx-runtime";
9
+ import { memo as a, useCallback as o } from "react";
10
+ import { PermissionButton as s } from "@burdenoff/fe-libs/shared/components";
11
+ import { usePermissions as c } from "@burdenoff/fe-libs/shared/providers/shell";
12
+ import { Clipboard as l, Download as u, Eye as d, FileText as f, Image as p, Minus as m, PanelLeft as h, PanelLeftClose as g, Pencil as _, Plus as v, RotateCcw as y, Save as b, Share2 as x, Store as S } from "lucide-react";
13
+ import { useI18n as C } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
14
+ import { Button as w, Spinner as T, Tooltip as E, TooltipContent as D, TooltipProvider as O, TooltipTrigger as k } from "@burdenoff/fe-libs/ui";
15
+ import { Fragment as A, jsx as j, jsxs as M } from "react/jsx-runtime";
13
16
  //#region src/bigconsole/components/dashboard/DashboardToolbar.tsx
14
- var j = i(function({ dashboardId: i, title: j, onAddWidget: M, onTogglePalette: N, isPaletteOpen: P = !1, onPaste: F, onSave: I, isSaving: L = !1, onExport: R, onPublishTemplate: z, onExportImage: B, onExportPdf: V, isExportingImage: H = !1, onShare: U }) {
15
- let { hasPermission: W } = s(), G = t((e) => e.viewMode === "edit"), K = t((e) => e.toggleViewMode), q = t((e) => e.zoomLevel), J = t((e) => e.setZoomLevel), Y = !!e((e) => e.clipboardWidgetId), X = a(() => {
16
- Y && F && F();
17
- }, [Y, F]);
18
- return /* @__PURE__ */ k(E, { children: /* @__PURE__ */ A("div", {
19
- className: "flex flex-wrap items-center justify-between gap-x-4 gap-y-2 px-4 py-2 bg-bg-surface border-b",
17
+ var N = a(function({ dashboardId: a, title: N, onAddWidget: P, onTogglePalette: F, isPaletteOpen: I = !1, onPaste: L, onSave: R, isSaving: z = !1, onExport: B, onPublishTemplate: V, onExportImage: H, onExportPdf: U, isExportingImage: W = !1, onShare: G }) {
18
+ let { hasPermission: K } = c(), { t: q } = C(), J = t((e) => e.viewMode === "edit"), Y = t((e) => e.toggleViewMode), X = t((e) => e.zoomLevel), Z = t((e) => e.setZoomLevel), Q = !!e((e) => e.clipboardWidgetId), $ = o(() => {
19
+ Q && L && L();
20
+ }, [Q, L]);
21
+ return /* @__PURE__ */ j(O, { children: /* @__PURE__ */ M(n, {
22
+ emphasis: "bare",
23
+ padding: "none",
24
+ "aria-label": N ? `Board toolbar — ${N}` : "Board toolbar",
25
+ "data-testid": "dashboard-toolbar",
26
+ className: "flex-shrink-0 border-b border-[var(--color-border-subtle)] bg-bg-surface px-4 py-2",
27
+ bodyClassName: "flex flex-wrap items-center justify-between gap-x-4 gap-y-2",
20
28
  children: [
21
- /* @__PURE__ */ A("div", {
29
+ /* @__PURE__ */ j("div", {
22
30
  className: "flex min-w-0 items-center gap-4",
23
- children: [j && /* @__PURE__ */ k("h1", {
24
- className: "min-w-0 truncate text-lg font-semibold",
25
- title: j,
26
- children: j
27
- }), i && /* @__PURE__ */ k(r, { dashboardId: i })]
31
+ children: a && /* @__PURE__ */ j(i, { dashboardId: a })
28
32
  }),
29
- /* @__PURE__ */ A("div", {
30
- className: "flex flex-shrink-0 items-center gap-1",
33
+ /* @__PURE__ */ M("div", {
34
+ role: "group",
35
+ "aria-label": "Zoom",
36
+ className: "flex min-w-0 items-center gap-1 border-l border-[var(--color-border-subtle)] pl-4",
31
37
  children: [
32
- /* @__PURE__ */ A(w, { children: [/* @__PURE__ */ k(D, {
38
+ /* @__PURE__ */ M(E, { children: [/* @__PURE__ */ j(k, {
33
39
  asChild: !0,
34
- children: /* @__PURE__ */ k(S, {
40
+ children: /* @__PURE__ */ j(w, {
35
41
  variant: "ghost",
36
42
  size: "icon-sm",
37
- onClick: () => J(Math.max(50, q - 10)),
38
- disabled: q <= 50,
39
- children: /* @__PURE__ */ k(p, { className: "size-4" })
43
+ onClick: () => Z(Math.max(50, X - 10)),
44
+ disabled: X <= 50,
45
+ children: /* @__PURE__ */ j(m, { className: "size-4" })
40
46
  })
41
- }), /* @__PURE__ */ k(T, { children: "Zoom out" })] }),
42
- /* @__PURE__ */ A("span", {
47
+ }), /* @__PURE__ */ j(D, { children: q("bigconsole.dashboards.toolbar.zoomOut", "Zoom out") })] }),
48
+ /* @__PURE__ */ M("span", {
43
49
  className: "text-sm text-text-secondary w-12 text-center",
44
- children: [q, "%"]
50
+ children: [X, "%"]
45
51
  }),
46
- /* @__PURE__ */ A(w, { children: [/* @__PURE__ */ k(D, {
52
+ /* @__PURE__ */ M(E, { children: [/* @__PURE__ */ j(k, {
47
53
  asChild: !0,
48
- children: /* @__PURE__ */ k(S, {
54
+ children: /* @__PURE__ */ j(w, {
49
55
  variant: "ghost",
50
56
  size: "icon-sm",
51
- onClick: () => J(Math.min(200, q + 10)),
52
- disabled: q >= 200,
53
- children: /* @__PURE__ */ k(_, { className: "size-4" })
57
+ onClick: () => Z(Math.min(200, X + 10)),
58
+ disabled: X >= 200,
59
+ children: /* @__PURE__ */ j(v, { className: "size-4" })
54
60
  })
55
- }), /* @__PURE__ */ k(T, { children: "Zoom in" })] }),
56
- /* @__PURE__ */ A(w, { children: [/* @__PURE__ */ k(D, {
61
+ }), /* @__PURE__ */ j(D, { children: q("bigconsole.dashboards.toolbar.zoomIn", "Zoom in") })] }),
62
+ /* @__PURE__ */ M(E, { children: [/* @__PURE__ */ j(k, {
57
63
  asChild: !0,
58
- children: /* @__PURE__ */ A(S, {
64
+ children: /* @__PURE__ */ M(w, {
59
65
  variant: "ghost",
60
66
  size: "sm",
61
- onClick: () => J(100),
62
- children: [/* @__PURE__ */ k(v, { className: "size-3.5 mr-1" }), "Reset"]
67
+ onClick: () => Z(100),
68
+ children: [/* @__PURE__ */ j(y, { className: "size-3.5 mr-1" }), q("bigconsole.dashboards.toolbar.reset", "Reset")]
63
69
  })
64
- }), /* @__PURE__ */ k(T, { children: "Reset zoom to 100%" })] })
70
+ }), /* @__PURE__ */ j(D, { children: q("bigconsole.dashboards.toolbar.resetZoomTooltip", "Reset zoom to 100%") })] })
65
71
  ]
66
72
  }),
67
- /* @__PURE__ */ A("div", {
68
- className: "flex flex-wrap items-center justify-end gap-2",
73
+ /* @__PURE__ */ M("div", {
74
+ role: "group",
75
+ "aria-label": "Board actions",
76
+ className: "flex min-w-0 flex-wrap items-center justify-end gap-2 border-l border-[var(--color-border-subtle)] pl-4",
69
77
  children: [
70
- G && /* @__PURE__ */ A(O, { children: [
71
- N && /* @__PURE__ */ A(w, { children: [/* @__PURE__ */ k(D, {
78
+ J && /* @__PURE__ */ M(A, { children: [
79
+ F && /* @__PURE__ */ M(E, { children: [/* @__PURE__ */ j(k, {
72
80
  asChild: !0,
73
- children: /* @__PURE__ */ A(S, {
74
- variant: P ? "secondary" : "outline",
81
+ children: /* @__PURE__ */ M(w, {
82
+ variant: I ? "secondary" : "outline",
75
83
  size: "sm",
76
- onClick: N,
77
- children: [k(P ? h : m, { className: "size-4" }), "Widgets"]
84
+ onClick: F,
85
+ children: [j(I ? g : h, { className: "size-4" }), q("bigconsole.dashboards.toolbar.widgets", "Widgets")]
78
86
  })
79
- }), /* @__PURE__ */ k(T, { children: P ? "Hide widget palette" : "Show widget palette for drag & drop" })] }),
80
- /* @__PURE__ */ A(w, { children: [/* @__PURE__ */ k(D, {
87
+ }), /* @__PURE__ */ j(D, { children: I ? q("bigconsole.dashboards.toolbar.hidePalette", "Hide widget palette") : q("bigconsole.dashboards.toolbar.showPalette", "Show widget palette for drag & drop") })] }),
88
+ /* @__PURE__ */ M(E, { children: [/* @__PURE__ */ j(k, {
81
89
  asChild: !0,
82
- children: /* @__PURE__ */ A(S, {
90
+ children: /* @__PURE__ */ M(w, {
83
91
  variant: "ghost",
84
92
  size: "sm",
85
- onClick: X,
86
- disabled: !Y,
87
- children: [/* @__PURE__ */ k(c, { className: "size-4" }), "Paste"]
93
+ onClick: $,
94
+ disabled: !Q,
95
+ children: [/* @__PURE__ */ j(l, { className: "size-4" }), q("bigconsole.dashboards.toolbar.paste", "Paste")]
88
96
  })
89
- }), /* @__PURE__ */ k(T, { children: "Paste widget from clipboard" })] }),
90
- /* @__PURE__ */ k(o, {
91
- permission: n.WIDGET_CREATE,
97
+ }), /* @__PURE__ */ j(D, { children: q("bigconsole.dashboards.toolbar.pasteTooltip", "Paste widget from clipboard") })] }),
98
+ /* @__PURE__ */ j(s, {
99
+ permission: r.WIDGET_CREATE,
92
100
  deniedBehavior: "hide",
93
- children: /* @__PURE__ */ A(S, {
101
+ children: /* @__PURE__ */ M(w, {
94
102
  size: "sm",
95
- onClick: M,
96
- children: [/* @__PURE__ */ k(_, { className: "size-4" }), "Add Widget"]
103
+ onClick: P,
104
+ children: [/* @__PURE__ */ j(v, { className: "size-4" }), q("bigconsole.dashboards.toolbar.addWidget", "Add Widget")]
97
105
  })
98
106
  })
99
107
  ] }),
100
- /* @__PURE__ */ k(S, {
101
- variant: G ? "secondary" : "outline",
108
+ /* @__PURE__ */ j(w, {
109
+ variant: J ? "secondary" : "outline",
102
110
  size: "sm",
103
- onClick: K,
104
- children: G ? /* @__PURE__ */ A(O, { children: [/* @__PURE__ */ k(u, { className: "size-4" }), "Preview"] }) : /* @__PURE__ */ A(O, { children: [/* @__PURE__ */ k(g, { className: "size-4" }), "Edit"] })
111
+ onClick: Y,
112
+ children: J ? /* @__PURE__ */ M(A, { children: [/* @__PURE__ */ j(d, { className: "size-4" }), q("bigconsole.dashboards.toolbar.preview", "Preview")] }) : /* @__PURE__ */ M(A, { children: [/* @__PURE__ */ j(_, { className: "size-4" }), q("bigconsole.dashboards.toolbar.edit", "Edit")] })
105
113
  }),
106
- I && /* @__PURE__ */ k(S, {
114
+ R && /* @__PURE__ */ j(w, {
107
115
  variant: "outline",
108
116
  size: "sm",
109
- onClick: I,
110
- disabled: L,
111
- children: L ? /* @__PURE__ */ A(O, { children: [/* @__PURE__ */ k(C, { className: "size-4" }), "Saving..."] }) : /* @__PURE__ */ A(O, { children: [/* @__PURE__ */ k(y, { className: "size-4" }), "Save"] })
117
+ onClick: R,
118
+ disabled: z,
119
+ children: z ? /* @__PURE__ */ M(A, { children: [/* @__PURE__ */ j(T, { className: "size-4" }), q("bigconsole.dashboards.toolbar.saving", "Saving...")] }) : /* @__PURE__ */ M(A, { children: [/* @__PURE__ */ j(b, { className: "size-4" }), q("bigconsole.dashboards.toolbar.save", "Save")] })
112
120
  }),
113
- U && /* @__PURE__ */ k(o, {
114
- permission: n.DASHBOARD_SHARE,
121
+ G && /* @__PURE__ */ j(s, {
122
+ permission: r.DASHBOARD_SHARE,
115
123
  deniedBehavior: "hide",
116
- children: /* @__PURE__ */ A(w, { children: [/* @__PURE__ */ k(D, {
124
+ children: /* @__PURE__ */ M(E, { children: [/* @__PURE__ */ j(k, {
117
125
  asChild: !0,
118
- children: /* @__PURE__ */ A(S, {
126
+ children: /* @__PURE__ */ M(w, {
119
127
  variant: "outline",
120
128
  size: "sm",
121
- onClick: U,
122
- children: [/* @__PURE__ */ k(b, { className: "size-4" }), "Share"]
129
+ onClick: G,
130
+ children: [/* @__PURE__ */ j(x, { className: "size-4" }), q("bigconsole.dashboards.toolbar.share", "Share")]
123
131
  })
124
- }), /* @__PURE__ */ k(T, { children: "Share dashboard with others" })] })
132
+ }), /* @__PURE__ */ j(D, { children: q("bigconsole.dashboards.toolbar.shareTooltip", "Share dashboard with others") })] })
125
133
  }),
126
- z && /* @__PURE__ */ k(o, {
127
- permission: n.DASHBOARD_PUBLISH,
134
+ V && /* @__PURE__ */ j(s, {
135
+ permission: r.DASHBOARD_PUBLISH,
128
136
  deniedBehavior: "hide",
129
- children: /* @__PURE__ */ A(w, { children: [/* @__PURE__ */ k(D, {
137
+ children: /* @__PURE__ */ M(E, { children: [/* @__PURE__ */ j(k, {
130
138
  asChild: !0,
131
- children: /* @__PURE__ */ A(S, {
139
+ children: /* @__PURE__ */ M(w, {
132
140
  variant: "outline",
133
141
  size: "sm",
134
- onClick: z,
135
- children: [/* @__PURE__ */ k(x, { className: "size-4" }), /* @__PURE__ */ k("span", {
142
+ onClick: V,
143
+ children: [/* @__PURE__ */ j(S, { className: "size-4" }), /* @__PURE__ */ j("span", {
136
144
  className: "hidden sm:inline",
137
- children: "Publish"
145
+ children: q("bigconsole.dashboards.toolbar.publish", "Publish")
138
146
  })]
139
147
  })
140
- }), /* @__PURE__ */ k(T, { children: "Publish this dashboard as a reusable template" })] })
148
+ }), /* @__PURE__ */ j(D, { children: q("bigconsole.dashboards.toolbar.publishTooltip", "Publish this dashboard as a reusable template") })] })
141
149
  }),
142
- R && /* @__PURE__ */ A(w, { children: [/* @__PURE__ */ k(D, {
150
+ B && /* @__PURE__ */ M(E, { children: [/* @__PURE__ */ j(k, {
143
151
  asChild: !0,
144
- children: /* @__PURE__ */ A(S, {
152
+ children: /* @__PURE__ */ M(w, {
145
153
  variant: "outline",
146
154
  size: "sm",
147
- onClick: R,
148
- children: [/* @__PURE__ */ k(l, { className: "size-4" }), "Export"]
155
+ onClick: B,
156
+ children: [/* @__PURE__ */ j(u, { className: "size-4" }), q("bigconsole.dashboards.toolbar.export", "Export")]
149
157
  })
150
- }), /* @__PURE__ */ k(T, { children: "Export dashboard to JSON" })] }),
151
- B && /* @__PURE__ */ A(w, { children: [/* @__PURE__ */ k(D, {
158
+ }), /* @__PURE__ */ j(D, { children: q("bigconsole.dashboards.toolbar.exportTooltip", "Export dashboard to JSON") })] }),
159
+ H && /* @__PURE__ */ M(E, { children: [/* @__PURE__ */ j(k, {
152
160
  asChild: !0,
153
- children: /* @__PURE__ */ k(S, {
161
+ children: /* @__PURE__ */ j(w, {
154
162
  variant: "outline",
155
163
  size: "icon-sm",
156
- onClick: B,
157
- disabled: H,
158
- children: k(H ? C : f, { className: "size-4" })
164
+ onClick: H,
165
+ disabled: W,
166
+ children: j(W ? T : p, { className: "size-4" })
159
167
  })
160
- }), /* @__PURE__ */ k(T, { children: "Export board as PNG image" })] }),
161
- V && /* @__PURE__ */ A(w, { children: [/* @__PURE__ */ k(D, {
168
+ }), /* @__PURE__ */ j(D, { children: q("bigconsole.dashboards.toolbar.exportPngTooltip", "Export board as PNG image") })] }),
169
+ U && /* @__PURE__ */ M(E, { children: [/* @__PURE__ */ j(k, {
162
170
  asChild: !0,
163
- children: /* @__PURE__ */ k(S, {
171
+ children: /* @__PURE__ */ j(w, {
164
172
  variant: "outline",
165
173
  size: "icon-sm",
166
- onClick: V,
167
- disabled: H,
168
- children: /* @__PURE__ */ k(d, { className: "size-4" })
174
+ onClick: U,
175
+ disabled: W,
176
+ children: /* @__PURE__ */ j(f, { className: "size-4" })
169
177
  })
170
- }), /* @__PURE__ */ k(T, { children: "Export board as PDF" })] })
178
+ }), /* @__PURE__ */ j(D, { children: q("bigconsole.dashboards.toolbar.exportPdfTooltip", "Export board as PDF") })] })
171
179
  ]
172
180
  })
173
181
  ]
174
182
  }) });
175
183
  });
176
184
  //#endregion
177
- export { j as default };
185
+ export { N as default };
178
186
 
179
187
  //# sourceMappingURL=DashboardToolbar.js.map