@burdenoff/microfe-bigconsole 2026.805.3 → 2026.812.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) 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 +135 -97
  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 +209 -193
  23. package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js.map +1 -1
  24. package/dist/bigconsole/components/dashboard/DashboardCanvas.js +213 -231
  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 +109 -102
  29. package/dist/bigconsole/components/dashboard/DashboardToolbar.js.map +1 -1
  30. package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js +81 -70
  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 +25 -23
  35. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterChip.js.map +1 -1
  36. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js +3 -3
  37. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js.map +1 -1
  38. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js +5 -3
  39. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js.map +1 -1
  40. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js +170 -284
  41. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js.map +1 -1
  42. package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js +147 -151
  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/SavedViewsDropdown/SavedViewsDropdown.js +17 -8
  49. package/dist/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.js.map +1 -1
  50. package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js +101 -95
  51. package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js.map +1 -1
  52. package/dist/bigconsole/components/dashboard/StoreTemplatePicker.js +20 -18
  53. package/dist/bigconsole/components/dashboard/StoreTemplatePicker.js.map +1 -1
  54. package/dist/bigconsole/components/dashboard/TemplateSetupBanner.js +26 -58
  55. package/dist/bigconsole/components/dashboard/TemplateSetupBanner.js.map +1 -1
  56. package/dist/bigconsole/components/dashboard/WidgetPalette.js +307 -231
  57. package/dist/bigconsole/components/dashboard/WidgetPalette.js.map +1 -1
  58. package/dist/bigconsole/components/datasink/CacheTTLSelector.js +29 -29
  59. package/dist/bigconsole/components/datasink/CacheTTLSelector.js.map +1 -1
  60. package/dist/bigconsole/components/datasink/DataSinkCard.js +78 -79
  61. package/dist/bigconsole/components/datasink/DataSinkCard.js.map +1 -1
  62. package/dist/bigconsole/components/datasink/DataSinkDataViewer.js +33 -34
  63. package/dist/bigconsole/components/datasink/DataSinkDataViewer.js.map +1 -1
  64. package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js +79 -56
  65. package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js.map +1 -1
  66. package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js +75 -65
  67. package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js.map +1 -1
  68. package/dist/bigconsole/components/datasink/DataSinkStatusBadge.js +1 -1
  69. package/dist/bigconsole/components/datasink/DataSinkStatusBadge.js.map +1 -1
  70. package/dist/bigconsole/components/datasink/DataSinkTableViewer.js +20 -19
  71. package/dist/bigconsole/components/datasink/DataSinkTableViewer.js.map +1 -1
  72. package/dist/bigconsole/components/datasink/ExportDataSinkDialog.js +127 -171
  73. package/dist/bigconsole/components/datasink/ExportDataSinkDialog.js.map +1 -1
  74. package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js +263 -243
  75. package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js.map +1 -1
  76. package/dist/bigconsole/components/datasink/LinkedParsersPanel.js +65 -66
  77. package/dist/bigconsole/components/datasink/LinkedParsersPanel.js.map +1 -1
  78. package/dist/bigconsole/components/datasink/LinkedWorkflowsPanel.js +121 -127
  79. package/dist/bigconsole/components/datasink/LinkedWorkflowsPanel.js.map +1 -1
  80. package/dist/bigconsole/components/datasink/RefreshTypeSelector.js +33 -26
  81. package/dist/bigconsole/components/datasink/RefreshTypeSelector.js.map +1 -1
  82. package/dist/bigconsole/components/datasink/SetupStateBadge.js +3 -3
  83. package/dist/bigconsole/components/datasink/SetupStateBadge.js.map +1 -1
  84. package/dist/bigconsole/components/datasink/WorkflowStatusPanel.js +95 -95
  85. package/dist/bigconsole/components/datasink/WorkflowStatusPanel.js.map +1 -1
  86. package/dist/bigconsole/components/parser/DataSinkSelector.js +154 -123
  87. package/dist/bigconsole/components/parser/DataSinkSelector.js.map +1 -1
  88. package/dist/bigconsole/components/parser/ExpressionEditor.js +3 -3
  89. package/dist/bigconsole/components/parser/ExpressionEditor.js.map +1 -1
  90. package/dist/bigconsole/components/parser/ImportParserDialog.js +235 -275
  91. package/dist/bigconsole/components/parser/ImportParserDialog.js.map +1 -1
  92. package/dist/bigconsole/components/parser/ParserCard.js +133 -114
  93. package/dist/bigconsole/components/parser/ParserCard.js.map +1 -1
  94. package/dist/bigconsole/components/parser/ParserSelector.js +191 -174
  95. package/dist/bigconsole/components/parser/ParserSelector.js.map +1 -1
  96. package/dist/bigconsole/components/parser/ParserStatusBadge.js +2 -2
  97. package/dist/bigconsole/components/parser/ParserStatusBadge.js.map +1 -1
  98. package/dist/bigconsole/components/parser/ParserTypeBadge.js +4 -4
  99. package/dist/bigconsole/components/parser/ParserTypeBadge.js.map +1 -1
  100. package/dist/bigconsole/components/pipeline/PipelineCard.js +134 -89
  101. package/dist/bigconsole/components/pipeline/PipelineCard.js.map +1 -1
  102. package/dist/bigconsole/components/pipeline/PipelineDeleteDialog.js +77 -64
  103. package/dist/bigconsole/components/pipeline/PipelineDeleteDialog.js.map +1 -1
  104. package/dist/bigconsole/components/pipeline/PipelineStatusBadge.js +7 -10
  105. package/dist/bigconsole/components/pipeline/PipelineStatusBadge.js.map +1 -1
  106. package/dist/bigconsole/components/preview/AiPreviewContent.js +31 -32
  107. package/dist/bigconsole/components/preview/AiPreviewContent.js.map +1 -1
  108. package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js +152 -106
  109. package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js.map +1 -1
  110. package/dist/bigconsole/components/preview/AiPreviewPanel.js +193 -152
  111. package/dist/bigconsole/components/preview/AiPreviewPanel.js.map +1 -1
  112. package/dist/bigconsole/components/preview/previewShared.js +41 -23
  113. package/dist/bigconsole/components/preview/previewShared.js.map +1 -1
  114. package/dist/bigconsole/components/widgets/ActionConfigDialog.js +342 -308
  115. package/dist/bigconsole/components/widgets/ActionConfigDialog.js.map +1 -1
  116. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js +262 -238
  117. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js.map +1 -1
  118. package/dist/bigconsole/components/widgets/PropertiesPanel.js +783 -867
  119. package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
  120. package/dist/bigconsole/components/widgets/WidgetErrorBoundary.js +7 -5
  121. package/dist/bigconsole/components/widgets/WidgetErrorBoundary.js.map +1 -1
  122. package/dist/bigconsole/components/widgets/WidgetHeader.js +7 -8
  123. package/dist/bigconsole/components/widgets/WidgetHeader.js.map +1 -1
  124. package/dist/bigconsole/components/widgets/WidgetRegistry.js +4 -4
  125. package/dist/bigconsole/components/widgets/WidgetRegistry.js.map +1 -1
  126. package/dist/bigconsole/components/widgets/WidgetWrapper.js +8 -7
  127. package/dist/bigconsole/components/widgets/WidgetWrapper.js.map +1 -1
  128. package/dist/bigconsole/components/widgets/adaptive-card/AdaptiveCardWidget.js +1 -1
  129. package/dist/bigconsole/components/widgets/adaptive-card/AdaptiveCardWidget.js.map +1 -1
  130. package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js +2 -2
  131. package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js.map +1 -1
  132. package/dist/bigconsole/components/widgets/chart/ChartConfig.js +11 -5
  133. package/dist/bigconsole/components/widgets/chart/ChartConfig.js.map +1 -1
  134. package/dist/bigconsole/components/widgets/comments/WidgetComments.js +19 -15
  135. package/dist/bigconsole/components/widgets/comments/WidgetComments.js.map +1 -1
  136. package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js +154 -102
  137. package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js.map +1 -1
  138. package/dist/bigconsole/components/widgets/gauge/CircularGauge.js +36 -32
  139. package/dist/bigconsole/components/widgets/gauge/CircularGauge.js.map +1 -1
  140. package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js +85 -60
  141. package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js.map +1 -1
  142. package/dist/bigconsole/components/widgets/gauge/GaugeWidget.js +64 -35
  143. package/dist/bigconsole/components/widgets/gauge/GaugeWidget.js.map +1 -1
  144. package/dist/bigconsole/components/widgets/gauge/LinearGauge.js +46 -45
  145. package/dist/bigconsole/components/widgets/gauge/LinearGauge.js.map +1 -1
  146. package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js +35 -24
  147. package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js.map +1 -1
  148. package/dist/bigconsole/components/widgets/iframe-widget/IframeWidget.js +2 -2
  149. package/dist/bigconsole/components/widgets/iframe-widget/IframeWidget.js.map +1 -1
  150. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +4 -4
  151. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js.map +1 -1
  152. package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js +153 -90
  153. package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js.map +1 -1
  154. package/dist/bigconsole/components/widgets/list/ListConfig.js +8 -2
  155. package/dist/bigconsole/components/widgets/list/ListConfig.js.map +1 -1
  156. package/dist/bigconsole/components/widgets/list/ListItem.js +1 -1
  157. package/dist/bigconsole/components/widgets/list/ListItem.js.map +1 -1
  158. package/dist/bigconsole/components/widgets/map-widget/MapWidget.js +1 -1
  159. package/dist/bigconsole/components/widgets/map-widget/MapWidget.js.map +1 -1
  160. package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js +14 -4
  161. package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js.map +1 -1
  162. package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js +112 -89
  163. package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js.map +1 -1
  164. package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js +21 -13
  165. package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js.map +1 -1
  166. package/dist/bigconsole/components/widgets/metric-card/index.js +4 -4
  167. package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js +3 -3
  168. package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js.map +1 -1
  169. package/dist/bigconsole/components/widgets/progress/ProgressConfig.js +34 -25
  170. package/dist/bigconsole/components/widgets/progress/ProgressConfig.js.map +1 -1
  171. package/dist/bigconsole/components/widgets/progress/ProgressWidget.js +129 -114
  172. package/dist/bigconsole/components/widgets/progress/ProgressWidget.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 +10 -4
  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/utils/targetProgress.js +13 -0
  194. package/dist/bigconsole/components/widgets/utils/targetProgress.js.map +1 -0
  195. package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js +112 -85
  196. package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js.map +1 -1
  197. package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js +28 -20
  198. package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js.map +1 -1
  199. package/dist/bigconsole/components/workflow/WorkflowCard.js +92 -77
  200. package/dist/bigconsole/components/workflow/WorkflowCard.js.map +1 -1
  201. package/dist/bigconsole/components/workflow/WorkflowDeleteDialog.js +70 -51
  202. package/dist/bigconsole/components/workflow/WorkflowDeleteDialog.js.map +1 -1
  203. package/dist/bigconsole/components/workflow/WorkflowStatusBadge.js +16 -17
  204. package/dist/bigconsole/components/workflow/WorkflowStatusBadge.js.map +1 -1
  205. package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js +6 -4
  206. package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js.map +1 -1
  207. package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js +360 -338
  208. package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js.map +1 -1
  209. package/dist/bigconsole/hooks/useModalFocusTrap.js +53 -0
  210. package/dist/bigconsole/hooks/useModalFocusTrap.js.map +1 -0
  211. package/dist/bigconsole/pages/DashboardBuilderPage.js +209 -203
  212. package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
  213. package/dist/bigconsole/pages/DashboardViewPage.js +126 -120
  214. package/dist/bigconsole/pages/DashboardViewPage.js.map +1 -1
  215. package/dist/bigconsole/pages/DashboardsPage.js +838 -800
  216. package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
  217. package/dist/bigconsole/pages/DataParsersPage.js +263 -315
  218. package/dist/bigconsole/pages/DataParsersPage.js.map +1 -1
  219. package/dist/bigconsole/pages/DataSinkBuilderPage.js +301 -341
  220. package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
  221. package/dist/bigconsole/pages/DataSinkViewPage.js +346 -339
  222. package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
  223. package/dist/bigconsole/pages/DataSinksPage.js +356 -458
  224. package/dist/bigconsole/pages/DataSinksPage.js.map +1 -1
  225. package/dist/bigconsole/pages/DataSourcesPage.js +7 -2
  226. package/dist/bigconsole/pages/DataSourcesPage.js.map +1 -1
  227. package/dist/bigconsole/pages/HomePage.js +186 -193
  228. package/dist/bigconsole/pages/HomePage.js.map +1 -1
  229. package/dist/bigconsole/pages/InsightsPage.js +887 -740
  230. package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
  231. package/dist/bigconsole/pages/ParserBuilderPage.js +679 -637
  232. package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
  233. package/dist/bigconsole/pages/ParserViewPage.js +368 -342
  234. package/dist/bigconsole/pages/ParserViewPage.js.map +1 -1
  235. package/dist/bigconsole/pages/PipelineBuilderPage.js +537 -444
  236. package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
  237. package/dist/bigconsole/pages/PipelineViewPage.js +412 -377
  238. package/dist/bigconsole/pages/PipelineViewPage.js.map +1 -1
  239. package/dist/bigconsole/pages/PipelinesPage.js +248 -298
  240. package/dist/bigconsole/pages/PipelinesPage.js.map +1 -1
  241. package/dist/bigconsole/pages/WidgetDemoPage.js +251 -153
  242. package/dist/bigconsole/pages/WidgetDemoPage.js.map +1 -1
  243. package/dist/bigconsole/pages/WorkflowViewPage.js +381 -371
  244. package/dist/bigconsole/pages/WorkflowViewPage.js.map +1 -1
  245. package/dist/bigconsole/pages/WorkflowsPage.js +171 -286
  246. package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
  247. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"WidgetPalette.js","names":[],"sources":["../../../../src/bigconsole/components/dashboard/WidgetPalette.tsx"],"sourcesContent":["/**\n * WidgetPalette Component\n *\n * Sidebar panel with draggable widget types for the dashboard builder.\n * Uses semantic tokens for consistent theming.\n * Features categorized widgets, search, and drag-and-drop support.\n */\n\nimport { type FC, memo, useState, useCallback, useMemo } from 'react';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n Search,\n ChevronDown,\n ChevronRight,\n TrendingUp,\n BarChart3,\n Filter,\n Table,\n Grid3x3,\n Gauge,\n Activity,\n List,\n FileText,\n Type,\n ExternalLink,\n MapPin,\n Calendar,\n Columns,\n GitBranch,\n Puzzle,\n LayoutDashboard,\n GripVertical,\n X,\n Layers,\n Store,\n type LucideIcon,\n} from 'lucide-react';\nimport {\n getWidgetCategories,\n getWidgetKey,\n WIDGET_CATEGORY_LABELS,\n type WidgetDefinition,\n} from '../widgets/WidgetRegistry';\nimport type { WidgetType, WidgetCategory } from '../../types';\n\n// ============================================================================\n// Icon Mapping\n// ============================================================================\n\nconst ICON_MAP: Record<string, LucideIcon> = {\n TrendingUp,\n BarChart3,\n Filter,\n Table,\n Grid3x3,\n Gauge,\n Activity,\n List,\n FileText,\n Type,\n ExternalLink,\n MapPin,\n Calendar,\n Columns,\n GitBranch,\n Puzzle,\n LayoutDashboard,\n};\n\nfunction getIconComponent(iconName: string): LucideIcon {\n return ICON_MAP[iconName] || Puzzle;\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface WidgetPaletteProps {\n /** Whether the palette is open */\n isOpen: boolean;\n /** Callback to close the palette */\n onClose: () => void;\n /** Callback when a widget is selected (for quick add without drag) */\n onWidgetSelect?: (type: WidgetType, definition?: WidgetDefinition) => void;\n /** Callback when drag starts */\n onDragStart?: (type: WidgetType, definition: WidgetDefinition) => void;\n /** Callback when drag ends */\n onDragEnd?: () => void;\n /** Installed widgets from the store (fetched by parent) */\n installedWidgets?: WidgetDefinition[];\n /** Whether installed widgets are still loading */\n installedWidgetsLoading?: boolean;\n /**\n * Built-in widget catalog (from the backend `getWidgetTypes`, fetched by the\n * parent via useWidgetCatalog). When omitted, falls back to the bundled\n * static registry.\n */\n definitions?: WidgetDefinition[];\n}\n\n// ============================================================================\n// Styles using semantic tokens\n// ============================================================================\n\nconst styles = {\n container: {\n width: '300px',\n height: '100%',\n backgroundColor: 'var(--color-bg-surface)',\n borderRight: '1px solid var(--color-border)',\n display: 'flex',\n flexDirection: 'column' as const,\n flexShrink: 0,\n overflow: 'hidden',\n position: 'relative' as const,\n },\n header: {\n padding: 'var(--space-formGap)',\n borderBottom: '1px solid var(--color-border)',\n backgroundColor: 'var(--color-bg-sunken)',\n flexShrink: 0,\n },\n headerTop: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n marginBottom: 'var(--space-controlGap)',\n },\n headerTitle: {\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-iconGap)',\n },\n headerIcon: {\n width: '32px',\n height: '32px',\n borderRadius: 'var(--radius-button)',\n backgroundColor: 'var(--color-action-primary-bg)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n },\n title: {\n fontSize: 'var(--font-size-body-md)',\n fontWeight: 'var(--font-weight-semibold)' as const,\n color: 'var(--color-text-primary)',\n margin: 0,\n },\n subtitle: {\n fontSize: 'var(--font-size-body-xs)',\n color: 'var(--color-text-muted)',\n margin: '2px 0 0 0',\n },\n closeButton: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '28px',\n height: '28px',\n border: 'none',\n background: 'transparent',\n borderRadius: 'var(--radius-button)',\n cursor: 'pointer',\n color: 'var(--color-text-secondary)',\n transition: 'background-color 0.15s',\n },\n searchContainer: {\n position: 'relative' as const,\n },\n searchIcon: {\n position: 'absolute' as const,\n left: '10px',\n top: '50%',\n transform: 'translateY(-50%)',\n width: '16px',\n height: '16px',\n color: 'var(--color-text-muted)',\n pointerEvents: 'none' as const,\n },\n searchInput: {\n width: '100%',\n paddingLeft: '36px',\n height: 'var(--size-controlHeight-sm)',\n fontSize: 'var(--font-size-body-sm)',\n },\n content: {\n flex: '1 1 0',\n minHeight: 0,\n overflow: 'hidden',\n position: 'relative' as const,\n },\n scrollArea: {\n position: 'absolute' as const,\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n overflowY: 'auto' as const,\n overflowX: 'hidden' as const,\n padding: 'var(--space-controlGap)',\n },\n categoryContainer: {\n marginBottom: 'var(--space-controlGap)',\n },\n categoryHeader: {\n width: '100%',\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-iconGap)',\n padding: 'var(--space-controlGap) var(--space-iconGap)',\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n borderRadius: 'var(--radius-button)',\n transition: 'background-color 0.15s',\n },\n categoryChevron: {\n width: '16px',\n height: '16px',\n color: 'var(--color-text-muted)',\n flexShrink: 0,\n },\n categoryLabel: {\n flex: 1,\n textAlign: 'left' as const,\n fontSize: 'var(--font-size-body-xs)',\n fontWeight: 'var(--font-weight-semibold)' as const,\n color: 'var(--color-text-secondary)',\n textTransform: 'uppercase' as const,\n letterSpacing: '0.05em',\n },\n categoryCount: {\n fontSize: 'var(--font-size-body-xs)',\n color: 'var(--color-text-muted)',\n backgroundColor: 'var(--color-bg-sunken)',\n padding: '2px 8px',\n borderRadius: 'var(--radius-full)',\n },\n widgetList: {\n display: 'flex',\n flexDirection: 'column' as const,\n gap: '4px',\n marginTop: 'var(--space-controlGap)',\n paddingLeft: '4px',\n },\n widgetCard: {\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-iconGap)',\n padding: 'var(--space-controlGap)',\n borderRadius: 'var(--radius-card)',\n cursor: 'grab',\n backgroundColor: 'var(--color-bg-surface)',\n border: '1px solid var(--color-border)',\n transition: 'all 0.15s ease',\n },\n widgetCardHover: {\n backgroundColor: 'var(--color-bg-hover)',\n borderColor: 'var(--color-action-primary-border)',\n boxShadow: 'var(--shadow-elevation-1)',\n },\n dragHandle: {\n width: '16px',\n height: '16px',\n color: 'var(--color-text-muted)',\n opacity: 0.5,\n flexShrink: 0,\n },\n widgetIcon: {\n width: '36px',\n height: '36px',\n borderRadius: 'var(--radius-button)',\n backgroundColor: 'var(--color-bg-sunken)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n },\n widgetIconInner: {\n width: '18px',\n height: '18px',\n color: 'var(--color-action-primary-bg)',\n },\n widgetText: {\n flex: 1,\n minWidth: 0,\n overflow: 'hidden',\n },\n widgetName: {\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)' as const,\n color: 'var(--color-text-primary)',\n whiteSpace: 'nowrap' as const,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n marginBottom: '2px',\n },\n widgetDescription: {\n fontSize: 'var(--font-size-body-xs)',\n color: 'var(--color-text-muted)',\n lineHeight: 1.3,\n overflow: 'hidden',\n display: '-webkit-box',\n WebkitLineClamp: 2,\n WebkitBoxOrient: 'vertical' as const,\n },\n emptyState: {\n textAlign: 'center' as const,\n padding: 'var(--space-pagePadding)',\n },\n emptyIcon: {\n width: '48px',\n height: '48px',\n borderRadius: 'var(--radius-card)',\n backgroundColor: 'var(--color-bg-sunken)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n margin: '0 auto var(--space-formGap)',\n },\n emptyText: {\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-muted)',\n margin: 0,\n },\n clearButton: {\n marginTop: 'var(--space-controlGap)',\n padding: 'var(--space-controlGap) var(--space-formGap)',\n fontSize: 'var(--font-size-body-xs)',\n fontWeight: 'var(--font-weight-medium)' as const,\n color: 'var(--color-action-primary-text)',\n backgroundColor: 'var(--color-action-primary-bg)',\n border: 'none',\n borderRadius: 'var(--radius-button)',\n cursor: 'pointer',\n },\n footer: {\n padding: 'var(--space-controlGap) var(--space-formGap)',\n borderTop: '1px solid var(--color-border)',\n backgroundColor: 'var(--color-bg-sunken)',\n flexShrink: 0,\n },\n footerText: {\n fontSize: 'var(--font-size-body-xs)',\n color: 'var(--color-text-muted)',\n margin: 0,\n textAlign: 'center' as const,\n },\n browseStoreButton: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 'var(--space-iconGap)',\n width: '100%',\n padding: 'var(--space-controlGap)',\n marginBottom: 'var(--space-controlGap)',\n borderRadius: 'var(--radius-button)',\n border: '1px dashed var(--color-border)',\n backgroundColor: 'transparent',\n color: 'var(--color-text-secondary)',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)' as const,\n cursor: 'pointer',\n transition: 'border-color 0.15s, color 0.15s',\n },\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const WidgetPalette: FC<WidgetPaletteProps> = memo(function WidgetPalette({\n isOpen,\n onClose,\n onWidgetSelect,\n onDragStart,\n onDragEnd,\n installedWidgets = [],\n installedWidgetsLoading = false,\n definitions,\n}) {\n const { t } = useI18n();\n const [searchQuery, setSearchQuery] = useState('');\n const [expandedCategories, setExpandedCategories] = useState<Set<WidgetCategory>>(\n new Set(['KPI', 'Visualization', 'Data', 'Content', 'Temporal', 'Custom', 'Installed'])\n );\n const [hoveredWidget, setHoveredWidget] = useState<string | null>(null);\n\n // Get categorized widgets, merging in installed widgets. When the parent\n // supplies a backend-sourced catalog (`definitions`), group that by category;\n // otherwise fall back to the bundled static registry.\n const categories = useMemo(() => {\n const baseCategories = definitions\n ? (Object.keys(WIDGET_CATEGORY_LABELS) as WidgetCategory[]).map((category) => ({\n category,\n label: WIDGET_CATEGORY_LABELS[category],\n widgets: definitions.filter((def) => def.category === category),\n }))\n : getWidgetCategories();\n\n return baseCategories\n .map((cat) => {\n if (cat.category === 'Installed') {\n // Two sources feed \"Installed from Store\": the registry-driven backend\n // catalog (getWidgetTypes store types — rich metadata, install-gated,\n // BOFF-2858) which arrives via `definitions` under this category, and\n // the legacy workspaceInstalledApps listing passed as `installedWidgets`.\n // Merge both, deduping by name (the catalog entry wins) so a widget\n // present in both sources shows once with the richer definition, while\n // legacy installs not yet in the registry are still preserved.\n const byName = new Map<string, WidgetDefinition>();\n for (const w of installedWidgets) byName.set(w.name.toLowerCase(), w);\n for (const w of cat.widgets) {\n const key = w.name.toLowerCase();\n const legacy = byName.get(key);\n // Catalog wins for metadata but MERGE defaultConfig so the legacy\n // workspaceInstalledApps fields survive — notably `componentId`, which the\n // current render path needs and the catalog store entry lacks until\n // widgetTypeKey rendering is wired. Keeps overlapping store widgets renderable.\n byName.set(key, legacy ? { ...w, defaultConfig: { ...legacy.defaultConfig, ...w.defaultConfig } } : w);\n }\n return { ...cat, widgets: Array.from(byName.values()) };\n }\n return cat;\n })\n .filter((cat) => cat.category !== 'Installed' || cat.widgets.length > 0);\n }, [installedWidgets, definitions]);\n\n // Filter widgets by search query\n const filteredCategories = useMemo(() => {\n if (!searchQuery.trim()) {\n return categories;\n }\n\n const query = searchQuery.toLowerCase();\n return categories\n .map((cat) => ({\n ...cat,\n widgets: cat.widgets.filter(\n (w) =>\n w.name.toLowerCase().includes(query) ||\n w.description.toLowerCase().includes(query) ||\n w.tags.some((tag) => tag.includes(query))\n ),\n }))\n .filter((cat) => cat.widgets.length > 0);\n }, [categories, searchQuery]);\n\n // Toggle category expansion\n const toggleCategory = useCallback((category: WidgetCategory) => {\n setExpandedCategories((prev) => {\n const next = new Set(prev);\n if (next.has(category)) {\n next.delete(category);\n } else {\n next.add(category);\n }\n return next;\n });\n }, []);\n\n // Handle drag start\n const handleDragStart = useCallback(\n (e: React.DragEvent, widget: WidgetDefinition) => {\n e.dataTransfer.setData(\n 'application/json',\n JSON.stringify({\n type: widget.type,\n name: widget.name,\n defaultSize: widget.defaultSize,\n defaultConfig: widget.defaultConfig,\n category: widget.category,\n })\n );\n e.dataTransfer.effectAllowed = 'copy';\n\n // Create custom drag image\n const dragImage = document.createElement('div');\n dragImage.style.cssText = `\n position: absolute;\n top: -1000px;\n left: -1000px;\n padding: 8px 12px;\n background: var(--color-bg-surface);\n border: 2px solid var(--color-action-primary-bg);\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--color-text-primary);\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n `;\n dragImage.textContent = widget.name;\n document.body.appendChild(dragImage);\n e.dataTransfer.setDragImage(dragImage, 0, 0);\n\n setTimeout(() => {\n document.body.removeChild(dragImage);\n }, 0);\n\n onDragStart?.(widget.type, widget);\n },\n [onDragStart]\n );\n\n // Handle drag end\n const handleDragEnd = useCallback(() => {\n onDragEnd?.();\n }, [onDragEnd]);\n\n // Handle click to quick-add\n const handleWidgetClick = useCallback(\n (widget: WidgetDefinition) => {\n onWidgetSelect?.(widget.type, widget);\n },\n [onWidgetSelect]\n );\n\n // Open the widget store in a new tab so the builder (and any unsaved edits)\n // stays intact. Preserves the current org/workspace/project query params.\n const handleBrowseStore = useCallback(() => {\n if (typeof window === 'undefined') return;\n const url = `${window.location.origin}/bigconsole/store${window.location.search}`;\n window.open(url, '_blank', 'noopener,noreferrer');\n }, []);\n\n if (!isOpen) {\n return null;\n }\n\n return (\n <div style={styles.container}>\n {/* Header */}\n <div style={styles.header}>\n <div style={styles.headerTop}>\n <div style={styles.headerTitle}>\n <div style={styles.headerIcon}>\n <Layers style={{ width: '18px', height: '18px', color: 'var(--color-action-primary-text)' }} />\n </div>\n <div>\n <h3 style={styles.title}>{t('bigconsole.dashboards.widgetPalette.title', 'Widgets')}</h3>\n <p style={styles.subtitle}>{t('bigconsole.dashboards.widgetPalette.subtitle', 'Drag or click to add')}</p>\n </div>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n style={styles.closeButton}\n onMouseOver={(e) => (e.currentTarget.style.backgroundColor = 'var(--color-bg-hover)')}\n onMouseOut={(e) => (e.currentTarget.style.backgroundColor = 'transparent')}\n >\n <X style={{ width: '16px', height: '16px' }} />\n </button>\n </div>\n\n {/* Search */}\n <div style={styles.searchContainer}>\n <Search style={styles.searchIcon} />\n <Input\n type=\"text\"\n placeholder={t('bigconsole.dashboards.widgetPalette.searchPlaceholder', 'Search widgets...')}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n style={styles.searchInput}\n />\n </div>\n </div>\n\n {/* Widget Categories */}\n <div style={styles.content}>\n <div style={styles.scrollArea}>\n {filteredCategories.map((category) => (\n <div key={category.category} style={styles.categoryContainer}>\n {/* Category Header */}\n <button\n type=\"button\"\n onClick={() => toggleCategory(category.category)}\n style={styles.categoryHeader}\n onMouseOver={(e) => (e.currentTarget.style.backgroundColor = 'var(--color-bg-hover)')}\n onMouseOut={(e) => (e.currentTarget.style.backgroundColor = 'transparent')}\n >\n {expandedCategories.has(category.category) ? (\n <ChevronDown style={styles.categoryChevron} />\n ) : (\n <ChevronRight style={styles.categoryChevron} />\n )}\n <span style={styles.categoryLabel}>{category.label}</span>\n <span style={styles.categoryCount}>{category.widgets.length}</span>\n </button>\n\n {/* Widget Items */}\n {expandedCategories.has(category.category) && (\n <div style={styles.widgetList}>\n {installedWidgetsLoading && category.category === 'Installed' && (\n <div\n style={{\n fontSize: 'var(--font-size-body-xs)',\n color: 'var(--color-text-muted)',\n padding: 'var(--space-controlGap)',\n }}\n >\n {t('bigconsole.dashboards.widgetPalette.loading', 'Loading...')}\n </div>\n )}\n {category.widgets.map((widget) => {\n const IconComponent = getIconComponent(widget.icon);\n const widgetKey = getWidgetKey(widget);\n const isHovered = hoveredWidget === widgetKey;\n\n return (\n <div\n key={widgetKey}\n draggable\n onDragStart={(e) => handleDragStart(e, widget)}\n onDragEnd={handleDragEnd}\n onClick={() => handleWidgetClick(widget)}\n onMouseEnter={() => setHoveredWidget(widgetKey)}\n onMouseLeave={() => setHoveredWidget(null)}\n style={{\n ...styles.widgetCard,\n ...(isHovered ? styles.widgetCardHover : {}),\n }}\n >\n {/* Drag Handle */}\n <GripVertical style={styles.dragHandle} />\n\n {/* Icon */}\n <div style={styles.widgetIcon}>\n <IconComponent style={styles.widgetIconInner} />\n </div>\n\n {/* Text */}\n <div style={styles.widgetText}>\n <div style={styles.widgetName}>{widget.name}</div>\n <div style={styles.widgetDescription}>{widget.description}</div>\n </div>\n </div>\n );\n })}\n </div>\n )}\n </div>\n ))}\n\n {filteredCategories.length === 0 && (\n <div style={styles.emptyState}>\n <div style={styles.emptyIcon}>\n <Search style={{ width: '24px', height: '24px', color: 'var(--color-text-muted)' }} />\n </div>\n <p style={styles.emptyText}>\n {t('bigconsole.dashboards.widgetPalette.noResultsBefore', 'No widgets found for')} \"\n <strong>{searchQuery}</strong>\"\n </p>\n <button type=\"button\" onClick={() => setSearchQuery('')} style={styles.clearButton}>\n {t('bigconsole.dashboards.widgetPalette.clearSearch', 'Clear search')}\n </button>\n </div>\n )}\n </div>\n </div>\n\n {/* Footer */}\n <div style={styles.footer}>\n <button\n type=\"button\"\n onClick={handleBrowseStore}\n style={styles.browseStoreButton}\n onMouseOver={(e) => {\n e.currentTarget.style.borderColor = 'var(--color-action-primary-bg)';\n e.currentTarget.style.color = 'var(--color-action-primary-text)';\n }}\n onMouseOut={(e) => {\n e.currentTarget.style.borderColor = 'var(--color-border)';\n e.currentTarget.style.color = 'var(--color-text-secondary)';\n }}\n >\n <Store style={{ width: '15px', height: '15px' }} />\n {t('bigconsole.dashboards.widgetPalette.browseStore', 'Browse widget store')}\n <ExternalLink style={{ width: '13px', height: '13px', opacity: 0.7 }} />\n </button>\n <p style={styles.footerText}>\n {t('bigconsole.dashboards.widgetPalette.footerHint', 'Drag widgets to position them on the canvas')}\n </p>\n </div>\n </div>\n );\n});\n\nexport default WidgetPalette;\n"],"mappings":"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"}
1
+ {"version":3,"file":"WidgetPalette.js","names":[],"sources":["../../../../src/bigconsole/components/dashboard/WidgetPalette.tsx"],"sourcesContent":["/**\n * WidgetPalette Component\n *\n * Sidebar panel with draggable widget types for the dashboard builder.\n * Uses semantic tokens for consistent theming.\n * Features categorized widgets, search, and drag-and-drop support.\n *\n * Section emphasis (BOFF-5636). The palette used to be three bands that all\n * looked alike — sunken header, surface body, sunken footer — with cards drawn\n * on exactly the same fill as the panel behind them, so a card read as a row\n * rather than as a draggable object. It now follows one rule:\n *\n * header (surface, the panel's identity)\n * → scroll body (sunken, a recessed tray)\n * → widget cards (surface + elevation, objects lifted off the tray)\n * → footer (surface, terminal band, lighter type)\n *\n * and the category headings sit above their cards with heading-weight type, so\n * the group is never lighter than the things it groups.\n */\n\nimport { type FC, memo, useState, useCallback, useMemo } from 'react';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { SECTION_FOCUS_RING } from '../common';\nimport {\n Search,\n ChevronDown,\n ChevronRight,\n TrendingUp,\n BarChart3,\n Filter,\n Table,\n Grid3x3,\n Gauge,\n Activity,\n List,\n FileText,\n Type,\n ExternalLink,\n MapPin,\n Calendar,\n Columns,\n GitBranch,\n Puzzle,\n LayoutDashboard,\n GripVertical,\n X,\n Layers,\n Store,\n type LucideIcon,\n} from 'lucide-react';\nimport {\n getWidgetCategories,\n getWidgetKey,\n WIDGET_CATEGORY_LABELS,\n type WidgetDefinition,\n} from '../widgets/WidgetRegistry';\nimport type { WidgetType, WidgetCategory } from '../../types';\n\n// ============================================================================\n// Icon Mapping\n// ============================================================================\n\nconst ICON_MAP: Record<string, LucideIcon> = {\n TrendingUp,\n BarChart3,\n Filter,\n Table,\n Grid3x3,\n Gauge,\n Activity,\n List,\n FileText,\n Type,\n ExternalLink,\n MapPin,\n Calendar,\n Columns,\n GitBranch,\n Puzzle,\n LayoutDashboard,\n};\n\nfunction getIconComponent(iconName: string): LucideIcon {\n return ICON_MAP[iconName] || Puzzle;\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface WidgetPaletteProps {\n /** Whether the palette is open */\n isOpen: boolean;\n /** Callback to close the palette */\n onClose: () => void;\n /** Callback when a widget is selected (for quick add without drag) */\n onWidgetSelect?: (type: WidgetType, definition?: WidgetDefinition) => void;\n /** Callback when drag starts */\n onDragStart?: (type: WidgetType, definition: WidgetDefinition) => void;\n /** Callback when drag ends */\n onDragEnd?: () => void;\n /** Installed widgets from the store (fetched by parent) */\n installedWidgets?: WidgetDefinition[];\n /** Whether installed widgets are still loading */\n installedWidgetsLoading?: boolean;\n /**\n * Built-in widget catalog (from the backend `getWidgetTypes`, fetched by the\n * parent via useWidgetCatalog). When omitted, falls back to the bundled\n * static registry.\n */\n definitions?: WidgetDefinition[];\n}\n\n// ============================================================================\n// Styles using semantic tokens\n// ============================================================================\n\nconst styles = {\n // Width, borders and max-height live in `className` so they can be\n // breakpoint-aware — a hard 300px pane next to a canvas is unusable on a\n // phone, where the palette now becomes a full-width, height-capped drawer.\n container: {\n backgroundColor: 'var(--color-bg-surface)',\n display: 'flex',\n flexDirection: 'column' as const,\n flexShrink: 0,\n overflow: 'hidden',\n position: 'relative' as const,\n },\n header: {\n padding: 'var(--space-formGap)',\n borderBottom: '1px solid var(--color-border-subtle)',\n backgroundColor: 'var(--color-bg-surface)',\n flexShrink: 0,\n },\n headerTop: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n marginBottom: 'var(--space-controlGap)',\n },\n headerTitle: {\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-iconGap)',\n },\n headerIcon: {\n width: '32px',\n height: '32px',\n borderRadius: 'var(--radius-button)',\n backgroundColor: 'var(--color-action-primary-bg)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n },\n title: {\n fontSize: 'var(--font-size-body-md)',\n fontWeight: 'var(--font-weight-bold)' as const,\n letterSpacing: '-0.01em',\n color: 'var(--color-text-primary)',\n margin: 0,\n },\n subtitle: {\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-secondary)',\n margin: '2px 0 0 0',\n },\n closeButton: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n // 40px keeps the only way to dismiss the palette above the minimum\n // touch-target size on a phone (was 28px).\n width: 'var(--size-controlHeight-md)',\n height: 'var(--size-controlHeight-md)',\n border: 'none',\n background: 'transparent',\n borderRadius: 'var(--radius-button)',\n cursor: 'pointer',\n color: 'var(--color-text-secondary)',\n flexShrink: 0,\n transition: 'background-color 0.15s',\n },\n searchContainer: {\n position: 'relative' as const,\n },\n searchIcon: {\n position: 'absolute' as const,\n left: '10px',\n top: '50%',\n transform: 'translateY(-50%)',\n width: '16px',\n height: '16px',\n color: 'var(--color-text-muted)',\n pointerEvents: 'none' as const,\n },\n searchInput: {\n width: '100%',\n paddingLeft: '36px',\n height: 'var(--size-controlHeight-md)',\n fontSize: 'var(--font-size-body-sm)',\n },\n content: {\n flex: '1 1 0',\n minHeight: 0,\n overflow: 'hidden',\n position: 'relative' as const,\n },\n // Recessed tray: the cards below sit ON this, so they can be lifted off it.\n scrollArea: {\n position: 'absolute' as const,\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n overflowY: 'auto' as const,\n overflowX: 'hidden' as const,\n padding: 'var(--space-controlGap)',\n backgroundColor: 'var(--color-bg-sunken)',\n },\n categoryContainer: {\n marginBottom: 'var(--space-formGap)',\n },\n categoryHeading: {\n margin: 0,\n },\n categoryHeader: {\n width: '100%',\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-iconGap)',\n minHeight: 'var(--size-controlHeight-md)',\n padding: 'var(--space-iconGap) var(--space-controlGap)',\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n borderRadius: 'var(--radius-button)',\n transition: 'background-color 0.15s',\n },\n categoryChevron: {\n width: '16px',\n height: '16px',\n color: 'var(--color-text-secondary)',\n flexShrink: 0,\n },\n // A group label must not be lighter than its members: heading weight,\n // primary text colour, uppercase for rhythm.\n categoryLabel: {\n flex: 1,\n textAlign: 'left' as const,\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-bold)' as const,\n color: 'var(--color-text-primary)',\n textTransform: 'uppercase' as const,\n letterSpacing: '0.06em',\n },\n categoryCount: {\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)' as const,\n color: 'var(--color-text-secondary)',\n backgroundColor: 'var(--color-bg-surface)',\n border: '1px solid var(--color-border-subtle)',\n padding: '1px 8px',\n // `--radius-full` is not a token in the build; the undefined var made the\n // declaration invalid, so the \"pill\" rendered as a square (BOFF-5636).\n borderRadius: 'var(--radius-pill, 9999px)',\n flexShrink: 0,\n },\n widgetList: {\n display: 'flex',\n flexDirection: 'column' as const,\n gap: '4px',\n marginTop: 'var(--space-controlGap)',\n paddingLeft: '4px',\n },\n widgetCard: {\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-iconGap)',\n minHeight: 'var(--size-controlHeight-lg)',\n padding: 'var(--space-controlGap)',\n borderRadius: 'var(--radius-card)',\n cursor: 'grab',\n backgroundColor: 'var(--color-bg-surface)',\n border: '1px solid var(--color-border-subtle)',\n // Elevation is what says \"this is an object you can pick up\". Previously the\n // card shared the panel's fill and had no shadow, so it read as a table row.\n boxShadow: 'var(--shadow-elevation-1)',\n transition: 'box-shadow 0.15s ease, border-color 0.15s ease, background-color 0.15s ease',\n },\n // `--color-bg-hover` is not a token in the build — the undefined var made every\n // hover declaration in this file invalid, so there was no hover feedback at all.\n // `--color-action-ghost-bgHover` is the real per-theme hover fill (BOFF-5636).\n widgetCardHover: {\n backgroundColor: 'var(--color-action-ghost-bgHover)',\n borderColor: 'var(--color-action-primary-border)',\n boxShadow: 'var(--shadow-elevation-2)',\n },\n dragHandle: {\n width: '16px',\n height: '16px',\n color: 'var(--color-text-muted)',\n opacity: 0.5,\n flexShrink: 0,\n },\n widgetIcon: {\n width: '36px',\n height: '36px',\n borderRadius: 'var(--radius-button)',\n backgroundColor: 'var(--color-bg-sunken)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n },\n widgetIconInner: {\n width: '18px',\n height: '18px',\n color: 'var(--color-action-primary-bg)',\n },\n widgetText: {\n flex: 1,\n minWidth: 0,\n overflow: 'hidden',\n },\n widgetName: {\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)' as const,\n color: 'var(--color-text-primary)',\n whiteSpace: 'nowrap' as const,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n marginBottom: '2px',\n },\n widgetDescription: {\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-muted)',\n lineHeight: 1.3,\n overflow: 'hidden',\n display: '-webkit-box',\n WebkitLineClamp: 2,\n WebkitBoxOrient: 'vertical' as const,\n },\n emptyState: {\n textAlign: 'center' as const,\n padding: 'var(--space-pagePadding) var(--space-formGap)',\n backgroundColor: 'var(--color-status-info-bgSubtle)',\n border: '1px solid var(--color-status-info-border)',\n borderRadius: 'var(--radius-card)',\n },\n emptyIcon: {\n width: '48px',\n height: '48px',\n borderRadius: 'var(--radius-card)',\n backgroundColor: 'var(--color-bg-surface)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n margin: '0 auto var(--space-formGap)',\n },\n emptyTitle: {\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)' as const,\n color: 'var(--color-status-info-text)',\n margin: 0,\n },\n emptyText: {\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-secondary)',\n margin: 'var(--space-iconGap) 0 0 0',\n },\n clearButton: {\n marginTop: 'var(--space-controlGap)',\n minHeight: 'var(--size-controlHeight-md)',\n padding: '0 var(--space-formGap)',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)' as const,\n color: 'var(--color-action-primary-text)',\n backgroundColor: 'var(--color-action-primary-bg)',\n border: 'none',\n borderRadius: 'var(--radius-button)',\n cursor: 'pointer',\n },\n // Terminal band. Surface fill + a hairline, matching the header's rule rather\n // than repeating the sunken tray, so top and bottom are no longer identical.\n footer: {\n padding: 'var(--space-controlGap) var(--space-formGap)',\n borderTop: '1px solid var(--color-border-subtle)',\n backgroundColor: 'var(--color-bg-surface)',\n flexShrink: 0,\n },\n footerText: {\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-muted)',\n margin: 0,\n textAlign: 'center' as const,\n },\n browseStoreButton: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 'var(--space-iconGap)',\n width: '100%',\n minHeight: 'var(--size-controlHeight-md)',\n padding: 'var(--space-controlGap)',\n marginBottom: 'var(--space-controlGap)',\n borderRadius: 'var(--radius-button)',\n border: '1px dashed var(--color-border-subtle)',\n backgroundColor: 'transparent',\n color: 'var(--color-text-secondary)',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)' as const,\n cursor: 'pointer',\n transition: 'border-color 0.15s, color 0.15s',\n },\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const WidgetPalette: FC<WidgetPaletteProps> = memo(function WidgetPalette({\n isOpen,\n onClose,\n onWidgetSelect,\n onDragStart,\n onDragEnd,\n installedWidgets = [],\n installedWidgetsLoading = false,\n definitions,\n}) {\n const { t } = useI18n();\n const [searchQuery, setSearchQuery] = useState('');\n const [expandedCategories, setExpandedCategories] = useState<Set<WidgetCategory>>(\n new Set(['KPI', 'Visualization', 'Data', 'Content', 'Temporal', 'Custom', 'Installed'])\n );\n const [hoveredWidget, setHoveredWidget] = useState<string | null>(null);\n\n // Get categorized widgets, merging in installed widgets. When the parent\n // supplies a backend-sourced catalog (`definitions`), group that by category;\n // otherwise fall back to the bundled static registry.\n const categories = useMemo(() => {\n const baseCategories = definitions\n ? (Object.keys(WIDGET_CATEGORY_LABELS) as WidgetCategory[]).map((category) => ({\n category,\n label: WIDGET_CATEGORY_LABELS[category],\n widgets: definitions.filter((def) => def.category === category),\n }))\n : getWidgetCategories();\n\n return baseCategories\n .map((cat) => {\n if (cat.category === 'Installed') {\n // Two sources feed \"Installed from Store\": the registry-driven backend\n // catalog (getWidgetTypes store types — rich metadata, install-gated,\n // BOFF-2858) which arrives via `definitions` under this category, and\n // the legacy workspaceInstalledApps listing passed as `installedWidgets`.\n // Merge both, deduping by name (the catalog entry wins) so a widget\n // present in both sources shows once with the richer definition, while\n // legacy installs not yet in the registry are still preserved.\n const byName = new Map<string, WidgetDefinition>();\n for (const w of installedWidgets) byName.set(w.name.toLowerCase(), w);\n for (const w of cat.widgets) {\n const key = w.name.toLowerCase();\n const legacy = byName.get(key);\n // Catalog wins for metadata but MERGE defaultConfig so the legacy\n // workspaceInstalledApps fields survive — notably `componentId`, which the\n // current render path needs and the catalog store entry lacks until\n // widgetTypeKey rendering is wired. Keeps overlapping store widgets renderable.\n byName.set(key, legacy ? { ...w, defaultConfig: { ...legacy.defaultConfig, ...w.defaultConfig } } : w);\n }\n return { ...cat, widgets: Array.from(byName.values()) };\n }\n return cat;\n })\n .filter((cat) => cat.category !== 'Installed' || cat.widgets.length > 0);\n }, [installedWidgets, definitions]);\n\n // Filter widgets by search query\n const filteredCategories = useMemo(() => {\n if (!searchQuery.trim()) {\n return categories;\n }\n\n const query = searchQuery.toLowerCase();\n return categories\n .map((cat) => ({\n ...cat,\n widgets: cat.widgets.filter(\n (w) =>\n w.name.toLowerCase().includes(query) ||\n w.description.toLowerCase().includes(query) ||\n w.tags.some((tag) => tag.includes(query))\n ),\n }))\n .filter((cat) => cat.widgets.length > 0);\n }, [categories, searchQuery]);\n\n // Toggle category expansion\n const toggleCategory = useCallback((category: WidgetCategory) => {\n setExpandedCategories((prev) => {\n const next = new Set(prev);\n if (next.has(category)) {\n next.delete(category);\n } else {\n next.add(category);\n }\n return next;\n });\n }, []);\n\n // Handle drag start\n const handleDragStart = useCallback(\n (e: React.DragEvent, widget: WidgetDefinition) => {\n e.dataTransfer.setData(\n 'application/json',\n JSON.stringify({\n type: widget.type,\n name: widget.name,\n defaultSize: widget.defaultSize,\n defaultConfig: widget.defaultConfig,\n category: widget.category,\n })\n );\n e.dataTransfer.effectAllowed = 'copy';\n\n // Create custom drag image\n const dragImage = document.createElement('div');\n dragImage.style.cssText = `\n position: absolute;\n top: -1000px;\n left: -1000px;\n padding: 8px 12px;\n background: var(--color-bg-surface);\n border: 2px solid var(--color-action-primary-bg);\n border-radius: var(--radius-card);\n font-size: var(--font-size-body-sm);\n font-weight: 500;\n color: var(--color-text-primary);\n box-shadow: var(--shadow-elevation-3);\n `;\n dragImage.textContent = widget.name;\n document.body.appendChild(dragImage);\n e.dataTransfer.setDragImage(dragImage, 0, 0);\n\n setTimeout(() => {\n document.body.removeChild(dragImage);\n }, 0);\n\n onDragStart?.(widget.type, widget);\n },\n [onDragStart]\n );\n\n // Handle drag end\n const handleDragEnd = useCallback(() => {\n onDragEnd?.();\n }, [onDragEnd]);\n\n // Handle click to quick-add\n const handleWidgetClick = useCallback(\n (widget: WidgetDefinition) => {\n onWidgetSelect?.(widget.type, widget);\n },\n [onWidgetSelect]\n );\n\n // Open the widget store in a new tab so the builder (and any unsaved edits)\n // stays intact. Preserves the current org/workspace/project query params.\n const handleBrowseStore = useCallback(() => {\n if (typeof window === 'undefined') return;\n const url = `${window.location.origin}/bigconsole/store${window.location.search}`;\n window.open(url, '_blank', 'noopener,noreferrer');\n }, []);\n\n if (!isOpen) {\n return null;\n }\n\n return (\n <section\n aria-label=\"Widget palette\"\n data-testid=\"widget-palette\"\n style={styles.container}\n className=\"h-auto max-h-[45vh] w-full border-b border-[var(--color-border-subtle)] md:h-full md:max-h-none md:w-[300px] md:border-b-0 md:border-r\"\n >\n {/* Header — the panel's identity band */}\n <div style={styles.header}>\n <div style={styles.headerTop}>\n <div style={styles.headerTitle}>\n <div style={styles.headerIcon}>\n <Layers\n aria-hidden=\"true\"\n style={{ width: '18px', height: '18px', color: 'var(--color-action-primary-text)' }}\n />\n </div>\n <div>\n <h2 style={styles.title}>{t('bigconsole.dashboards.widgetPalette.title', 'Widgets')}</h2>\n <p style={styles.subtitle}>{t('bigconsole.dashboards.widgetPalette.subtitle', 'Drag or click to add')}</p>\n </div>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close widget palette\"\n title=\"Close widget palette\"\n style={styles.closeButton}\n className={`hover:bg-action-ghost-bgHover motion-safe:transition-colors ${SECTION_FOCUS_RING}`}\n >\n <X aria-hidden=\"true\" style={{ width: '16px', height: '16px' }} />\n </button>\n </div>\n\n {/* Search */}\n <div style={styles.searchContainer}>\n <label htmlFor=\"widget-palette-search\" className=\"sr-only\">\n Search widgets\n </label>\n <Search aria-hidden=\"true\" style={styles.searchIcon} />\n <Input\n id=\"widget-palette-search\"\n type=\"text\"\n placeholder={t('bigconsole.dashboards.widgetPalette.searchPlaceholder', 'Search widgets...')}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n style={styles.searchInput}\n />\n </div>\n </div>\n\n {/* Widget Categories — recessed tray */}\n <div style={styles.content}>\n <div style={styles.scrollArea}>\n {filteredCategories.map((category) => {\n const isExpanded = expandedCategories.has(category.category);\n const panelId = `widget-palette-${category.category.toLowerCase()}`;\n return (\n <div key={category.category} style={styles.categoryContainer}>\n {/* Category Header */}\n <h3 style={styles.categoryHeading}>\n <button\n type=\"button\"\n onClick={() => toggleCategory(category.category)}\n aria-expanded={isExpanded}\n aria-controls={panelId}\n style={styles.categoryHeader}\n className={`hover:bg-action-ghost-bgHover motion-safe:transition-colors ${SECTION_FOCUS_RING}`}\n >\n {isExpanded ? (\n <ChevronDown aria-hidden=\"true\" style={styles.categoryChevron} />\n ) : (\n <ChevronRight aria-hidden=\"true\" style={styles.categoryChevron} />\n )}\n <span style={styles.categoryLabel}>{category.label}</span>\n <span style={styles.categoryCount}>{category.widgets.length}</span>\n </button>\n </h3>\n\n {/* Widget Items */}\n {isExpanded && (\n <div id={panelId} style={styles.widgetList}>\n {installedWidgetsLoading && category.category === 'Installed' && (\n <div\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-muted)',\n padding: 'var(--space-controlGap)',\n }}\n >\n {t('bigconsole.dashboards.widgetPalette.loading', 'Loading...')}\n </div>\n )}\n {category.widgets.map((widget) => {\n const IconComponent = getIconComponent(widget.icon);\n const widgetKey = getWidgetKey(widget);\n const isHovered = hoveredWidget === widgetKey;\n\n return (\n <div\n key={widgetKey}\n draggable\n role=\"button\"\n tabIndex={0}\n aria-label={`Add ${widget.name} widget`}\n onDragStart={(e) => handleDragStart(e, widget)}\n onDragEnd={handleDragEnd}\n onClick={() => handleWidgetClick(widget)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleWidgetClick(widget);\n }\n }}\n onMouseEnter={() => setHoveredWidget(widgetKey)}\n onMouseLeave={() => setHoveredWidget(null)}\n className={SECTION_FOCUS_RING}\n style={{\n ...styles.widgetCard,\n ...(isHovered ? styles.widgetCardHover : {}),\n }}\n >\n {/* Drag Handle */}\n <GripVertical aria-hidden=\"true\" style={styles.dragHandle} />\n\n {/* Icon */}\n <div style={styles.widgetIcon}>\n <IconComponent aria-hidden=\"true\" style={styles.widgetIconInner} />\n </div>\n\n {/* Text */}\n <div style={styles.widgetText}>\n <div style={styles.widgetName}>{widget.name}</div>\n <div style={styles.widgetDescription}>{widget.description}</div>\n </div>\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n })}\n\n {filteredCategories.length === 0 && (\n <div style={styles.emptyState} role=\"status\">\n <div style={styles.emptyIcon}>\n <Search\n aria-hidden=\"true\"\n style={{ width: '24px', height: '24px', color: 'var(--color-text-muted)' }}\n />\n </div>\n <p style={styles.emptyTitle}>\n {t('bigconsole.dashboards.widgetPalette.noResultsBefore', 'No widgets found for')} &ldquo;\n <strong>{searchQuery}</strong>&rdquo;\n </p>\n {/* No catalog key exists for this hint — literal until one lands in\n src/translations/en.ts. */}\n <p style={styles.emptyText}>Try a shorter term, or browse the widget store for more types.</p>\n <button\n type=\"button\"\n onClick={() => setSearchQuery('')}\n style={styles.clearButton}\n className={SECTION_FOCUS_RING}\n >\n {t('bigconsole.dashboards.widgetPalette.clearSearch', 'Clear search')}\n </button>\n </div>\n )}\n </div>\n </div>\n\n {/* Footer — terminal band */}\n <div style={styles.footer}>\n <button\n type=\"button\"\n onClick={handleBrowseStore}\n style={styles.browseStoreButton}\n className={`hover:border-action-primary-bg hover:text-action-primary-text motion-safe:transition-colors ${SECTION_FOCUS_RING}`}\n >\n <Store aria-hidden=\"true\" style={{ width: '15px', height: '15px' }} />\n {t('bigconsole.dashboards.widgetPalette.browseStore', 'Browse widget store')}\n <ExternalLink aria-hidden=\"true\" style={{ width: '13px', height: '13px', opacity: 0.7 }} />\n </button>\n <p style={styles.footerText}>\n {t('bigconsole.dashboards.widgetPalette.footerHint', 'Drag widgets to position them on the canvas')}\n </p>\n </div>\n </section>\n );\n});\n\nexport default WidgetPalette;\n"],"mappings":"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"}
@@ -73,7 +73,7 @@ var f = e(function({ value: e, onChange: u, disabled: f = !1, error: p, hideLabe
73
73
  C(null), u(n);
74
74
  }, [u, h]);
75
75
  return /* @__PURE__ */ l("div", {
76
- className: "space-y-3",
76
+ className: "space-y-form-gap",
77
77
  children: [
78
78
  !m && /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
79
79
  className: "block text-sm font-medium text-text-primary mb-1",
@@ -83,16 +83,17 @@ var f = e(function({ value: e, onChange: u, disabled: f = !1, error: p, hideLabe
83
83
  children: h("bigconsole.dataSinks.cacheTtl.headingDescription", "How long should data be cached before refreshing?")
84
84
  })] }),
85
85
  /* @__PURE__ */ l("div", {
86
- className: "space-y-2",
86
+ role: "group",
87
+ "aria-label": h("bigconsole.dataSinks.cacheTtl.heading", "Cache Duration"),
88
+ className: "space-y-list-gap",
87
89
  children: [g.map((t) => /* @__PURE__ */ l("label", {
88
90
  className: `
89
- flex items-start gap-3
90
- p-3
91
- border rounded-lg
92
- cursor-pointer
93
- transition-all
94
- ${f ? "opacity-50 cursor-not-allowed" : ""}
95
- ${!v && e === t.value ? "border-action-primary-bg bg-action-primary-bg/5" : "border-border-default hover:border-border-hover"}
91
+ flex cursor-pointer items-start gap-3
92
+ rounded-input
93
+ border p-3
94
+ motion-safe:transition-colors
95
+ ${f ? "cursor-not-allowed opacity-50" : ""}
96
+ ${!v && e === t.value ? "border-[var(--color-action-primary-bg)] bg-bg-accentSubtle" : "border-[var(--color-border-subtle)] hover:border-[var(--color-border-strong)]"}
96
97
  `,
97
98
  children: [/* @__PURE__ */ c("input", {
98
99
  type: "radio",
@@ -100,7 +101,7 @@ var f = e(function({ value: e, onChange: u, disabled: f = !1, error: p, hideLabe
100
101
  checked: !v && e === t.value,
101
102
  onChange: () => T(t.value),
102
103
  disabled: f,
103
- className: "\n mt-0.5\n w-4 h-4\n text-action-primary-bg\n border-border-default\n focus:ring-action-primary-bg\n focus:ring-offset-0\n "
104
+ className: "\n mt-0.5\n h-4 w-4\n border-[var(--color-border-default)]\n text-action-primary-bg\n focus-visible:ring-2\n focus-visible:ring-ring\n "
104
105
  }), /* @__PURE__ */ l("div", {
105
106
  className: "flex-1",
106
107
  children: [/* @__PURE__ */ l("div", {
@@ -119,13 +120,12 @@ var f = e(function({ value: e, onChange: u, disabled: f = !1, error: p, hideLabe
119
120
  })]
120
121
  }, t.value)), /* @__PURE__ */ l("label", {
121
122
  className: `
122
- flex items-start gap-3
123
- p-3
124
- border rounded-lg
125
- cursor-pointer
126
- transition-all
127
- ${f ? "opacity-50 cursor-not-allowed" : ""}
128
- ${v ? "border-action-primary-bg bg-action-primary-bg/5" : "border-border-default hover:border-border-hover"}
123
+ flex cursor-pointer items-start gap-3
124
+ rounded-input
125
+ border p-3
126
+ motion-safe:transition-colors
127
+ ${f ? "cursor-not-allowed opacity-50" : ""}
128
+ ${v ? "border-[var(--color-action-primary-bg)] bg-bg-accentSubtle" : "border-[var(--color-border-subtle)] hover:border-[var(--color-border-strong)]"}
129
129
  `,
130
130
  children: [/* @__PURE__ */ c("input", {
131
131
  type: "radio",
@@ -133,7 +133,7 @@ var f = e(function({ value: e, onChange: u, disabled: f = !1, error: p, hideLabe
133
133
  checked: v,
134
134
  onChange: E,
135
135
  disabled: f,
136
- className: "\n mt-0.5\n w-4 h-4\n text-action-primary-bg\n border-border-default\n focus:ring-action-primary-bg\n focus:ring-offset-0\n "
136
+ className: "\n mt-0.5\n h-4 w-4\n border-[var(--color-border-default)]\n text-action-primary-bg\n focus-visible:ring-2\n focus-visible:ring-ring\n "
137
137
  }), /* @__PURE__ */ l("div", {
138
138
  className: "flex-1",
139
139
  children: [
@@ -146,10 +146,11 @@ var f = e(function({ value: e, onChange: u, disabled: f = !1, error: p, hideLabe
146
146
  children: h("bigconsole.dataSinks.cacheTtl.customDescription", "Enter a custom cache duration (30 - 86400 seconds)")
147
147
  }),
148
148
  v && /* @__PURE__ */ l(s, { children: [/* @__PURE__ */ l("div", {
149
- className: "mt-3 flex items-center gap-2",
149
+ className: "mt-3 flex flex-wrap items-center gap-2",
150
150
  children: [
151
151
  /* @__PURE__ */ c("input", {
152
152
  type: "number",
153
+ "aria-label": "Custom cache duration in seconds",
153
154
  value: b,
154
155
  onChange: D,
155
156
  disabled: f,
@@ -157,16 +158,15 @@ var f = e(function({ value: e, onChange: u, disabled: f = !1, error: p, hideLabe
157
158
  max: 86400,
158
159
  placeholder: "300",
159
160
  className: `
160
- w-32 px-3 py-2
161
- bg-bg-sunken
162
- border rounded-md
161
+ h-control-md w-full min-w-0 rounded-input
162
+ border bg-bg-sunken
163
+ px-3
163
164
  text-sm text-text-primary
164
- placeholder-text-tertiary
165
- focus:outline-none
166
- focus:border-action-primary-bg
167
- focus:ring-2
168
- focus:ring-action-primary-bg/20
169
- ${p || S ? "border-status-error-border" : "border-border-default"}
165
+ focus-visible:outline-none
166
+ focus-visible:ring-2
167
+ focus-visible:ring-ring
168
+ sm:w-32
169
+ ${p || S ? "border-[var(--color-status-error-border)]" : "border-[var(--color-border-default)]"}
170
170
  `
171
171
  }),
172
172
  /* @__PURE__ */ c("span", {
@@ -174,7 +174,7 @@ var f = e(function({ value: e, onChange: u, disabled: f = !1, error: p, hideLabe
174
174
  children: h("bigconsole.dataSinks.cacheTtl.secondsUnit", "seconds")
175
175
  }),
176
176
  b && !isNaN(parseInt(b)) && !S && /* @__PURE__ */ l("span", {
177
- className: "text-xs text-text-tertiary",
177
+ className: "text-xs text-text-muted",
178
178
  children: [
179
179
  "(",
180
180
  _(parseInt(b)),
@@ -1 +1 @@
1
- {"version":3,"file":"CacheTTLSelector.js","names":[],"sources":["../../../../src/bigconsole/components/datasink/CacheTTLSelector.tsx"],"sourcesContent":["/**\n * Cache TTL Selector\n *\n * Component for selecting cache duration with preset options and custom input.\n */\n\nimport { memo, useState, useEffect, useCallback, useMemo, useRef } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface CacheTTLOption {\n value: number;\n label: string;\n description: string;\n recommended?: boolean;\n}\n\ninterface CacheTTLSelectorProps {\n /** Current TTL value in seconds (null for no cache) */\n value: number | null;\n /** Callback when value changes */\n onChange: (value: number) => void;\n /** Whether selector is disabled */\n disabled?: boolean;\n /** Error message */\n error?: string;\n /**\n * Hide the built-in \"Cache Duration\" heading + description. Use when the\n * surrounding form already renders its own label for this control, to avoid a\n * duplicated heading.\n */\n hideLabel?: boolean;\n}\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst PRESET_VALUES: number[] = [300, 900, 3600, 86400];\n\n// ============================================================================\n// HELPERS\n// ============================================================================\n\n/**\n * Check if value is a preset option\n */\nfunction isPresetValue(value: number | null): boolean {\n if (value === null) return false;\n return PRESET_VALUES.includes(value);\n}\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const CacheTTLSelector = memo(function CacheTTLSelector({\n value,\n onChange,\n disabled = false,\n error,\n hideLabel = false,\n}: CacheTTLSelectorProps) {\n const { t } = useI18n();\n\n const PRESET_OPTIONS = useMemo<CacheTTLOption[]>(\n () => [\n {\n value: 300, // 5 minutes\n label: t('bigconsole.dataSinks.cacheTtl.preset5MinutesLabel', '5 minutes'),\n description: t('bigconsole.dataSinks.cacheTtl.preset5MinutesDescription', 'Best for real-time dashboards'),\n },\n {\n value: 900, // 15 minutes\n label: t('bigconsole.dataSinks.cacheTtl.preset15MinutesLabel', '15 minutes'),\n description: t('bigconsole.dataSinks.cacheTtl.preset15MinutesDescription', 'Balanced performance'),\n recommended: true,\n },\n {\n value: 3600, // 1 hour\n label: t('bigconsole.dataSinks.cacheTtl.preset1HourLabel', '1 hour'),\n description: t('bigconsole.dataSinks.cacheTtl.preset1HourDescription', 'For data that changes hourly'),\n },\n {\n value: 86400, // 24 hours\n label: t('bigconsole.dataSinks.cacheTtl.preset24HoursLabel', '24 hours'),\n description: t('bigconsole.dataSinks.cacheTtl.preset24HoursDescription', 'For daily reports'),\n },\n ],\n [t]\n );\n\n // Format seconds to human-readable string\n const formatDuration = useCallback(\n (seconds: number): string => {\n if (seconds < 60) {\n return t('bigconsole.dataSinks.cacheTtl.durationSeconds', '{{count}} seconds', { count: seconds });\n }\n if (seconds < 3600) {\n return t('bigconsole.dataSinks.cacheTtl.durationMinutes', '{{count}} minutes', {\n count: Math.floor(seconds / 60),\n });\n }\n if (seconds < 86400) {\n return t('bigconsole.dataSinks.cacheTtl.durationHours', '{{count}} hours', {\n count: Math.floor(seconds / 3600),\n });\n }\n return t('bigconsole.dataSinks.cacheTtl.durationDays', '{{count}} days', {\n count: Math.floor(seconds / 86400),\n });\n },\n [t]\n );\n\n // Track whether custom mode is active\n const [isCustom, setIsCustom] = useState(!isPresetValue(value) && value !== null);\n const [customValue, setCustomValue] = useState(value?.toString() || '');\n const [validationError, setValidationError] = useState<string | null>(null);\n const prevValueRef = useRef(value);\n\n // Sync custom value when external value changes (using deferred update to avoid cascading renders)\n useEffect(() => {\n if (prevValueRef.current !== value) {\n prevValueRef.current = value;\n if (value !== null && !isPresetValue(value)) {\n // Defer state update to avoid synchronous setState in effect\n queueMicrotask(() => {\n setCustomValue(value.toString());\n setIsCustom(true);\n });\n }\n }\n }, [value]);\n\n // Handle preset selection\n const handlePresetChange = useCallback(\n (presetValue: number) => {\n if (disabled) return;\n setIsCustom(false);\n onChange(presetValue);\n },\n [disabled, onChange]\n );\n\n // Handle custom mode activation\n const handleCustomSelect = useCallback(() => {\n if (disabled) return;\n setIsCustom(true);\n const parsed = parseInt(customValue);\n if (!isNaN(parsed) && parsed >= 30 && parsed <= 86400) {\n onChange(parsed);\n }\n }, [disabled, customValue, onChange]);\n\n // Handle custom value change with validation\n const handleCustomChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const inputValue = e.target.value;\n setCustomValue(inputValue);\n\n // Validate input\n if (inputValue === '') {\n setValidationError(null);\n return;\n }\n\n const parsed = parseInt(inputValue);\n\n if (isNaN(parsed)) {\n setValidationError(t('bigconsole.dataSinks.cacheTtl.errorInvalidNumber', 'Please enter a valid number'));\n return;\n }\n\n if (parsed < 30) {\n setValidationError(t('bigconsole.dataSinks.cacheTtl.errorMinDuration', 'Minimum cache duration is 30 seconds'));\n return;\n }\n\n if (parsed > 86400) {\n setValidationError(\n t('bigconsole.dataSinks.cacheTtl.errorMaxDuration', 'Maximum cache duration is 86400 seconds (24 hours)')\n );\n return;\n }\n\n // Valid value\n setValidationError(null);\n onChange(parsed);\n },\n [onChange, t]\n );\n\n return (\n <div className=\"space-y-3\">\n {/* Label (optional — hidden when the surrounding form supplies its own) */}\n {!hideLabel && (\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {t('bigconsole.dataSinks.cacheTtl.heading', 'Cache Duration')}\n </label>\n <p className=\"text-xs text-text-secondary\">\n {t('bigconsole.dataSinks.cacheTtl.headingDescription', 'How long should data be cached before refreshing?')}\n </p>\n </div>\n )}\n\n {/* Options */}\n <div className=\"space-y-2\">\n {/* Preset options */}\n {PRESET_OPTIONS.map((option) => (\n <label\n key={option.value}\n className={`\n flex items-start gap-3\n p-3\n border rounded-lg\n cursor-pointer\n transition-all\n ${disabled ? 'opacity-50 cursor-not-allowed' : ''}\n ${\n !isCustom && value === option.value\n ? 'border-action-primary-bg bg-action-primary-bg/5'\n : 'border-border-default hover:border-border-hover'\n }\n `}\n >\n <input\n type=\"radio\"\n name=\"cache-ttl\"\n checked={!isCustom && value === option.value}\n onChange={() => handlePresetChange(option.value)}\n disabled={disabled}\n className={`\n mt-0.5\n w-4 h-4\n text-action-primary-bg\n border-border-default\n focus:ring-action-primary-bg\n focus:ring-offset-0\n `}\n />\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium text-text-primary\">{option.label}</span>\n {option.recommended && (\n <span className=\"px-1.5 py-0.5 text-xs font-medium bg-action-primary-bg/10 text-action-primary-bg rounded\">\n {t('bigconsole.dataSinks.cacheTtl.recommendedBadge', 'Recommended')}\n </span>\n )}\n </div>\n <p className=\"text-xs text-text-secondary mt-0.5\">{option.description}</p>\n </div>\n </label>\n ))}\n\n {/* Custom option */}\n <label\n className={`\n flex items-start gap-3\n p-3\n border rounded-lg\n cursor-pointer\n transition-all\n ${disabled ? 'opacity-50 cursor-not-allowed' : ''}\n ${\n isCustom\n ? 'border-action-primary-bg bg-action-primary-bg/5'\n : 'border-border-default hover:border-border-hover'\n }\n `}\n >\n <input\n type=\"radio\"\n name=\"cache-ttl\"\n checked={isCustom}\n onChange={handleCustomSelect}\n disabled={disabled}\n className={`\n mt-0.5\n w-4 h-4\n text-action-primary-bg\n border-border-default\n focus:ring-action-primary-bg\n focus:ring-offset-0\n `}\n />\n <div className=\"flex-1\">\n <span className=\"text-sm font-medium text-text-primary\">\n {t('bigconsole.dataSinks.cacheTtl.customLabel', 'Custom')}\n </span>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {t(\n 'bigconsole.dataSinks.cacheTtl.customDescription',\n 'Enter a custom cache duration (30 - 86400 seconds)'\n )}\n </p>\n {isCustom && (\n <>\n <div className=\"mt-3 flex items-center gap-2\">\n <input\n type=\"number\"\n value={customValue}\n onChange={handleCustomChange}\n disabled={disabled}\n min={30}\n max={86400}\n placeholder=\"300\"\n className={`\n w-32 px-3 py-2\n bg-bg-sunken\n border rounded-md\n text-sm text-text-primary\n placeholder-text-tertiary\n focus:outline-none\n focus:border-action-primary-bg\n focus:ring-2\n focus:ring-action-primary-bg/20\n ${error || validationError ? 'border-status-error-border' : 'border-border-default'}\n `}\n />\n <span className=\"text-sm text-text-secondary\">\n {t('bigconsole.dataSinks.cacheTtl.secondsUnit', 'seconds')}\n </span>\n {customValue && !isNaN(parseInt(customValue)) && !validationError && (\n <span className=\"text-xs text-text-tertiary\">({formatDuration(parseInt(customValue))})</span>\n )}\n </div>\n {validationError && (\n <div className=\"flex items-center gap-1 mt-1\">\n <svg\n className=\"w-3.5 h-3.5 text-status-error-text flex-shrink-0\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n <span className=\"text-xs text-status-error-text\">{validationError}</span>\n </div>\n )}\n </>\n )}\n </div>\n </label>\n </div>\n\n {/* Error message */}\n {error && (\n <div className=\"flex items-start gap-2\">\n <svg\n className=\"w-4 h-4 text-status-error-text flex-shrink-0 mt-0.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n <p className=\"text-xs text-status-error-text\">{error}</p>\n </div>\n )}\n\n {/* Info message */}\n {value !== null && !error && (\n <div className=\"flex items-center gap-2 text-xs text-text-secondary\">\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n <span>\n {t(\n 'bigconsole.dataSinks.cacheTtl.infoCachedFor',\n 'Data will be cached for {{duration}} before being refreshed',\n {\n duration: formatDuration(value),\n }\n )}\n </span>\n </div>\n )}\n </div>\n );\n});\n\nexport default CacheTTLSelector;\n"],"mappings":"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"}
1
+ {"version":3,"file":"CacheTTLSelector.js","names":[],"sources":["../../../../src/bigconsole/components/datasink/CacheTTLSelector.tsx"],"sourcesContent":["/**\n * Cache TTL Selector\n *\n * Component for selecting cache duration with preset options and custom input.\n */\n\nimport { memo, useState, useEffect, useCallback, useMemo, useRef } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface CacheTTLOption {\n value: number;\n label: string;\n description: string;\n recommended?: boolean;\n}\n\ninterface CacheTTLSelectorProps {\n /** Current TTL value in seconds (null for no cache) */\n value: number | null;\n /** Callback when value changes */\n onChange: (value: number) => void;\n /** Whether selector is disabled */\n disabled?: boolean;\n /** Error message */\n error?: string;\n /**\n * Hide the built-in \"Cache Duration\" heading + description. Use when the\n * surrounding form already renders its own label for this control, to avoid a\n * duplicated heading.\n */\n hideLabel?: boolean;\n}\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst PRESET_VALUES: number[] = [300, 900, 3600, 86400];\n\n// ============================================================================\n// HELPERS\n// ============================================================================\n\n/**\n * Check if value is a preset option\n */\nfunction isPresetValue(value: number | null): boolean {\n if (value === null) return false;\n return PRESET_VALUES.includes(value);\n}\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const CacheTTLSelector = memo(function CacheTTLSelector({\n value,\n onChange,\n disabled = false,\n error,\n hideLabel = false,\n}: CacheTTLSelectorProps) {\n const { t } = useI18n();\n\n const PRESET_OPTIONS = useMemo<CacheTTLOption[]>(\n () => [\n {\n value: 300, // 5 minutes\n label: t('bigconsole.dataSinks.cacheTtl.preset5MinutesLabel', '5 minutes'),\n description: t('bigconsole.dataSinks.cacheTtl.preset5MinutesDescription', 'Best for real-time dashboards'),\n },\n {\n value: 900, // 15 minutes\n label: t('bigconsole.dataSinks.cacheTtl.preset15MinutesLabel', '15 minutes'),\n description: t('bigconsole.dataSinks.cacheTtl.preset15MinutesDescription', 'Balanced performance'),\n recommended: true,\n },\n {\n value: 3600, // 1 hour\n label: t('bigconsole.dataSinks.cacheTtl.preset1HourLabel', '1 hour'),\n description: t('bigconsole.dataSinks.cacheTtl.preset1HourDescription', 'For data that changes hourly'),\n },\n {\n value: 86400, // 24 hours\n label: t('bigconsole.dataSinks.cacheTtl.preset24HoursLabel', '24 hours'),\n description: t('bigconsole.dataSinks.cacheTtl.preset24HoursDescription', 'For daily reports'),\n },\n ],\n [t]\n );\n\n // Format seconds to human-readable string\n const formatDuration = useCallback(\n (seconds: number): string => {\n if (seconds < 60) {\n return t('bigconsole.dataSinks.cacheTtl.durationSeconds', '{{count}} seconds', { count: seconds });\n }\n if (seconds < 3600) {\n return t('bigconsole.dataSinks.cacheTtl.durationMinutes', '{{count}} minutes', {\n count: Math.floor(seconds / 60),\n });\n }\n if (seconds < 86400) {\n return t('bigconsole.dataSinks.cacheTtl.durationHours', '{{count}} hours', {\n count: Math.floor(seconds / 3600),\n });\n }\n return t('bigconsole.dataSinks.cacheTtl.durationDays', '{{count}} days', {\n count: Math.floor(seconds / 86400),\n });\n },\n [t]\n );\n\n // Track whether custom mode is active\n const [isCustom, setIsCustom] = useState(!isPresetValue(value) && value !== null);\n const [customValue, setCustomValue] = useState(value?.toString() || '');\n const [validationError, setValidationError] = useState<string | null>(null);\n const prevValueRef = useRef(value);\n\n // Sync custom value when external value changes (using deferred update to avoid cascading renders)\n useEffect(() => {\n if (prevValueRef.current !== value) {\n prevValueRef.current = value;\n if (value !== null && !isPresetValue(value)) {\n // Defer state update to avoid synchronous setState in effect\n queueMicrotask(() => {\n setCustomValue(value.toString());\n setIsCustom(true);\n });\n }\n }\n }, [value]);\n\n // Handle preset selection\n const handlePresetChange = useCallback(\n (presetValue: number) => {\n if (disabled) return;\n setIsCustom(false);\n onChange(presetValue);\n },\n [disabled, onChange]\n );\n\n // Handle custom mode activation\n const handleCustomSelect = useCallback(() => {\n if (disabled) return;\n setIsCustom(true);\n const parsed = parseInt(customValue);\n if (!isNaN(parsed) && parsed >= 30 && parsed <= 86400) {\n onChange(parsed);\n }\n }, [disabled, customValue, onChange]);\n\n // Handle custom value change with validation\n const handleCustomChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const inputValue = e.target.value;\n setCustomValue(inputValue);\n\n // Validate input\n if (inputValue === '') {\n setValidationError(null);\n return;\n }\n\n const parsed = parseInt(inputValue);\n\n if (isNaN(parsed)) {\n setValidationError(t('bigconsole.dataSinks.cacheTtl.errorInvalidNumber', 'Please enter a valid number'));\n return;\n }\n\n if (parsed < 30) {\n setValidationError(t('bigconsole.dataSinks.cacheTtl.errorMinDuration', 'Minimum cache duration is 30 seconds'));\n return;\n }\n\n if (parsed > 86400) {\n setValidationError(\n t('bigconsole.dataSinks.cacheTtl.errorMaxDuration', 'Maximum cache duration is 86400 seconds (24 hours)')\n );\n return;\n }\n\n // Valid value\n setValidationError(null);\n onChange(parsed);\n },\n [onChange, t]\n );\n\n return (\n <div className=\"space-y-form-gap\">\n {/* Label — suppressed with `hideLabel` when the surrounding form already\n renders one for this control, so the section never shows a duplicated\n heading. The `role=\"group\"` name below keeps the control set announced\n to assistive tech either way. */}\n {!hideLabel && (\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {t('bigconsole.dataSinks.cacheTtl.heading', 'Cache Duration')}\n </label>\n <p className=\"text-xs text-text-secondary\">\n {t('bigconsole.dataSinks.cacheTtl.headingDescription', 'How long should data be cached before refreshing?')}\n </p>\n </div>\n )}\n\n {/* Options */}\n <div\n role=\"group\"\n aria-label={t('bigconsole.dataSinks.cacheTtl.heading', 'Cache Duration')}\n className=\"space-y-list-gap\"\n >\n {/* Preset options */}\n {PRESET_OPTIONS.map((option) => (\n <label\n key={option.value}\n className={`\n flex cursor-pointer items-start gap-3\n rounded-input\n border p-3\n motion-safe:transition-colors\n ${disabled ? 'cursor-not-allowed opacity-50' : ''}\n ${\n !isCustom && value === option.value\n ? 'border-[var(--color-action-primary-bg)] bg-bg-accentSubtle'\n : 'border-[var(--color-border-subtle)] hover:border-[var(--color-border-strong)]'\n }\n `}\n >\n <input\n type=\"radio\"\n name=\"cache-ttl\"\n checked={!isCustom && value === option.value}\n onChange={() => handlePresetChange(option.value)}\n disabled={disabled}\n className={`\n mt-0.5\n h-4 w-4\n border-[var(--color-border-default)]\n text-action-primary-bg\n focus-visible:ring-2\n focus-visible:ring-ring\n `}\n />\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium text-text-primary\">{option.label}</span>\n {option.recommended && (\n <span className=\"px-1.5 py-0.5 text-xs font-medium bg-action-primary-bg/10 text-action-primary-bg rounded\">\n {t('bigconsole.dataSinks.cacheTtl.recommendedBadge', 'Recommended')}\n </span>\n )}\n </div>\n <p className=\"text-xs text-text-secondary mt-0.5\">{option.description}</p>\n </div>\n </label>\n ))}\n\n {/* Custom option */}\n <label\n className={`\n flex cursor-pointer items-start gap-3\n rounded-input\n border p-3\n motion-safe:transition-colors\n ${disabled ? 'cursor-not-allowed opacity-50' : ''}\n ${\n isCustom\n ? 'border-[var(--color-action-primary-bg)] bg-bg-accentSubtle'\n : 'border-[var(--color-border-subtle)] hover:border-[var(--color-border-strong)]'\n }\n `}\n >\n <input\n type=\"radio\"\n name=\"cache-ttl\"\n checked={isCustom}\n onChange={handleCustomSelect}\n disabled={disabled}\n className={`\n mt-0.5\n h-4 w-4\n border-[var(--color-border-default)]\n text-action-primary-bg\n focus-visible:ring-2\n focus-visible:ring-ring\n `}\n />\n <div className=\"flex-1\">\n <span className=\"text-sm font-medium text-text-primary\">\n {t('bigconsole.dataSinks.cacheTtl.customLabel', 'Custom')}\n </span>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {t(\n 'bigconsole.dataSinks.cacheTtl.customDescription',\n 'Enter a custom cache duration (30 - 86400 seconds)'\n )}\n </p>\n {isCustom && (\n <>\n <div className=\"mt-3 flex flex-wrap items-center gap-2\">\n <input\n type=\"number\"\n aria-label=\"Custom cache duration in seconds\"\n value={customValue}\n onChange={handleCustomChange}\n disabled={disabled}\n min={30}\n max={86400}\n placeholder=\"300\"\n className={`\n h-control-md w-full min-w-0 rounded-input\n border bg-bg-sunken\n px-3\n text-sm text-text-primary\n focus-visible:outline-none\n focus-visible:ring-2\n focus-visible:ring-ring\n sm:w-32\n ${error || validationError ? 'border-[var(--color-status-error-border)]' : 'border-[var(--color-border-default)]'}\n `}\n />\n <span className=\"text-sm text-text-secondary\">\n {t('bigconsole.dataSinks.cacheTtl.secondsUnit', 'seconds')}\n </span>\n {customValue && !isNaN(parseInt(customValue)) && !validationError && (\n <span className=\"text-xs text-text-muted\">({formatDuration(parseInt(customValue))})</span>\n )}\n </div>\n {validationError && (\n <div className=\"flex items-center gap-1 mt-1\">\n <svg\n className=\"w-3.5 h-3.5 text-status-error-text flex-shrink-0\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n <span className=\"text-xs text-status-error-text\">{validationError}</span>\n </div>\n )}\n </>\n )}\n </div>\n </label>\n </div>\n\n {/* Error message */}\n {error && (\n <div className=\"flex items-start gap-2\">\n <svg\n className=\"w-4 h-4 text-status-error-text flex-shrink-0 mt-0.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n <p className=\"text-xs text-status-error-text\">{error}</p>\n </div>\n )}\n\n {/* Info message */}\n {value !== null && !error && (\n <div className=\"flex items-center gap-2 text-xs text-text-secondary\">\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n <span>\n {t(\n 'bigconsole.dataSinks.cacheTtl.infoCachedFor',\n 'Data will be cached for {{duration}} before being refreshed',\n {\n duration: formatDuration(value),\n }\n )}\n </span>\n </div>\n )}\n </div>\n );\n});\n\nexport default CacheTTLSelector;\n"],"mappings":"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"}
@@ -1,129 +1,128 @@
1
- import e from "./DataSinkStatusBadge.js";
2
- import { memo as t, useCallback as n } from "react";
3
- import { jsx as r, jsxs as i } from "react/jsx-runtime";
4
- import { formatDistanceToNow as a } from "date-fns";
1
+ import { SECTION_FOCUS_RING as e } from "../common/sectionStyles.js";
2
+ import "../common/index.js";
3
+ import t from "./DataSinkStatusBadge.js";
4
+ import { memo as n, useCallback as r } from "react";
5
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
6
+ import { formatDistanceToNow as o } from "date-fns";
5
7
  //#region src/bigconsole/components/datasink/DataSinkCard.tsx
6
- var o = t(function({ dataSink: t, setupState: o, onView: s, onEdit: c, onRefresh: l, onExport: u, onDelete: d, onContinueSetup: f, canEdit: p = !0, canRefresh: m = !0, canDelete: h = !0 }) {
7
- let g = n((e) => {
8
- e.stopPropagation(), s?.(t.id);
9
- }, [t.id, s]), _ = n((e) => {
10
- e.stopPropagation(), c?.(t.id);
11
- }, [t.id, c]), v = n((e) => {
12
- e.stopPropagation(), l?.(t.id);
13
- }, [t.id, l]), y = n((e) => {
14
- e.stopPropagation(), u?.(t.id);
15
- }, [t.id, u]), b = n((e) => {
16
- e.stopPropagation(), d?.(t.id);
17
- }, [t.id, d]), x = n((e) => {
18
- e.stopPropagation(), f?.(t.id);
19
- }, [t.id, f]), S = (o ?? t.setupState) === "completed", C = t.lastRefreshedAt ? a(new Date(t.lastRefreshedAt), { addSuffix: !0 }) : "Never";
20
- return /* @__PURE__ */ i("div", {
21
- className: "\n p-4\n bg-bg-surface\n border border-border-default\n rounded-lg\n hover:border-action-primary-bg/50\n transition-colors\n cursor-pointer\n ",
22
- onClick: g,
8
+ var s = `inline-flex min-h-[var(--size-controlHeight-md)] items-center justify-center rounded-button px-3 py-1.5 text-xs font-medium motion-safe:transition-colors ${e}`, c = n(function({ dataSink: e, setupState: n, onView: c, onEdit: l, onRefresh: u, onExport: d, onDelete: f, onContinueSetup: p, canEdit: m = !0, canRefresh: h = !0, canDelete: g = !0 }) {
9
+ let _ = r((t) => {
10
+ t.stopPropagation(), c?.(e.id);
11
+ }, [e.id, c]), v = r((t) => {
12
+ t.stopPropagation(), l?.(e.id);
13
+ }, [e.id, l]), y = r((t) => {
14
+ t.stopPropagation(), u?.(e.id);
15
+ }, [e.id, u]), b = r((t) => {
16
+ t.stopPropagation(), d?.(e.id);
17
+ }, [e.id, d]), x = r((t) => {
18
+ t.stopPropagation(), f?.(e.id);
19
+ }, [e.id, f]), S = r((t) => {
20
+ t.stopPropagation(), p?.(e.id);
21
+ }, [e.id, p]), C = (n ?? e.setupState) === "completed", w = e.lastRefreshedAt ? o(new Date(e.lastRefreshedAt), { addSuffix: !0 }) : "Never";
22
+ return /* @__PURE__ */ a("article", {
23
+ className: "\n min-w-0\n cursor-pointer\n rounded-card\n border border-transparent\n bg-bg-sunken\n p-card-padding\n hover:border-[var(--color-action-primary-bg)]\n motion-safe:transition-colors\n ",
24
+ onClick: _,
23
25
  children: [
24
- /* @__PURE__ */ i("div", {
25
- className: "flex items-start justify-between mb-3",
26
- children: [/* @__PURE__ */ i("div", {
27
- className: "flex-1 min-w-0",
28
- children: [/* @__PURE__ */ r("h3", {
29
- className: "text-sm font-semibold text-text-primary truncate",
30
- children: t.name || "Untitled DataSink"
31
- }), /* @__PURE__ */ r("p", {
32
- className: "text-xs text-text-secondary font-mono mt-0.5 truncate",
33
- children: t.key
26
+ /* @__PURE__ */ a("div", {
27
+ className: "mb-3 flex items-start justify-between gap-icon-gap",
28
+ children: [/* @__PURE__ */ a("div", {
29
+ className: "min-w-0 flex-1",
30
+ children: [/* @__PURE__ */ i("h3", {
31
+ className: "truncate text-sm font-semibold text-text-primary",
32
+ children: e.name || "Untitled data sink"
33
+ }), /* @__PURE__ */ i("p", {
34
+ className: "mt-0.5 truncate font-mono text-xs text-text-secondary",
35
+ children: e.key
34
36
  })]
35
- }), /* @__PURE__ */ r(e, {
36
- status: t.status,
37
+ }), /* @__PURE__ */ i(t, {
38
+ status: e.status,
37
39
  size: "sm"
38
40
  })]
39
41
  }),
40
- t.description && /* @__PURE__ */ r("p", {
41
- className: "text-xs text-text-secondary mb-3 line-clamp-2",
42
- children: t.description
42
+ e.description && /* @__PURE__ */ i("p", {
43
+ className: "mb-3 line-clamp-2 text-xs text-text-secondary",
44
+ children: e.description
43
45
  }),
44
- /* @__PURE__ */ i("div", {
45
- className: "flex items-center gap-4 text-xs text-text-secondary mb-3",
46
- children: [/* @__PURE__ */ i("span", {
46
+ /* @__PURE__ */ a("div", {
47
+ className: "mb-3 flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-text-secondary",
48
+ children: [/* @__PURE__ */ a("span", {
47
49
  className: "flex items-center gap-1",
48
- children: [/* @__PURE__ */ r("svg", {
50
+ children: [/* @__PURE__ */ i("svg", {
49
51
  className: "w-3.5 h-3.5",
50
52
  fill: "none",
51
53
  stroke: "currentColor",
52
54
  viewBox: "0 0 24 24",
53
- children: /* @__PURE__ */ r("path", {
55
+ children: /* @__PURE__ */ i("path", {
54
56
  strokeLinecap: "round",
55
57
  strokeLinejoin: "round",
56
58
  strokeWidth: 2,
57
59
  d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
58
60
  })
59
- }), C]
60
- }), t.linkedWorkflowCount !== void 0 && t.linkedWorkflowCount > 0 && /* @__PURE__ */ i("span", {
61
+ }), w]
62
+ }), e.linkedWorkflowCount !== void 0 && e.linkedWorkflowCount > 0 && /* @__PURE__ */ a("span", {
61
63
  className: "flex items-center gap-1",
62
64
  children: [
63
- /* @__PURE__ */ r("svg", {
65
+ /* @__PURE__ */ i("svg", {
64
66
  className: "w-3.5 h-3.5",
65
67
  fill: "none",
66
68
  stroke: "currentColor",
67
69
  viewBox: "0 0 24 24",
68
- children: /* @__PURE__ */ r("path", {
70
+ children: /* @__PURE__ */ i("path", {
69
71
  strokeLinecap: "round",
70
72
  strokeLinejoin: "round",
71
73
  strokeWidth: 2,
72
74
  d: "M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"
73
75
  })
74
76
  }),
75
- t.linkedWorkflowCount,
77
+ e.linkedWorkflowCount,
76
78
  " workflow",
77
- t.linkedWorkflowCount === 1 ? "" : "s"
79
+ e.linkedWorkflowCount === 1 ? "" : "s"
78
80
  ]
79
81
  })]
80
82
  }),
81
- !S && /* @__PURE__ */ r("div", {
82
- className: "mb-3 p-2 bg-status-warning-bg/10 border border-status-warning-border/20 rounded-md",
83
- children: /* @__PURE__ */ i("div", {
84
- className: "flex items-center justify-between",
85
- children: [/* @__PURE__ */ r("span", {
86
- className: "text-xs text-status-warning-text",
87
- children: "Setup incomplete"
88
- }), /* @__PURE__ */ r("button", {
89
- type: "button",
90
- onClick: x,
91
- className: "text-xs font-medium text-action-primary-bg hover:underline",
92
- children: "Continue"
93
- })]
94
- })
83
+ !C && /* @__PURE__ */ a("div", {
84
+ className: "mb-3 flex items-center justify-between gap-icon-gap rounded-input border border-[var(--color-status-warning-border)] bg-[var(--color-status-warning-bgSubtle)] p-2",
85
+ children: [/* @__PURE__ */ i("span", {
86
+ className: "text-xs text-[var(--color-status-warning-text)]",
87
+ children: "Setup incomplete"
88
+ }), /* @__PURE__ */ i("button", {
89
+ type: "button",
90
+ onClick: S,
91
+ className: "rounded-button px-1 text-xs font-medium text-text-link hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-bg-surface",
92
+ children: "Continue"
93
+ })]
95
94
  }),
96
- /* @__PURE__ */ i("div", {
97
- className: "flex items-center gap-2 pt-2 border-t border-border-default",
95
+ /* @__PURE__ */ a("div", {
96
+ className: "flex flex-wrap items-center gap-2 border-t border-[var(--color-border-subtle)] pt-2",
98
97
  children: [
99
- /* @__PURE__ */ r("button", {
98
+ /* @__PURE__ */ i("button", {
100
99
  type: "button",
101
- onClick: g,
102
- className: "flex-1 px-3 py-1.5 text-xs font-medium text-text-primary bg-bg-sunken hover:bg-border-default rounded-md transition-colors",
100
+ onClick: _,
101
+ className: `${s} flex-1 bg-bg-surface text-text-primary hover:bg-bg-elevated`,
103
102
  children: "View"
104
103
  }),
105
- p && /* @__PURE__ */ r("button", {
104
+ m && /* @__PURE__ */ i("button", {
106
105
  type: "button",
107
- onClick: _,
108
- className: "px-3 py-1.5 text-xs font-medium text-text-secondary hover:text-text-primary hover:bg-bg-sunken rounded-md transition-colors",
106
+ onClick: v,
107
+ className: `${s} text-text-secondary hover:bg-bg-surface hover:text-text-primary`,
109
108
  children: "Edit"
110
109
  }),
111
- m && /* @__PURE__ */ r("button", {
110
+ h && /* @__PURE__ */ i("button", {
112
111
  type: "button",
113
- onClick: v,
114
- className: "px-3 py-1.5 text-xs font-medium text-text-secondary hover:text-text-primary hover:bg-bg-sunken rounded-md transition-colors",
112
+ onClick: y,
113
+ className: `${s} text-text-secondary hover:bg-bg-surface hover:text-text-primary`,
115
114
  children: "Refresh"
116
115
  }),
117
- u && /* @__PURE__ */ r("button", {
116
+ d && /* @__PURE__ */ i("button", {
118
117
  type: "button",
119
- onClick: y,
120
- className: "px-3 py-1.5 text-xs font-medium text-text-secondary hover:text-text-primary hover:bg-bg-sunken rounded-md transition-colors",
118
+ onClick: b,
119
+ className: `${s} text-text-secondary hover:bg-bg-surface hover:text-text-primary`,
121
120
  children: "Export"
122
121
  }),
123
- h && /* @__PURE__ */ r("button", {
122
+ g && /* @__PURE__ */ i("button", {
124
123
  type: "button",
125
- onClick: b,
126
- className: "px-3 py-1.5 text-xs font-medium text-status-error-text hover:bg-status-error-bg/10 rounded-md transition-colors",
124
+ onClick: x,
125
+ className: `${s} text-status-error-text hover:bg-[var(--color-status-error-bgSubtle)]`,
127
126
  children: "Delete"
128
127
  })
129
128
  ]
@@ -132,6 +131,6 @@ var o = t(function({ dataSink: t, setupState: o, onView: s, onEdit: c, onRefresh
132
131
  });
133
132
  });
134
133
  //#endregion
135
- export { o as default };
134
+ export { c as default };
136
135
 
137
136
  //# sourceMappingURL=DataSinkCard.js.map