@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":"TextWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/text-widget/TextWidget.tsx"],"sourcesContent":["/**\n * TextWidget Component\n *\n * Displays markdown/rich text content.\n *\n * Data flow: DataSink → Parser → Widget\n * - Static configuration lives in `widget.config` (content, format, alignment).\n * - Dynamic parser output is passed in `data` and overrides matching config keys.\n * - This lets the text widget render from manual configuration, parser-driven\n * data, or both.\n */\n\nimport { type FC, memo, useMemo } from 'react';\nimport type { Widget } from '../../../types';\nimport { resolveTextData } from './textData';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TextWidgetProps {\n widget: Widget;\n data?: unknown;\n}\n\nexport type { TextData, TextFormat, TextAlignment } from './textData';\n\n// ============================================================================\n// Simple Markdown Parser (basic support)\n// ============================================================================\n\nfunction parseMarkdown(text: string): string {\n let html = text;\n\n // Escape HTML\n html = html.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n\n // Headers\n html = html.replace(/^### (.+)$/gm, '<h3 class=\"text-base font-semibold text-text-primary mt-3 mb-1\">$1</h3>');\n html = html.replace(/^## (.+)$/gm, '<h2 class=\"text-lg font-semibold text-text-primary mt-4 mb-2\">$1</h2>');\n html = html.replace(/^# (.+)$/gm, '<h1 class=\"text-xl font-bold text-text-primary mt-4 mb-2\">$1</h1>');\n\n // Bold and italic\n html = html.replace(/\\*\\*(.+?)\\*\\*/g, '<strong class=\"font-semibold\">$1</strong>');\n html = html.replace(/\\*(.+?)\\*/g, '<em>$1</em>');\n\n // Links\n html = html.replace(\n /\\[([^\\]]+)\\]\\(([^)]+)\\)/g,\n '<a href=\"$2\" class=\"text-action-primary-text hover:underline\" target=\"_blank\" rel=\"noopener\">$1</a>'\n );\n\n // Inline code\n html = html.replace(/`([^`]+)`/g, '<code class=\"px-1 py-0.5 bg-bg-sunken rounded text-sm font-mono\">$1</code>');\n\n // Blockquotes\n html = html.replace(\n /^> (.+)$/gm,\n '<blockquote class=\"border-l-2 border-action-primary-bg pl-3 italic text-text-secondary my-2\">$1</blockquote>'\n );\n\n // Unordered lists\n html = html.replace(/^- (.+)$/gm, '<li class=\"ml-4 list-disc\">$1</li>');\n html = html.replace(/(<li[^>]*>.*<\\/li>\\n?)+/g, '<ul class=\"my-2\">$&</ul>');\n\n // Tables (simple)\n html = html.replace(/^\\|(.+)\\|$/gm, (match, content) => {\n const cells = content.split('|').map((cell: string) => cell.trim());\n const isHeader = cells.some((c: string) => c.match(/^-+$/));\n if (isHeader) return '';\n return `<tr>${cells.map((c: string) => `<td class=\"border border-border-default px-2 py-1 text-sm\">${c}</td>`).join('')}</tr>`;\n });\n html = html.replace(/(<tr>.*<\\/tr>\\n?)+/g, '<table class=\"w-full border-collapse my-2\">$&</table>');\n\n // Paragraphs (wrap remaining text)\n html = html\n .split('\\n\\n')\n .map((para) => {\n if (para.startsWith('<')) return para;\n return `<p class=\"my-2 text-text-primary\">${para}</p>`;\n })\n .join('');\n\n // Line breaks\n html = html.replace(/\\n/g, '<br/>');\n\n return html;\n}\n\nconst ALIGNMENT_CLASSES = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n justify: 'text-justify',\n} as const;\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const TextWidget: FC<TextWidgetProps> = memo(function TextWidget({ widget, data }) {\n const resolved = useMemo(() => resolveTextData(widget.config, data), [widget.config, data]);\n const { content, format, alignment, hasContent } = resolved;\n\n const renderedContent = useMemo(() => {\n if (!content) return null;\n\n if (format === 'markdown') {\n return { __html: parseMarkdown(content) };\n }\n\n if (format === 'html') {\n return { __html: content };\n }\n\n // Plain text\n return null;\n }, [content, format]);\n\n const alignmentClass = ALIGNMENT_CLASSES[alignment ?? 'left'];\n\n if (!hasContent) {\n return (\n <div className=\"flex items-center justify-center h-full text-text-secondary text-sm\">\n <div className=\"text-center\">\n <svg\n className=\"w-12 h-12 mx-auto mb-2 text-text-tertiary\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\"\n />\n </svg>\n <p>No text content</p>\n </div>\n </div>\n );\n }\n\n if (format === 'plain') {\n return (\n <div className={`h-full p-4 overflow-auto ${alignmentClass}`}>\n <pre className=\"text-sm text-text-primary whitespace-pre-wrap font-sans\">{content}</pre>\n </div>\n );\n }\n\n return (\n <div className={`h-full p-4 overflow-auto ${alignmentClass}`}>\n <div className=\"prose prose-sm max-w-none text-text-primary\" dangerouslySetInnerHTML={renderedContent!} />\n </div>\n );\n});\n\nexport default TextWidget;\n"],"mappings":";;;;AA+BA,SAAS,EAAc,GAAsB;CAC3C,IAAI,IAAO;AAsDX,QAnDA,IAAO,EAAK,QAAQ,MAAM,QAAQ,CAAC,QAAQ,MAAM,OAAO,CAAC,QAAQ,MAAM,OAAO,EAG9E,IAAO,EAAK,QAAQ,gBAAgB,4EAA0E,EAC9G,IAAO,EAAK,QAAQ,eAAe,0EAAwE,EAC3G,IAAO,EAAK,QAAQ,cAAc,sEAAoE,EAGtG,IAAO,EAAK,QAAQ,kBAAkB,8CAA4C,EAClF,IAAO,EAAK,QAAQ,cAAc,cAAc,EAGhD,IAAO,EAAK,QACV,4BACA,8GACD,EAGD,IAAO,EAAK,QAAQ,cAAc,+EAA6E,EAG/G,IAAO,EAAK,QACV,cACA,iHACD,EAGD,IAAO,EAAK,QAAQ,cAAc,uCAAqC,EACvE,IAAO,EAAK,QAAQ,4BAA4B,6BAA2B,EAG3E,IAAO,EAAK,QAAQ,iBAAiB,GAAO,MAAY;EACtD,IAAM,IAAQ,EAAQ,MAAM,IAAI,CAAC,KAAK,MAAiB,EAAK,MAAM,CAAC;AAGnE,SAFiB,EAAM,MAAM,MAAc,EAAE,MAAM,OAAO,CAAC,GACtC,KACd,OAAO,EAAM,KAAK,MAAc,8DAA8D,EAAE,OAAO,CAAC,KAAK,GAAG,CAAC;GACxH,EACF,IAAO,EAAK,QAAQ,uBAAuB,0DAAwD,EAGnG,IAAO,EACJ,MAAM,OAAO,CACb,KAAK,MACA,EAAK,WAAW,IAAI,GAAS,IAC1B,qCAAqC,EAAK,MACjD,CACD,KAAK,GAAG,EAGX,IAAO,EAAK,QAAQ,OAAO,QAAQ,EAE5B;;AAGT,IAAM,IAAoB;CACxB,MAAM;CACN,QAAQ;CACR,OAAO;CACP,SAAS;CACV,EAMY,IAAkC,EAAK,SAAoB,EAAE,WAAQ,WAAQ;CAExF,IAAM,EAAE,YAAS,WAAQ,cAAW,kBADnB,QAAc,EAAgB,EAAO,QAAQ,EAAK,EAAE,CAAC,EAAO,QAAQ,EAAK,CAAC,EAGrF,IAAkB,QACjB,IAED,MAAW,aACN,EAAE,QAAQ,EAAc,EAAQ,EAAE,GAGvC,MAAW,SACN,EAAE,QAAQ,GAAS,GAIrB,OAXc,MAYpB,CAAC,GAAS,EAAO,CAAC,EAEf,IAAiB,EAAkB,KAAa;AAiCtD,QA/BK,IAuBD,MAAW,UAEX,kBAAC,OAAD;EAAK,WAAW,4BAA4B;YAC1C,kBAAC,OAAD;GAAK,WAAU;aAA2D;GAAc,CAAA;EACpF,CAAA,GAKR,kBAAC,OAAD;EAAK,WAAW,4BAA4B;YAC1C,kBAAC,OAAD;GAAK,WAAU;GAA8C,yBAAyB;GAAoB,CAAA;EACtG,CAAA,GAhCJ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IACE,WAAU;IACV,MAAK;IACL,QAAO;IACP,SAAQ;cAER,kBAAC,QAAD;KACE,eAAc;KACd,gBAAe;KACf,aAAa;KACb,GAAE;KACF,CAAA;IACE,CAAA,EACN,kBAAC,KAAD,EAAA,UAAG,mBAAmB,CAAA,CAClB;;EACF,CAAA;EAiBV"}
1
+ {"version":3,"file":"TextWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/text-widget/TextWidget.tsx"],"sourcesContent":["/**\n * TextWidget Component\n *\n * Displays markdown/rich text content.\n *\n * Data flow: DataSink → Parser → Widget\n * - Static configuration lives in `widget.config` (content, format, alignment).\n * - Dynamic parser output is passed in `data` and overrides matching config keys.\n * - This lets the text widget render from manual configuration, parser-driven\n * data, or both.\n */\n\nimport { type FC, memo, useMemo } from 'react';\nimport type { Widget } from '../../../types';\nimport { resolveTextData } from './textData';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TextWidgetProps {\n widget: Widget;\n data?: unknown;\n}\n\nexport type { TextData, TextFormat, TextAlignment } from './textData';\n\n// ============================================================================\n// Simple Markdown Parser (basic support)\n// ============================================================================\n\nfunction parseMarkdown(text: string): string {\n let html = text;\n\n // Escape HTML\n html = html.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n\n // Headers\n html = html.replace(/^### (.+)$/gm, '<h3 class=\"text-base font-semibold text-text-primary mt-3 mb-1\">$1</h3>');\n html = html.replace(/^## (.+)$/gm, '<h2 class=\"text-lg font-semibold text-text-primary mt-4 mb-2\">$1</h2>');\n html = html.replace(/^# (.+)$/gm, '<h1 class=\"text-xl font-bold text-text-primary mt-4 mb-2\">$1</h1>');\n\n // Bold and italic\n html = html.replace(/\\*\\*(.+?)\\*\\*/g, '<strong class=\"font-semibold\">$1</strong>');\n html = html.replace(/\\*(.+?)\\*/g, '<em>$1</em>');\n\n // Links\n html = html.replace(\n /\\[([^\\]]+)\\]\\(([^)]+)\\)/g,\n '<a href=\"$2\" class=\"text-action-primary-text hover:underline\" target=\"_blank\" rel=\"noopener\">$1</a>'\n );\n\n // Inline code\n html = html.replace(/`([^`]+)`/g, '<code class=\"px-1 py-0.5 bg-bg-sunken rounded text-sm font-mono\">$1</code>');\n\n // Blockquotes\n html = html.replace(\n /^> (.+)$/gm,\n '<blockquote class=\"border-l-2 border-action-primary-bg pl-3 italic text-text-secondary my-2\">$1</blockquote>'\n );\n\n // Unordered lists\n html = html.replace(/^- (.+)$/gm, '<li class=\"ml-4 list-disc\">$1</li>');\n html = html.replace(/(<li[^>]*>.*<\\/li>\\n?)+/g, '<ul class=\"my-2\">$&</ul>');\n\n // Tables (simple)\n html = html.replace(/^\\|(.+)\\|$/gm, (match, content) => {\n const cells = content.split('|').map((cell: string) => cell.trim());\n const isHeader = cells.some((c: string) => c.match(/^-+$/));\n if (isHeader) return '';\n return `<tr>${cells.map((c: string) => `<td class=\"border border-border-default px-2 py-1 text-sm\">${c}</td>`).join('')}</tr>`;\n });\n html = html.replace(/(<tr>.*<\\/tr>\\n?)+/g, '<table class=\"w-full border-collapse my-2\">$&</table>');\n\n // Paragraphs (wrap remaining text)\n html = html\n .split('\\n\\n')\n .map((para) => {\n if (para.startsWith('<')) return para;\n return `<p class=\"my-2 text-text-primary\">${para}</p>`;\n })\n .join('');\n\n // Line breaks\n html = html.replace(/\\n/g, '<br/>');\n\n return html;\n}\n\nconst ALIGNMENT_CLASSES = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n justify: 'text-justify',\n} as const;\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const TextWidget: FC<TextWidgetProps> = memo(function TextWidget({ widget, data }) {\n const resolved = useMemo(() => resolveTextData(widget.config, data), [widget.config, data]);\n const { content, format, alignment, hasContent } = resolved;\n\n const renderedContent = useMemo(() => {\n if (!content) return null;\n\n if (format === 'markdown') {\n return { __html: parseMarkdown(content) };\n }\n\n if (format === 'html') {\n return { __html: content };\n }\n\n // Plain text\n return null;\n }, [content, format]);\n\n const alignmentClass = ALIGNMENT_CLASSES[alignment ?? 'left'];\n\n if (!hasContent) {\n return (\n <div className=\"flex items-center justify-center h-full text-text-secondary text-sm\">\n <div className=\"text-center\">\n <svg className=\"w-12 h-12 mx-auto mb-2 text-text-muted\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\"\n />\n </svg>\n <p>No text content</p>\n </div>\n </div>\n );\n }\n\n if (format === 'plain') {\n return (\n <div className={`h-full p-4 overflow-auto ${alignmentClass}`}>\n <pre className=\"text-sm text-text-primary whitespace-pre-wrap font-sans\">{content}</pre>\n </div>\n );\n }\n\n return (\n <div className={`h-full p-4 overflow-auto ${alignmentClass}`}>\n <div className=\"prose prose-sm max-w-none text-text-primary\" dangerouslySetInnerHTML={renderedContent!} />\n </div>\n );\n});\n\nexport default TextWidget;\n"],"mappings":";;;;AA+BA,SAAS,EAAc,GAAsB;CAC3C,IAAI,IAAO;AAsDX,QAnDA,IAAO,EAAK,QAAQ,MAAM,QAAQ,CAAC,QAAQ,MAAM,OAAO,CAAC,QAAQ,MAAM,OAAO,EAG9E,IAAO,EAAK,QAAQ,gBAAgB,4EAA0E,EAC9G,IAAO,EAAK,QAAQ,eAAe,0EAAwE,EAC3G,IAAO,EAAK,QAAQ,cAAc,sEAAoE,EAGtG,IAAO,EAAK,QAAQ,kBAAkB,8CAA4C,EAClF,IAAO,EAAK,QAAQ,cAAc,cAAc,EAGhD,IAAO,EAAK,QACV,4BACA,8GACD,EAGD,IAAO,EAAK,QAAQ,cAAc,+EAA6E,EAG/G,IAAO,EAAK,QACV,cACA,iHACD,EAGD,IAAO,EAAK,QAAQ,cAAc,uCAAqC,EACvE,IAAO,EAAK,QAAQ,4BAA4B,6BAA2B,EAG3E,IAAO,EAAK,QAAQ,iBAAiB,GAAO,MAAY;EACtD,IAAM,IAAQ,EAAQ,MAAM,IAAI,CAAC,KAAK,MAAiB,EAAK,MAAM,CAAC;AAGnE,SAFiB,EAAM,MAAM,MAAc,EAAE,MAAM,OAAO,CAAC,GACtC,KACd,OAAO,EAAM,KAAK,MAAc,8DAA8D,EAAE,OAAO,CAAC,KAAK,GAAG,CAAC;GACxH,EACF,IAAO,EAAK,QAAQ,uBAAuB,0DAAwD,EAGnG,IAAO,EACJ,MAAM,OAAO,CACb,KAAK,MACA,EAAK,WAAW,IAAI,GAAS,IAC1B,qCAAqC,EAAK,MACjD,CACD,KAAK,GAAG,EAGX,IAAO,EAAK,QAAQ,OAAO,QAAQ,EAE5B;;AAGT,IAAM,IAAoB;CACxB,MAAM;CACN,QAAQ;CACR,OAAO;CACP,SAAS;CACV,EAMY,IAAkC,EAAK,SAAoB,EAAE,WAAQ,WAAQ;CAExF,IAAM,EAAE,YAAS,WAAQ,cAAW,kBADnB,QAAc,EAAgB,EAAO,QAAQ,EAAK,EAAE,CAAC,EAAO,QAAQ,EAAK,CAAC,EAGrF,IAAkB,QACjB,IAED,MAAW,aACN,EAAE,QAAQ,EAAc,EAAQ,EAAE,GAGvC,MAAW,SACN,EAAE,QAAQ,GAAS,GAIrB,OAXc,MAYpB,CAAC,GAAS,EAAO,CAAC,EAEf,IAAiB,EAAkB,KAAa;AA4BtD,QA1BK,IAkBD,MAAW,UAEX,kBAAC,OAAD;EAAK,WAAW,4BAA4B;YAC1C,kBAAC,OAAD;GAAK,WAAU;aAA2D;GAAc,CAAA;EACpF,CAAA,GAKR,kBAAC,OAAD;EAAK,WAAW,4BAA4B;YAC1C,kBAAC,OAAD;GAAK,WAAU;GAA8C,yBAAyB;GAAoB,CAAA;EACtG,CAAA,GA3BJ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;IAAyC,MAAK;IAAO,QAAO;IAAe,SAAQ;cAChG,kBAAC,QAAD;KACE,eAAc;KACd,gBAAe;KACf,aAAa;KACb,GAAE;KACF,CAAA;IACE,CAAA,EACN,kBAAC,KAAD,EAAA,UAAG,mBAAmB,CAAA,CAClB;;EACF,CAAA;EAiBV"}
@@ -115,7 +115,7 @@ var s = e(function({ widget: e, data: i, onClick: s }) {
115
115
  }
116
116
  }),
117
117
  /* @__PURE__ */ n("div", {
118
- className: "absolute top-1/2 -translate-y-1/2 text-[9px] text-text-tertiary",
118
+ className: "absolute top-1/2 -translate-y-1/2 text-[9px] text-text-muted",
119
119
  style: { left: `${d + 1}%` },
120
120
  children: t.toLocaleDateString("en-US", {
121
121
  month: "short",
@@ -146,7 +146,7 @@ var s = e(function({ widget: e, data: i, onClick: s }) {
146
146
  children: e.name
147
147
  }),
148
148
  /* @__PURE__ */ n("span", {
149
- className: "text-[10px] text-text-tertiary",
149
+ className: "text-[10px] text-text-muted",
150
150
  children: new Date(e.date).toLocaleDateString("en-US", {
151
151
  month: "short",
152
152
  day: "numeric"
@@ -162,7 +162,7 @@ var s = e(function({ widget: e, data: i, onClick: s }) {
162
162
  children: /* @__PURE__ */ r("div", {
163
163
  className: "text-center",
164
164
  children: [/* @__PURE__ */ n("svg", {
165
- className: "w-12 h-12 mx-auto mb-2 text-text-tertiary",
165
+ className: "w-12 h-12 mx-auto mb-2 text-text-muted",
166
166
  fill: "none",
167
167
  stroke: "currentColor",
168
168
  viewBox: "0 0 24 24",
@@ -1 +1 @@
1
- {"version":3,"file":"TimelineWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/timeline/TimelineWidget.tsx"],"sourcesContent":["/**\n * TimelineWidget Component\n *\n * Simple timeline/gantt view showing project tasks and milestones.\n */\n\nimport { type FC, memo, useMemo } from 'react';\nimport type { Widget } from '../../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TimelineWidgetProps {\n widget: Widget;\n data?: TimelineData;\n onClick?: (task: TimelineTask) => void;\n}\n\nexport interface TimelineTask {\n id: string;\n name: string;\n start: string;\n end: string;\n progress?: number;\n color?: string;\n duration?: number;\n dependencies?: string[];\n}\n\nexport interface TimelineMilestone {\n id: string;\n name: string;\n date: string;\n color?: string;\n}\n\nexport interface TimelineData {\n tasks?: TimelineTask[];\n milestones?: TimelineMilestone[];\n}\n\n// ============================================================================\n// Normalization\n// ============================================================================\n\nfunction firstDefined<T = unknown>(obj: Record<string, unknown>, keys: string[]): T | undefined {\n for (const key of keys) {\n if (obj[key] !== undefined && obj[key] !== null) return obj[key] as T;\n }\n return undefined;\n}\n\n/**\n * Normalize whatever the widget is bound to into `TimelineTask[]`. Accepts the\n * documented `{ tasks, ... }` shape, a tasks array under a different common key,\n * or a bare array of task-like records — a DataSink parser naturally outputs a\n * bare array, and WidgetWrapper has no timeline-specific reshaping step (unlike\n * table/list/chart), so this widget has to tolerate it itself, the same way\n * MapWidget tolerates a bare marker array instead of requiring `{ markers }`.\n * Field names are matched against common aliases (e.g. a parser emitting\n * `title` instead of `name`) so one exact parser output shape isn't required.\n */\nexport function normalizeTimelineTasks(\n data: TimelineData | TimelineTask[] | Record<string, unknown> | undefined\n): TimelineTask[] {\n const rawTasks: unknown = Array.isArray(data)\n ? data\n : Array.isArray((data as TimelineData | undefined)?.tasks)\n ? (data as TimelineData).tasks\n : Array.isArray((data as Record<string, unknown> | undefined)?.items)\n ? (data as Record<string, unknown>).items\n : Array.isArray((data as Record<string, unknown> | undefined)?.data)\n ? (data as Record<string, unknown>).data\n : undefined;\n\n if (!Array.isArray(rawTasks)) return [];\n\n return rawTasks\n .map((raw, i): TimelineTask | null => {\n if (!raw || typeof raw !== 'object') return null;\n const r = raw as Record<string, unknown>;\n const start = firstDefined<string>(r, ['start', 'startDate', 'date']);\n const end = firstDefined<string>(r, ['end', 'endDate']) ?? start;\n if (!start || !end) return null;\n const name = firstDefined<string>(r, ['name', 'title', 'label', 'task']) ?? 'Untitled task';\n const id = firstDefined<string>(r, ['id', 'taskId', '_id']) ?? `${name}-${start}-${i}`;\n return {\n id: String(id),\n name: String(name),\n start: String(start),\n end: String(end),\n progress: typeof r.progress === 'number' ? r.progress : undefined,\n color: typeof r.color === 'string' ? r.color : undefined,\n duration: typeof r.duration === 'number' ? r.duration : undefined,\n dependencies: Array.isArray(r.dependencies) ? (r.dependencies as string[]) : undefined,\n };\n })\n .filter((t): t is TimelineTask => t !== null);\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction getProgressColor(progress: number): string {\n if (progress >= 100) return 'bg-status-success-bg';\n if (progress >= 50) return 'bg-action-primary-bg';\n if (progress > 0) return 'bg-status-warning-bg';\n return 'bg-bg-sunken';\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const TimelineWidget: FC<TimelineWidgetProps> = memo(function TimelineWidget({\n widget: _widget,\n data,\n onClick,\n}) {\n const tasks = useMemo(() => normalizeTimelineTasks(data), [data]);\n const milestones = data?.milestones || [];\n\n // Calculate date range\n const { minDate, maxDate, totalDays } = useMemo(() => {\n if (!tasks.length) {\n return { minDate: new Date(), maxDate: new Date(), totalDays: 1 };\n }\n\n const dates = tasks.flatMap((t) => [new Date(t.start), new Date(t.end)]);\n const min = new Date(Math.min(...dates.map((d) => d.getTime())));\n const max = new Date(Math.max(...dates.map((d) => d.getTime())));\n const days = Math.ceil((max.getTime() - min.getTime()) / (1000 * 60 * 60 * 24)) + 1;\n\n return { minDate: min, maxDate: max, totalDays: days };\n }, [tasks]);\n\n if (!tasks.length) {\n return (\n <div className=\"flex items-center justify-center h-full text-text-secondary text-sm\">\n <div className=\"text-center\">\n <svg\n className=\"w-12 h-12 mx-auto mb-2 text-text-tertiary\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"\n />\n </svg>\n <p>No timeline data</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col h-full p-4 overflow-auto\">\n {/* Header with date range */}\n <div className=\"flex items-center justify-between mb-4\">\n <h3 className=\"text-sm font-medium text-text-primary\">Project Timeline</h3>\n <span className=\"text-xs text-text-secondary\">\n {minDate.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })} -{' '}\n {maxDate.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}\n </span>\n </div>\n\n {/* Timeline content */}\n <div className=\"flex-1 space-y-3 overflow-auto\">\n {tasks.map((task) => {\n const startDate = new Date(task.start);\n const endDate = new Date(task.end);\n const taskDays = Math.ceil((endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24)) + 1;\n const startOffset = Math.ceil((startDate.getTime() - minDate.getTime()) / (1000 * 60 * 60 * 24));\n const progress = task.progress ?? 0;\n\n // Calculate bar position and width as percentages\n const leftPercent = (startOffset / totalDays) * 100;\n const widthPercent = (taskDays / totalDays) * 100;\n\n return (\n <div\n key={task.id}\n className={`\n ${onClick ? 'cursor-pointer' : ''}\n `}\n onClick={() => onClick?.(task)}\n >\n {/* Task name and progress */}\n <div className=\"flex items-center justify-between mb-1\">\n <span className=\"text-xs font-medium text-text-primary truncate max-w-[60%]\">{task.name}</span>\n <span className=\"text-[10px] text-text-secondary\">{progress}%</span>\n </div>\n\n {/* Timeline bar */}\n <div className=\"relative h-6 bg-bg-sunken rounded overflow-hidden\">\n {/* Task bar */}\n <div\n className=\"absolute top-1 bottom-1 rounded\"\n style={{\n left: `${leftPercent}%`,\n width: `${Math.max(widthPercent, 5)}%`,\n backgroundColor: task.color || 'var(--color-chart-1)',\n opacity: 0.3,\n }}\n />\n\n {/* Progress fill */}\n <div\n className={`absolute top-1 bottom-1 rounded ${getProgressColor(progress)}`}\n style={{\n left: `${leftPercent}%`,\n width: `${Math.max((widthPercent * progress) / 100, 2)}%`,\n }}\n />\n\n {/* Date labels */}\n <div\n className=\"absolute top-1/2 -translate-y-1/2 text-[9px] text-text-tertiary\"\n style={{ left: `${leftPercent + 1}%` }}\n >\n {startDate.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}\n </div>\n </div>\n </div>\n );\n })}\n </div>\n\n {/* Milestones */}\n {milestones.length > 0 && (\n <div className=\"mt-4 pt-3 border-t border-border-default\">\n <p className=\"text-xs font-medium text-text-secondary mb-2\">Milestones</p>\n <div className=\"flex flex-wrap gap-2\">\n {milestones.map((milestone) => (\n <div key={milestone.id} className=\"flex items-center gap-1.5 px-2 py-1 rounded bg-bg-sunken\">\n <div\n className=\"w-2 h-2 rounded-full\"\n style={{ backgroundColor: milestone.color || 'var(--color-chart-negative)' }}\n />\n <span className=\"text-[10px] text-text-primary\">{milestone.name}</span>\n <span className=\"text-[10px] text-text-tertiary\">\n {new Date(milestone.date).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}\n </span>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n );\n});\n\nexport default TimelineWidget;\n"],"mappings":"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"}
1
+ {"version":3,"file":"TimelineWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/timeline/TimelineWidget.tsx"],"sourcesContent":["/**\n * TimelineWidget Component\n *\n * Simple timeline/gantt view showing project tasks and milestones.\n */\n\nimport { type FC, memo, useMemo } from 'react';\nimport type { Widget } from '../../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TimelineWidgetProps {\n widget: Widget;\n data?: TimelineData;\n onClick?: (task: TimelineTask) => void;\n}\n\nexport interface TimelineTask {\n id: string;\n name: string;\n start: string;\n end: string;\n progress?: number;\n color?: string;\n duration?: number;\n dependencies?: string[];\n}\n\nexport interface TimelineMilestone {\n id: string;\n name: string;\n date: string;\n color?: string;\n}\n\nexport interface TimelineData {\n tasks?: TimelineTask[];\n milestones?: TimelineMilestone[];\n}\n\n// ============================================================================\n// Normalization\n// ============================================================================\n\nfunction firstDefined<T = unknown>(obj: Record<string, unknown>, keys: string[]): T | undefined {\n for (const key of keys) {\n if (obj[key] !== undefined && obj[key] !== null) return obj[key] as T;\n }\n return undefined;\n}\n\n/**\n * Normalize whatever the widget is bound to into `TimelineTask[]`. Accepts the\n * documented `{ tasks, ... }` shape, a tasks array under a different common key,\n * or a bare array of task-like records — a DataSink parser naturally outputs a\n * bare array, and WidgetWrapper has no timeline-specific reshaping step (unlike\n * table/list/chart), so this widget has to tolerate it itself, the same way\n * MapWidget tolerates a bare marker array instead of requiring `{ markers }`.\n * Field names are matched against common aliases (e.g. a parser emitting\n * `title` instead of `name`) so one exact parser output shape isn't required.\n */\nexport function normalizeTimelineTasks(\n data: TimelineData | TimelineTask[] | Record<string, unknown> | undefined\n): TimelineTask[] {\n const rawTasks: unknown = Array.isArray(data)\n ? data\n : Array.isArray((data as TimelineData | undefined)?.tasks)\n ? (data as TimelineData).tasks\n : Array.isArray((data as Record<string, unknown> | undefined)?.items)\n ? (data as Record<string, unknown>).items\n : Array.isArray((data as Record<string, unknown> | undefined)?.data)\n ? (data as Record<string, unknown>).data\n : undefined;\n\n if (!Array.isArray(rawTasks)) return [];\n\n return rawTasks\n .map((raw, i): TimelineTask | null => {\n if (!raw || typeof raw !== 'object') return null;\n const r = raw as Record<string, unknown>;\n const start = firstDefined<string>(r, ['start', 'startDate', 'date']);\n const end = firstDefined<string>(r, ['end', 'endDate']) ?? start;\n if (!start || !end) return null;\n const name = firstDefined<string>(r, ['name', 'title', 'label', 'task']) ?? 'Untitled task';\n const id = firstDefined<string>(r, ['id', 'taskId', '_id']) ?? `${name}-${start}-${i}`;\n return {\n id: String(id),\n name: String(name),\n start: String(start),\n end: String(end),\n progress: typeof r.progress === 'number' ? r.progress : undefined,\n color: typeof r.color === 'string' ? r.color : undefined,\n duration: typeof r.duration === 'number' ? r.duration : undefined,\n dependencies: Array.isArray(r.dependencies) ? (r.dependencies as string[]) : undefined,\n };\n })\n .filter((t): t is TimelineTask => t !== null);\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction getProgressColor(progress: number): string {\n if (progress >= 100) return 'bg-status-success-bg';\n if (progress >= 50) return 'bg-action-primary-bg';\n if (progress > 0) return 'bg-status-warning-bg';\n return 'bg-bg-sunken';\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const TimelineWidget: FC<TimelineWidgetProps> = memo(function TimelineWidget({\n widget: _widget,\n data,\n onClick,\n}) {\n const tasks = useMemo(() => normalizeTimelineTasks(data), [data]);\n const milestones = data?.milestones || [];\n\n // Calculate date range\n const { minDate, maxDate, totalDays } = useMemo(() => {\n if (!tasks.length) {\n return { minDate: new Date(), maxDate: new Date(), totalDays: 1 };\n }\n\n const dates = tasks.flatMap((t) => [new Date(t.start), new Date(t.end)]);\n const min = new Date(Math.min(...dates.map((d) => d.getTime())));\n const max = new Date(Math.max(...dates.map((d) => d.getTime())));\n const days = Math.ceil((max.getTime() - min.getTime()) / (1000 * 60 * 60 * 24)) + 1;\n\n return { minDate: min, maxDate: max, totalDays: days };\n }, [tasks]);\n\n if (!tasks.length) {\n return (\n <div className=\"flex items-center justify-center h-full text-text-secondary text-sm\">\n <div className=\"text-center\">\n <svg className=\"w-12 h-12 mx-auto mb-2 text-text-muted\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"\n />\n </svg>\n <p>No timeline data</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col h-full p-4 overflow-auto\">\n {/* Header with date range */}\n <div className=\"flex items-center justify-between mb-4\">\n <h3 className=\"text-sm font-medium text-text-primary\">Project Timeline</h3>\n <span className=\"text-xs text-text-secondary\">\n {minDate.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })} -{' '}\n {maxDate.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}\n </span>\n </div>\n\n {/* Timeline content */}\n <div className=\"flex-1 space-y-3 overflow-auto\">\n {tasks.map((task) => {\n const startDate = new Date(task.start);\n const endDate = new Date(task.end);\n const taskDays = Math.ceil((endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24)) + 1;\n const startOffset = Math.ceil((startDate.getTime() - minDate.getTime()) / (1000 * 60 * 60 * 24));\n const progress = task.progress ?? 0;\n\n // Calculate bar position and width as percentages\n const leftPercent = (startOffset / totalDays) * 100;\n const widthPercent = (taskDays / totalDays) * 100;\n\n return (\n <div\n key={task.id}\n className={`\n ${onClick ? 'cursor-pointer' : ''}\n `}\n onClick={() => onClick?.(task)}\n >\n {/* Task name and progress */}\n <div className=\"flex items-center justify-between mb-1\">\n <span className=\"text-xs font-medium text-text-primary truncate max-w-[60%]\">{task.name}</span>\n <span className=\"text-[10px] text-text-secondary\">{progress}%</span>\n </div>\n\n {/* Timeline bar */}\n <div className=\"relative h-6 bg-bg-sunken rounded overflow-hidden\">\n {/* Task bar */}\n <div\n className=\"absolute top-1 bottom-1 rounded\"\n style={{\n left: `${leftPercent}%`,\n width: `${Math.max(widthPercent, 5)}%`,\n backgroundColor: task.color || 'var(--color-chart-1)',\n opacity: 0.3,\n }}\n />\n\n {/* Progress fill */}\n <div\n className={`absolute top-1 bottom-1 rounded ${getProgressColor(progress)}`}\n style={{\n left: `${leftPercent}%`,\n width: `${Math.max((widthPercent * progress) / 100, 2)}%`,\n }}\n />\n\n {/* Date labels */}\n <div\n className=\"absolute top-1/2 -translate-y-1/2 text-[9px] text-text-muted\"\n style={{ left: `${leftPercent + 1}%` }}\n >\n {startDate.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}\n </div>\n </div>\n </div>\n );\n })}\n </div>\n\n {/* Milestones */}\n {milestones.length > 0 && (\n <div className=\"mt-4 pt-3 border-t border-border-default\">\n <p className=\"text-xs font-medium text-text-secondary mb-2\">Milestones</p>\n <div className=\"flex flex-wrap gap-2\">\n {milestones.map((milestone) => (\n <div key={milestone.id} className=\"flex items-center gap-1.5 px-2 py-1 rounded bg-bg-sunken\">\n <div\n className=\"w-2 h-2 rounded-full\"\n style={{ backgroundColor: milestone.color || 'var(--color-chart-negative)' }}\n />\n <span className=\"text-[10px] text-text-primary\">{milestone.name}</span>\n <span className=\"text-[10px] text-text-muted\">\n {new Date(milestone.date).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}\n </span>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n );\n});\n\nexport default TimelineWidget;\n"],"mappings":";;;AA8CA,SAAS,EAA0B,GAA8B,GAA+B;AAC9F,MAAK,IAAM,KAAO,EAChB,KAAI,EAAI,OAAS,KAAA,KAAa,EAAI,OAAS,KAAM,QAAO,EAAI;;AAehE,SAAgB,EACd,GACgB;CAChB,IAAM,IAAoB,MAAM,QAAQ,EAAK,GACzC,IACA,MAAM,QAAS,GAAmC,MAAM,GACrD,EAAsB,QACvB,MAAM,QAAS,GAA8C,MAAM,GAChE,EAAiC,QAClC,MAAM,QAAS,GAA8C,KAAK,GAC/D,EAAiC,OAClC,KAAA;AAIV,QAFK,MAAM,QAAQ,EAAS,GAErB,EACJ,KAAK,GAAK,MAA2B;AACpC,MAAI,CAAC,KAAO,OAAO,KAAQ,SAAU,QAAO;EAC5C,IAAM,IAAI,GACJ,IAAQ,EAAqB,GAAG;GAAC;GAAS;GAAa;GAAO,CAAC,EAC/D,IAAM,EAAqB,GAAG,CAAC,OAAO,UAAU,CAAC,IAAI;AAC3D,MAAI,CAAC,KAAS,CAAC,EAAK,QAAO;EAC3B,IAAM,IAAO,EAAqB,GAAG;GAAC;GAAQ;GAAS;GAAS;GAAO,CAAC,IAAI,iBACtE,IAAK,EAAqB,GAAG;GAAC;GAAM;GAAU;GAAM,CAAC,IAAI,GAAG,EAAK,GAAG,EAAM,GAAG;AACnF,SAAO;GACL,IAAI,OAAO,EAAG;GACd,MAAM,OAAO,EAAK;GAClB,OAAO,OAAO,EAAM;GACpB,KAAK,OAAO,EAAI;GAChB,UAAU,OAAO,EAAE,YAAa,WAAW,EAAE,WAAW,KAAA;GACxD,OAAO,OAAO,EAAE,SAAU,WAAW,EAAE,QAAQ,KAAA;GAC/C,UAAU,OAAO,EAAE,YAAa,WAAW,EAAE,WAAW,KAAA;GACxD,cAAc,MAAM,QAAQ,EAAE,aAAa,GAAI,EAAE,eAA4B,KAAA;GAC9E;GACD,CACD,QAAQ,MAAyB,MAAM,KAAK,GAtBV,EAAE;;AA6BzC,SAAS,EAAiB,GAA0B;AAIlD,QAHI,KAAY,MAAY,yBACxB,KAAY,KAAW,yBACvB,IAAW,IAAU,yBAClB;;AAOT,IAAa,IAA0C,EAAK,SAAwB,EAClF,QAAQ,GACR,SACA,cACC;CACD,IAAM,IAAQ,QAAc,EAAuB,EAAK,EAAE,CAAC,EAAK,CAAC,EAC3D,IAAa,GAAM,cAAc,EAAE,EAGnC,EAAE,YAAS,YAAS,iBAAc,QAAc;AACpD,MAAI,CAAC,EAAM,OACT,QAAO;GAAE,yBAAS,IAAI,MAAM;GAAE,yBAAS,IAAI,MAAM;GAAE,WAAW;GAAG;EAGnE,IAAM,IAAQ,EAAM,SAAS,MAAM,CAAC,IAAI,KAAK,EAAE,MAAM,EAAE,IAAI,KAAK,EAAE,IAAI,CAAC,CAAC,EAClE,IAAM,IAAI,KAAK,KAAK,IAAI,GAAG,EAAM,KAAK,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,EAC1D,IAAM,IAAI,KAAK,KAAK,IAAI,GAAG,EAAM,KAAK,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;AAGhE,SAAO;GAAE,SAAS;GAAK,SAAS;GAAK,WAFxB,KAAK,MAAM,EAAI,SAAS,GAAG,EAAI,SAAS,KAAK,MAAO,KAAK,KAAK,IAAI,GAAG;GAE5B;IACrD,CAAC,EAAM,CAAC;AAoBX,QAlBK,EAAM,SAmBT,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,MAAD;KAAI,WAAU;eAAwC;KAAqB,CAAA,EAC3E,kBAAC,QAAD;KAAM,WAAU;eAAhB;MACG,EAAQ,mBAAmB,SAAS;OAAE,OAAO;OAAS,KAAK;OAAW,CAAC;MAAC;MAAG;MAC3E,EAAQ,mBAAmB,SAAS;OAAE,OAAO;OAAS,KAAK;OAAW,CAAC;MACnE;OACH;;GAGN,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAM,KAAK,MAAS;KACnB,IAAM,IAAY,IAAI,KAAK,EAAK,MAAM,EAChC,IAAU,IAAI,KAAK,EAAK,IAAI,EAC5B,IAAW,KAAK,MAAM,EAAQ,SAAS,GAAG,EAAU,SAAS,KAAK,MAAO,KAAK,KAAK,IAAI,GAAG,GAC1F,IAAc,KAAK,MAAM,EAAU,SAAS,GAAG,EAAQ,SAAS,KAAK,MAAO,KAAK,KAAK,IAAI,EAC1F,IAAW,EAAK,YAAY,GAG5B,IAAe,IAAc,IAAa,KAC1C,IAAgB,IAAW,IAAa;AAE9C,YACE,kBAAC,OAAD;MAEE,WAAW;oBACL,IAAU,mBAAmB,GAAG;;MAEtC,eAAe,IAAU,EAAK;gBALhC,CAQE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBAA8D,EAAK;QAAY,CAAA,EAC/F,kBAAC,QAAD;QAAM,WAAU;kBAAhB,CAAmD,GAAS,IAAQ;UAChE;UAGN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QAEE,kBAAC,OAAD;SACE,WAAU;SACV,OAAO;UACL,MAAM,GAAG,EAAY;UACrB,OAAO,GAAG,KAAK,IAAI,GAAc,EAAE,CAAC;UACpC,iBAAiB,EAAK,SAAS;UAC/B,SAAS;UACV;SACD,CAAA;QAGF,kBAAC,OAAD;SACE,WAAW,mCAAmC,EAAiB,EAAS;SACxE,OAAO;UACL,MAAM,GAAG,EAAY;UACrB,OAAO,GAAG,KAAK,IAAK,IAAe,IAAY,KAAK,EAAE,CAAC;UACxD;SACD,CAAA;QAGF,kBAAC,OAAD;SACE,WAAU;SACV,OAAO,EAAE,MAAM,GAAG,IAAc,EAAE,IAAI;mBAErC,EAAU,mBAAmB,SAAS;UAAE,OAAO;UAAS,KAAK;UAAW,CAAC;SACtE,CAAA;QACF;SACF;QA1CC,EAAK,GA0CN;MAER;IACE,CAAA;GAGL,EAAW,SAAS,KACnB,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,KAAD;KAAG,WAAU;eAA+C;KAAc,CAAA,EAC1E,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAW,KAAK,MACf,kBAAC,OAAD;MAAwB,WAAU;gBAAlC;OACE,kBAAC,OAAD;QACE,WAAU;QACV,OAAO,EAAE,iBAAiB,EAAU,SAAS,+BAA+B;QAC5E,CAAA;OACF,kBAAC,QAAD;QAAM,WAAU;kBAAiC,EAAU;QAAY,CAAA;OACvE,kBAAC,QAAD;QAAM,WAAU;kBACb,IAAI,KAAK,EAAU,KAAK,CAAC,mBAAmB,SAAS;SAAE,OAAO;SAAS,KAAK;SAAW,CAAC;QACpF,CAAA;OACH;QATI,EAAU,GASd,CACN;KACE,CAAA,CACF;;GAEJ;MA7GJ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;IAAyC,MAAK;IAAO,QAAO;IAAe,SAAQ;cAChG,kBAAC,QAAD;KACE,eAAc;KACd,gBAAe;KACf,aAAa;KACb,GAAE;KACF,CAAA;IACE,CAAA,EACN,kBAAC,KAAD,EAAA,UAAG,oBAAoB,CAAA,CACnB;;EACF,CAAA;EAmGV"}
@@ -61,9 +61,9 @@ function r(e) {
61
61
  }
62
62
  var i = {
63
63
  success: "text-status-success-text",
64
- warning: "text-status-warning-text",
64
+ warning: "text-[var(--color-status-warning-text)]",
65
65
  danger: "text-status-error-text",
66
- info: "text-status-info-text",
66
+ info: "text-[var(--color-status-info-text)]",
67
67
  neutral: "text-text-secondary"
68
68
  }, a = {
69
69
  success: "bg-status-success-bg",
@@ -1 +1 @@
1
- {"version":3,"file":"conditionalFormat.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/utils/conditionalFormat.ts"],"sourcesContent":["/**\n * Conditional Formatting Engine (shared)\n *\n * Rule-based styling shared across Table, Chart, KPI and Metric widgets.\n * Rules are stored on the widget `config` (e.g. `config.conditionalRules`) and\n * evaluated per data point. Colors are expressed as *semantic intents*\n * (success/warning/danger/info/neutral) — never raw hex — so theming and\n * dark-mode keep working. The intent is resolved to either a Tailwind class\n * (for DOM cells) or a CSS variable (for SVG charts) at render time.\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Comparison operators supported by a conditional rule. */\nexport type ConditionalOperator =\n | 'gt'\n | 'gte'\n | 'lt'\n | 'lte'\n | 'eq'\n | 'neq'\n | 'between'\n | 'outside'\n | 'contains'\n | 'notContains'\n | 'startsWith'\n | 'endsWith'\n | 'isEmpty'\n | 'isNotEmpty';\n\n/**\n * Semantic color intent. Maps to `--color-status-*` / neutral tokens so the\n * result is theme-aware. Raw colors are intentionally NOT allowed here.\n */\nexport type SemanticIntent = 'success' | 'warning' | 'danger' | 'info' | 'neutral';\n\n/** Icon hint rendered alongside a matched value. */\nexport type ConditionalIcon = 'arrow-up' | 'arrow-down' | 'flag' | 'check' | 'alert' | 'dot';\n\nexport interface ConditionalStyle {\n /** Text color intent. */\n textColor?: SemanticIntent;\n /** Background color intent (subtle fill). */\n bgColor?: SemanticIntent;\n /** Bold the matched value. */\n bold?: boolean;\n /** Icon hint to render before the value. */\n icon?: ConditionalIcon;\n /** Render an in-cell data bar scaled against `dataBarMax`. */\n dataBar?: boolean;\n /** Color intent for the data bar (defaults to `info`). */\n dataBarColor?: SemanticIntent;\n}\n\nexport interface ConditionalRule {\n /** Optional stable id (UI keying). */\n id?: string;\n /**\n * Field to test. When omitted, the rule tests the value it is applied to\n * (e.g. the current cell value or series value).\n */\n field?: string;\n /** Comparison operator. */\n operator: ConditionalOperator;\n /** Comparison operand (primary). */\n value?: string | number;\n /** Second operand for `between` / `outside`. */\n value2?: string | number;\n /** Styling applied when the rule matches. */\n style: ConditionalStyle;\n}\n\n// ============================================================================\n// Evaluation\n// ============================================================================\n\nfunction toNumber(v: unknown): number | null {\n if (typeof v === 'number') return Number.isNaN(v) ? null : v;\n if (typeof v === 'string' && v.trim() !== '') {\n const n = Number(v);\n return Number.isNaN(n) ? null : n;\n }\n return null;\n}\n\n/** Evaluate a single rule against a candidate value. */\nexport function evaluateRule(rawValue: unknown, rule: ConditionalRule, rowData?: Record<string, unknown>): boolean {\n // Resolve the value being tested: explicit field on the row, else the raw value.\n const candidate = rule.field != null && rowData ? rowData[rule.field] : rawValue;\n\n switch (rule.operator) {\n case 'isEmpty':\n return candidate == null || candidate === '';\n case 'isNotEmpty':\n return candidate != null && candidate !== '';\n case 'contains':\n return String(candidate ?? '')\n .toLowerCase()\n .includes(String(rule.value ?? '').toLowerCase());\n case 'notContains':\n return !String(candidate ?? '')\n .toLowerCase()\n .includes(String(rule.value ?? '').toLowerCase());\n case 'startsWith':\n return String(candidate ?? '')\n .toLowerCase()\n .startsWith(String(rule.value ?? '').toLowerCase());\n case 'endsWith':\n return String(candidate ?? '')\n .toLowerCase()\n .endsWith(String(rule.value ?? '').toLowerCase());\n default:\n break;\n }\n\n // Equality works for both strings and numbers.\n if (rule.operator === 'eq' || rule.operator === 'neq') {\n const num = toNumber(candidate);\n const ruleNum = toNumber(rule.value);\n const equal =\n num != null && ruleNum != null ? num === ruleNum : String(candidate ?? '') === String(rule.value ?? '');\n return rule.operator === 'eq' ? equal : !equal;\n }\n\n // Remaining operators are numeric.\n const num = toNumber(candidate);\n if (num == null) return false;\n const a = toNumber(rule.value);\n\n switch (rule.operator) {\n case 'gt':\n return a != null && num > a;\n case 'gte':\n return a != null && num >= a;\n case 'lt':\n return a != null && num < a;\n case 'lte':\n return a != null && num <= a;\n case 'between': {\n const b = toNumber(rule.value2);\n if (a == null || b == null) return false;\n const lo = Math.min(a, b);\n const hi = Math.max(a, b);\n return num >= lo && num <= hi;\n }\n case 'outside': {\n const b = toNumber(rule.value2);\n if (a == null || b == null) return false;\n const lo = Math.min(a, b);\n const hi = Math.max(a, b);\n return num < lo || num > hi;\n }\n default:\n return false;\n }\n}\n\n/**\n * Resolve the merged style for a value given an ordered rule list.\n * Later matching rules override earlier ones (last-wins), so order rules from\n * general to specific. Returns `undefined` when nothing matches.\n */\nexport function resolveConditionalStyle(\n rawValue: unknown,\n rules: ConditionalRule[] | undefined,\n rowData?: Record<string, unknown>\n): ConditionalStyle | undefined {\n if (!rules?.length) return undefined;\n let merged: ConditionalStyle | undefined;\n for (const rule of rules) {\n if (evaluateRule(rawValue, rule, rowData)) {\n merged = { ...merged, ...rule.style };\n }\n }\n return merged;\n}\n\n// ============================================================================\n// Intent → presentation mapping (theme-safe)\n// ============================================================================\n\n/** CSS variable for a semantic intent's solid color (charts/SVG). */\nexport function intentToCssVar(intent: SemanticIntent): string {\n switch (intent) {\n case 'success':\n return 'var(--color-status-success)';\n case 'warning':\n return 'var(--color-status-warning)';\n case 'danger':\n return 'var(--color-status-error)';\n case 'info':\n return 'var(--color-status-info)';\n case 'neutral':\n default:\n return 'var(--color-text-secondary)';\n }\n}\n\nconst TEXT_CLASS: Record<SemanticIntent, string> = {\n success: 'text-status-success-text',\n warning: 'text-status-warning-text',\n danger: 'text-status-error-text',\n info: 'text-status-info-text',\n neutral: 'text-text-secondary',\n};\n\nconst BG_CLASS: Record<SemanticIntent, string> = {\n success: 'bg-status-success-bg',\n warning: 'bg-status-warning-bg',\n danger: 'bg-status-error-bg',\n info: 'bg-status-info-bg',\n neutral: 'bg-bg-sunken',\n};\n\n/** Build the Tailwind className fragment for a resolved style (DOM cells). */\nexport function conditionalStyleToClassName(style: ConditionalStyle | undefined): string {\n if (!style) return '';\n const parts: string[] = [];\n if (style.textColor) parts.push(TEXT_CLASS[style.textColor]);\n if (style.bgColor) parts.push(BG_CLASS[style.bgColor]);\n if (style.bold) parts.push('font-semibold');\n return parts.join(' ');\n}\n\n/** Subtle background fill class per intent — used for whole-row highlighting. */\nconst ROW_BG_CLASS: Record<SemanticIntent, string> = {\n success: 'bg-status-success-bg-subtle',\n warning: 'bg-status-warning-bg-subtle',\n danger: 'bg-status-error-bg-subtle',\n info: 'bg-status-info-bg-subtle',\n neutral: 'bg-bg-sunken',\n};\n\n/** Left-edge accent border class per intent — used for whole-row highlighting. */\nconst ROW_ACCENT_CLASS: Record<SemanticIntent, string> = {\n success: 'border-l-4 border-status-success-border',\n warning: 'border-l-4 border-status-warning-border',\n danger: 'border-l-4 border-status-error-border',\n info: 'border-l-4 border-status-info-border',\n neutral: 'border-l-4 border-border-default',\n};\n\n/**\n * Resolve a `<tr>`-level className for a whole row given an ordered rule list.\n * Each rule's `field` is tested against the row; the merged style's `bgColor`\n * (falling back to `textColor`) paints a subtle fill and adds a matching\n * left-edge accent bar, with `bold` emphasising the row text. Returns `''`\n * when nothing matches so default striped row styling is preserved. This is\n * the escalation surface that renders boarding-breach rows in red.\n */\nexport function resolveRowClassName(row: Record<string, unknown>, rules: ConditionalRule[] | undefined): string {\n const style = resolveConditionalStyle(undefined, rules, row);\n if (!style) return '';\n const parts: string[] = [];\n const fill = style.bgColor ?? style.textColor;\n if (fill) {\n parts.push(ROW_BG_CLASS[fill]);\n parts.push(ROW_ACCENT_CLASS[fill]);\n }\n if (style.textColor) parts.push(TEXT_CLASS[style.textColor]);\n if (style.bold) parts.push('font-semibold');\n return parts.join(' ');\n}\n\n/** SVG paths for the supported conditional icons (16x16 viewBox 0 0 24 24). */\nexport const CONDITIONAL_ICON_PATHS: Record<ConditionalIcon, string> = {\n 'arrow-up': 'M5 15l7-7 7 7',\n 'arrow-down': 'M19 9l-7 7-7-7',\n flag: 'M3 21V5a2 2 0 012-2h11l-2 4 2 4H5',\n check: 'M5 13l4 4L19 7',\n alert: 'M12 9v4m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z',\n dot: 'M12 12m-4 0a4 4 0 108 0a4 4 0 10-8 0',\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"conditionalFormat.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/utils/conditionalFormat.ts"],"sourcesContent":["/**\n * Conditional Formatting Engine (shared)\n *\n * Rule-based styling shared across Table, Chart, KPI and Metric widgets.\n * Rules are stored on the widget `config` (e.g. `config.conditionalRules`) and\n * evaluated per data point. Colors are expressed as *semantic intents*\n * (success/warning/danger/info/neutral) — never raw hex — so theming and\n * dark-mode keep working. The intent is resolved to either a Tailwind class\n * (for DOM cells) or a CSS variable (for SVG charts) at render time.\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Comparison operators supported by a conditional rule. */\nexport type ConditionalOperator =\n | 'gt'\n | 'gte'\n | 'lt'\n | 'lte'\n | 'eq'\n | 'neq'\n | 'between'\n | 'outside'\n | 'contains'\n | 'notContains'\n | 'startsWith'\n | 'endsWith'\n | 'isEmpty'\n | 'isNotEmpty';\n\n/**\n * Semantic color intent. Maps to `--color-status-*` / neutral tokens so the\n * result is theme-aware. Raw colors are intentionally NOT allowed here.\n */\nexport type SemanticIntent = 'success' | 'warning' | 'danger' | 'info' | 'neutral';\n\n/** Icon hint rendered alongside a matched value. */\nexport type ConditionalIcon = 'arrow-up' | 'arrow-down' | 'flag' | 'check' | 'alert' | 'dot';\n\nexport interface ConditionalStyle {\n /** Text color intent. */\n textColor?: SemanticIntent;\n /** Background color intent (subtle fill). */\n bgColor?: SemanticIntent;\n /** Bold the matched value. */\n bold?: boolean;\n /** Icon hint to render before the value. */\n icon?: ConditionalIcon;\n /** Render an in-cell data bar scaled against `dataBarMax`. */\n dataBar?: boolean;\n /** Color intent for the data bar (defaults to `info`). */\n dataBarColor?: SemanticIntent;\n}\n\nexport interface ConditionalRule {\n /** Optional stable id (UI keying). */\n id?: string;\n /**\n * Field to test. When omitted, the rule tests the value it is applied to\n * (e.g. the current cell value or series value).\n */\n field?: string;\n /** Comparison operator. */\n operator: ConditionalOperator;\n /** Comparison operand (primary). */\n value?: string | number;\n /** Second operand for `between` / `outside`. */\n value2?: string | number;\n /** Styling applied when the rule matches. */\n style: ConditionalStyle;\n}\n\n// ============================================================================\n// Evaluation\n// ============================================================================\n\nfunction toNumber(v: unknown): number | null {\n if (typeof v === 'number') return Number.isNaN(v) ? null : v;\n if (typeof v === 'string' && v.trim() !== '') {\n const n = Number(v);\n return Number.isNaN(n) ? null : n;\n }\n return null;\n}\n\n/** Evaluate a single rule against a candidate value. */\nexport function evaluateRule(rawValue: unknown, rule: ConditionalRule, rowData?: Record<string, unknown>): boolean {\n // Resolve the value being tested: explicit field on the row, else the raw value.\n const candidate = rule.field != null && rowData ? rowData[rule.field] : rawValue;\n\n switch (rule.operator) {\n case 'isEmpty':\n return candidate == null || candidate === '';\n case 'isNotEmpty':\n return candidate != null && candidate !== '';\n case 'contains':\n return String(candidate ?? '')\n .toLowerCase()\n .includes(String(rule.value ?? '').toLowerCase());\n case 'notContains':\n return !String(candidate ?? '')\n .toLowerCase()\n .includes(String(rule.value ?? '').toLowerCase());\n case 'startsWith':\n return String(candidate ?? '')\n .toLowerCase()\n .startsWith(String(rule.value ?? '').toLowerCase());\n case 'endsWith':\n return String(candidate ?? '')\n .toLowerCase()\n .endsWith(String(rule.value ?? '').toLowerCase());\n default:\n break;\n }\n\n // Equality works for both strings and numbers.\n if (rule.operator === 'eq' || rule.operator === 'neq') {\n const num = toNumber(candidate);\n const ruleNum = toNumber(rule.value);\n const equal =\n num != null && ruleNum != null ? num === ruleNum : String(candidate ?? '') === String(rule.value ?? '');\n return rule.operator === 'eq' ? equal : !equal;\n }\n\n // Remaining operators are numeric.\n const num = toNumber(candidate);\n if (num == null) return false;\n const a = toNumber(rule.value);\n\n switch (rule.operator) {\n case 'gt':\n return a != null && num > a;\n case 'gte':\n return a != null && num >= a;\n case 'lt':\n return a != null && num < a;\n case 'lte':\n return a != null && num <= a;\n case 'between': {\n const b = toNumber(rule.value2);\n if (a == null || b == null) return false;\n const lo = Math.min(a, b);\n const hi = Math.max(a, b);\n return num >= lo && num <= hi;\n }\n case 'outside': {\n const b = toNumber(rule.value2);\n if (a == null || b == null) return false;\n const lo = Math.min(a, b);\n const hi = Math.max(a, b);\n return num < lo || num > hi;\n }\n default:\n return false;\n }\n}\n\n/**\n * Resolve the merged style for a value given an ordered rule list.\n * Later matching rules override earlier ones (last-wins), so order rules from\n * general to specific. Returns `undefined` when nothing matches.\n */\nexport function resolveConditionalStyle(\n rawValue: unknown,\n rules: ConditionalRule[] | undefined,\n rowData?: Record<string, unknown>\n): ConditionalStyle | undefined {\n if (!rules?.length) return undefined;\n let merged: ConditionalStyle | undefined;\n for (const rule of rules) {\n if (evaluateRule(rawValue, rule, rowData)) {\n merged = { ...merged, ...rule.style };\n }\n }\n return merged;\n}\n\n// ============================================================================\n// Intent → presentation mapping (theme-safe)\n// ============================================================================\n\n/** CSS variable for a semantic intent's solid color (charts/SVG). */\nexport function intentToCssVar(intent: SemanticIntent): string {\n switch (intent) {\n case 'success':\n return 'var(--color-status-success)';\n case 'warning':\n return 'var(--color-status-warning)';\n case 'danger':\n return 'var(--color-status-error)';\n case 'info':\n return 'var(--color-status-info)';\n case 'neutral':\n default:\n return 'var(--color-text-secondary)';\n }\n}\n\nconst TEXT_CLASS: Record<SemanticIntent, string> = {\n success: 'text-status-success-text',\n warning: 'text-[var(--color-status-warning-text)]',\n danger: 'text-status-error-text',\n info: 'text-[var(--color-status-info-text)]',\n neutral: 'text-text-secondary',\n};\n\nconst BG_CLASS: Record<SemanticIntent, string> = {\n success: 'bg-status-success-bg',\n warning: 'bg-status-warning-bg',\n danger: 'bg-status-error-bg',\n info: 'bg-status-info-bg',\n neutral: 'bg-bg-sunken',\n};\n\n/** Build the Tailwind className fragment for a resolved style (DOM cells). */\nexport function conditionalStyleToClassName(style: ConditionalStyle | undefined): string {\n if (!style) return '';\n const parts: string[] = [];\n if (style.textColor) parts.push(TEXT_CLASS[style.textColor]);\n if (style.bgColor) parts.push(BG_CLASS[style.bgColor]);\n if (style.bold) parts.push('font-semibold');\n return parts.join(' ');\n}\n\n/** Subtle background fill class per intent — used for whole-row highlighting. */\nconst ROW_BG_CLASS: Record<SemanticIntent, string> = {\n success: 'bg-status-success-bg-subtle',\n warning: 'bg-status-warning-bg-subtle',\n danger: 'bg-status-error-bg-subtle',\n info: 'bg-status-info-bg-subtle',\n neutral: 'bg-bg-sunken',\n};\n\n/** Left-edge accent border class per intent — used for whole-row highlighting. */\nconst ROW_ACCENT_CLASS: Record<SemanticIntent, string> = {\n success: 'border-l-4 border-status-success-border',\n warning: 'border-l-4 border-status-warning-border',\n danger: 'border-l-4 border-status-error-border',\n info: 'border-l-4 border-status-info-border',\n neutral: 'border-l-4 border-border-default',\n};\n\n/**\n * Resolve a `<tr>`-level className for a whole row given an ordered rule list.\n * Each rule's `field` is tested against the row; the merged style's `bgColor`\n * (falling back to `textColor`) paints a subtle fill and adds a matching\n * left-edge accent bar, with `bold` emphasising the row text. Returns `''`\n * when nothing matches so default striped row styling is preserved. This is\n * the escalation surface that renders boarding-breach rows in red.\n */\nexport function resolveRowClassName(row: Record<string, unknown>, rules: ConditionalRule[] | undefined): string {\n const style = resolveConditionalStyle(undefined, rules, row);\n if (!style) return '';\n const parts: string[] = [];\n const fill = style.bgColor ?? style.textColor;\n if (fill) {\n parts.push(ROW_BG_CLASS[fill]);\n parts.push(ROW_ACCENT_CLASS[fill]);\n }\n if (style.textColor) parts.push(TEXT_CLASS[style.textColor]);\n if (style.bold) parts.push('font-semibold');\n return parts.join(' ');\n}\n\n/** SVG paths for the supported conditional icons (16x16 viewBox 0 0 24 24). */\nexport const CONDITIONAL_ICON_PATHS: Record<ConditionalIcon, string> = {\n 'arrow-up': 'M5 15l7-7 7 7',\n 'arrow-down': 'M19 9l-7 7-7-7',\n flag: 'M3 21V5a2 2 0 012-2h11l-2 4 2 4H5',\n check: 'M5 13l4 4L19 7',\n alert: 'M12 9v4m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z',\n dot: 'M12 12m-4 0a4 4 0 108 0a4 4 0 10-8 0',\n};\n"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ //#region src/bigconsole/components/widgets/utils/targetProgress.ts
2
+ function e(e, t) {
3
+ if (typeof e != "number" || !Number.isFinite(e) || t === void 0 || t === 0 || !Number.isFinite(t)) return null;
4
+ let n = e / t * 100;
5
+ return Number.isFinite(n) ? n : null;
6
+ }
7
+ function t(e) {
8
+ return Math.min(Math.max(e, 0), 100);
9
+ }
10
+ //#endregion
11
+ export { t as clampProgressWidth, e as getTargetProgress };
12
+
13
+ //# sourceMappingURL=targetProgress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targetProgress.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/utils/targetProgress.ts"],"sourcesContent":["/**\n * Shared target-progress maths for widgets that render a \"vs target\" bar.\n *\n * Kept in one place so the KPI comparison and metric card widgets cannot drift\n * apart on the guard conditions — both previously divided by the target with no\n * protection and rendered \"NaN%\" / \"Infinity%\".\n */\n\n/**\n * Progress toward a target, as a percentage.\n *\n * Returns null whenever no meaningful ratio exists, so callers can suppress the\n * whole target block rather than render a broken figure:\n * - a non-numeric value (parser output may be a string, e.g. a status flag)\n * - an absent, zero or non-finite target (JSON payloads carry `0` and `null`)\n *\n * `Number.isFinite` does not coerce, so a runtime `null` is rejected too.\n */\nexport function getTargetProgress(value: number | string | undefined, target: number | undefined): number | null {\n if (typeof value !== 'number' || !Number.isFinite(value)) return null;\n // Order matters: the `undefined` check narrows `target` to `number`, so no\n // cast is needed (`Number.isFinite` is not a TypeScript type guard).\n if (target === undefined || target === 0 || !Number.isFinite(target)) return null;\n const progress = (value / target) * 100;\n return Number.isFinite(progress) ? progress : null;\n}\n\n/**\n * Clamp a progress percentage to a CSS-safe bar width.\n *\n * A negative value would otherwise emit a negative width, which the browser\n * drops entirely, leaving the bar at its previous size.\n */\nexport function clampProgressWidth(progress: number): number {\n return Math.min(Math.max(progress, 0), 100);\n}\n"],"mappings":";AAkBA,SAAgB,EAAkB,GAAoC,GAA2C;AAI/G,KAHI,OAAO,KAAU,YAAY,CAAC,OAAO,SAAS,EAAM,IAGpD,MAAW,KAAA,KAAa,MAAW,KAAK,CAAC,OAAO,SAAS,EAAO,CAAE,QAAO;CAC7E,IAAM,IAAY,IAAQ,IAAU;AACpC,QAAO,OAAO,SAAS,EAAS,GAAG,IAAW;;AAShD,SAAgB,EAAmB,GAA0B;AAC3D,QAAO,KAAK,IAAI,KAAK,IAAI,GAAU,EAAE,EAAE,IAAI"}
@@ -5,29 +5,26 @@ import { Fragment as a, jsx as o, jsxs as s } from "react/jsx-runtime";
5
5
  //#region src/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.tsx
6
6
  var c = {
7
7
  container: {
8
- padding: "16px",
9
- backgroundColor: "var(--color-bg-surface)",
10
- borderRadius: "8px"
8
+ display: "flex",
9
+ flexDirection: "column",
10
+ gap: "var(--space-formGap)",
11
+ minWidth: 0
11
12
  },
12
13
  header: {
13
14
  display: "flex",
14
- justifyContent: "space-between",
15
+ flexWrap: "wrap",
16
+ justifyContent: "flex-end",
15
17
  alignItems: "center",
16
- marginBottom: "16px"
17
- },
18
- title: {
19
- fontSize: "16px",
20
- fontWeight: 600,
21
- color: "var(--color-text-primary)",
22
- margin: 0
18
+ gap: "var(--space-controlGap)"
23
19
  },
24
20
  addButton: {
25
- padding: "8px 16px",
21
+ minHeight: "var(--size-controlHeight-md)",
22
+ padding: "0 var(--space-formGap)",
26
23
  backgroundColor: "var(--color-action-primary-bg)",
27
- color: "var(--color-text-inverse)",
24
+ color: "var(--color-action-primary-text)",
28
25
  border: "none",
29
- borderRadius: "6px",
30
- fontSize: "14px",
26
+ borderRadius: "var(--radius-button)",
27
+ fontSize: "var(--font-size-body-sm)",
31
28
  fontWeight: 500,
32
29
  cursor: "pointer"
33
30
  },
@@ -37,26 +34,33 @@ var c = {
37
34
  gap: "12px"
38
35
  },
39
36
  webhookCard: {
40
- padding: "16px",
41
- backgroundColor: "var(--color-bg-subtle)",
42
- borderRadius: "8px",
43
- border: "1px solid var(--color-border-subtle)"
37
+ padding: "var(--space-cardPadding)",
38
+ backgroundColor: "var(--color-bg-sunken)",
39
+ borderRadius: "var(--radius-card)",
40
+ border: "1px solid var(--color-border-subtle)",
41
+ minWidth: 0
44
42
  },
45
43
  webhookHeader: {
46
44
  display: "flex",
45
+ flexWrap: "wrap",
47
46
  justifyContent: "space-between",
48
47
  alignItems: "flex-start",
49
- marginBottom: "8px"
48
+ gap: "var(--space-iconGap)",
49
+ marginBottom: "8px",
50
+ minWidth: 0
50
51
  },
51
52
  webhookTitle: {
52
53
  display: "flex",
54
+ flexWrap: "wrap",
53
55
  alignItems: "center",
54
- gap: "8px"
56
+ gap: "8px",
57
+ minWidth: 0
55
58
  },
56
59
  webhookName: {
57
- fontSize: "14px",
60
+ fontSize: "var(--font-size-body-sm)",
58
61
  fontWeight: 600,
59
- color: "var(--color-text-primary)"
62
+ color: "var(--color-text-primary)",
63
+ wordBreak: "break-word"
60
64
  },
61
65
  statusBadge: {
62
66
  padding: "2px 8px",
@@ -73,26 +77,28 @@ var c = {
73
77
  color: "var(--color-status-warning-text)"
74
78
  },
75
79
  webhookDetails: {
76
- fontSize: "13px",
77
- color: "var(--color-text-muted)",
80
+ fontSize: "var(--font-size-body-sm)",
81
+ color: "var(--color-text-secondary)",
78
82
  marginBottom: "4px"
79
83
  },
80
84
  webhookUrl: {
81
- fontSize: "12px",
82
- color: "var(--color-text-placeholder)",
83
- fontFamily: "monospace",
85
+ fontSize: "var(--font-size-body-sm)",
86
+ color: "var(--color-text-muted)",
87
+ fontFamily: "var(--font-family-mono)",
84
88
  wordBreak: "break-all"
85
89
  },
86
90
  webhookActions: {
87
91
  display: "flex",
92
+ flexWrap: "wrap",
88
93
  gap: "8px",
89
94
  marginTop: "12px"
90
95
  },
91
96
  actionButton: {
92
- padding: "6px 12px",
93
- fontSize: "12px",
97
+ minHeight: "var(--size-controlHeight-md)",
98
+ padding: "0 12px",
99
+ fontSize: "var(--font-size-body-sm)",
94
100
  fontWeight: 500,
95
- borderRadius: "4px",
101
+ borderRadius: "var(--radius-button)",
96
102
  border: "none",
97
103
  cursor: "pointer"
98
104
  },
@@ -114,14 +120,24 @@ var c = {
114
120
  },
115
121
  emptyState: {
116
122
  textAlign: "center",
117
- padding: "32px",
118
- color: "var(--color-text-placeholder)"
123
+ padding: "var(--space-pagePadding) var(--space-formGap)",
124
+ color: "var(--color-text-secondary)",
125
+ backgroundColor: "var(--color-status-info-bgSubtle)",
126
+ border: "1px solid var(--color-status-info-border)",
127
+ borderRadius: "var(--radius-card)"
128
+ },
129
+ emptyTitle: {
130
+ fontSize: "var(--font-size-body-sm)",
131
+ fontWeight: 600,
132
+ color: "var(--color-status-info-text)",
133
+ margin: 0
119
134
  },
120
135
  form: {
121
- padding: "16px",
122
- backgroundColor: "var(--color-bg-subtle)",
123
- borderRadius: "8px",
124
- marginBottom: "16px"
136
+ padding: "var(--space-cardPadding)",
137
+ backgroundColor: "var(--color-bg-sunken)",
138
+ border: "1px solid var(--color-border-subtle)",
139
+ borderRadius: "var(--radius-card)",
140
+ minWidth: 0
125
141
  },
126
142
  formGroup: { marginBottom: "12px" },
127
143
  label: {
@@ -133,54 +149,64 @@ var c = {
133
149
  },
134
150
  input: {
135
151
  width: "100%",
152
+ minHeight: "var(--size-controlHeight-md)",
136
153
  padding: "8px 12px",
137
- fontSize: "14px",
138
- border: "1px solid var(--color-border-default)",
139
- borderRadius: "6px",
154
+ fontSize: "var(--font-size-body-sm)",
155
+ color: "var(--color-text-primary)",
156
+ backgroundColor: "var(--color-bg-surface)",
157
+ border: "1px solid var(--color-border-subtle)",
158
+ borderRadius: "var(--radius-input)",
140
159
  boxSizing: "border-box"
141
160
  },
142
161
  select: {
143
162
  width: "100%",
163
+ minHeight: "var(--size-controlHeight-md)",
144
164
  padding: "8px 12px",
145
- fontSize: "14px",
146
- border: "1px solid var(--color-border-default)",
147
- borderRadius: "6px",
165
+ fontSize: "var(--font-size-body-sm)",
166
+ color: "var(--color-text-primary)",
167
+ border: "1px solid var(--color-border-subtle)",
168
+ borderRadius: "var(--radius-input)",
148
169
  boxSizing: "border-box",
149
170
  backgroundColor: "var(--color-bg-surface)"
150
171
  },
151
172
  textarea: {
152
173
  width: "100%",
153
174
  padding: "8px 12px",
154
- fontSize: "14px",
155
- border: "1px solid var(--color-border-default)",
156
- borderRadius: "6px",
175
+ fontSize: "var(--font-size-body-sm)",
176
+ color: "var(--color-text-primary)",
177
+ backgroundColor: "var(--color-bg-surface)",
178
+ border: "1px solid var(--color-border-subtle)",
179
+ borderRadius: "var(--radius-input)",
157
180
  boxSizing: "border-box",
158
- fontFamily: "monospace",
181
+ fontFamily: "var(--font-family-mono)",
159
182
  minHeight: "80px",
160
183
  resize: "vertical"
161
184
  },
162
185
  formActions: {
163
186
  display: "flex",
187
+ flexWrap: "wrap",
164
188
  gap: "8px",
165
189
  justifyContent: "flex-end",
166
- marginTop: "16px"
190
+ marginTop: "var(--space-formGap)"
167
191
  },
168
192
  cancelButton: {
169
- padding: "8px 16px",
170
- backgroundColor: "var(--color-bg-sunken)",
193
+ minHeight: "var(--size-controlHeight-md)",
194
+ padding: "0 var(--space-formGap)",
195
+ backgroundColor: "var(--color-bg-surface)",
171
196
  color: "var(--color-text-primary)",
172
- border: "none",
173
- borderRadius: "6px",
174
- fontSize: "14px",
197
+ border: "1px solid var(--color-border-subtle)",
198
+ borderRadius: "var(--radius-button)",
199
+ fontSize: "var(--font-size-body-sm)",
175
200
  cursor: "pointer"
176
201
  },
177
202
  saveButton: {
178
- padding: "8px 16px",
203
+ minHeight: "var(--size-controlHeight-md)",
204
+ padding: "0 var(--space-formGap)",
179
205
  backgroundColor: "var(--color-action-primary-bg)",
180
- color: "var(--color-text-inverse)",
206
+ color: "var(--color-action-primary-text)",
181
207
  border: "none",
182
- borderRadius: "6px",
183
- fontSize: "14px",
208
+ borderRadius: "var(--radius-button)",
209
+ fontSize: "var(--font-size-body-sm)",
184
210
  fontWeight: 500,
185
211
  cursor: "pointer"
186
212
  },
@@ -337,23 +363,16 @@ var c = {
337
363
  style: c.webhookHeader,
338
364
  children: /* @__PURE__ */ s("div", {
339
365
  style: c.webhookTitle,
340
- children: [
341
- /* @__PURE__ */ o("span", {
342
- style: { fontSize: "16px" },
343
- children: "📡"
344
- }),
345
- /* @__PURE__ */ o("span", {
346
- style: c.webhookName,
347
- children: e.eventPattern
348
- }),
349
- /* @__PURE__ */ o("span", {
350
- style: {
351
- ...c.statusBadge,
352
- ...e.isActive ? c.activeBadge : c.inactiveBadge
353
- },
354
- children: e.isActive ? f("bigconsole.widget.webhookConfig.active", "Active") : f("bigconsole.widget.webhookConfig.inactive", "Inactive")
355
- })
356
- ]
366
+ children: [/* @__PURE__ */ o("span", {
367
+ style: c.webhookName,
368
+ children: e.eventPattern
369
+ }), /* @__PURE__ */ o("span", {
370
+ style: {
371
+ ...c.statusBadge,
372
+ ...e.isActive ? c.activeBadge : c.inactiveBadge
373
+ },
374
+ children: e.isActive ? f("bigconsole.widget.webhookConfig.active", "Active") : f("bigconsole.widget.webhookConfig.inactive", "Inactive")
375
+ })]
357
376
  })
358
377
  }),
359
378
  /* @__PURE__ */ s("div", {
@@ -369,14 +388,15 @@ var c = {
369
388
  children: e.webhookUrl
370
389
  }),
371
390
  u && /* @__PURE__ */ o("div", {
391
+ role: "status",
372
392
  style: {
373
393
  ...c.testResult,
374
394
  ...u.success ? c.testSuccess : c.testFailure
375
395
  },
376
- children: u.success ? /* @__PURE__ */ o(a, { children: f("bigconsole.widget.webhookConfig.testSuccess", "Test successful! Status: {{statusCode}}, Latency: {{latencyMs}}ms", {
396
+ children: u.success ? /* @__PURE__ */ o(a, { children: f("bigconsole.widget.webhookConfig.testSuccess", "Test successful! Status: {{statusCode}}, Latency: {{latencyMs}}ms", {
377
397
  statusCode: u.statusCode ?? "",
378
398
  latencyMs: u.latencyMs ?? ""
379
- }) }) : /* @__PURE__ */ o(a, { children: f("bigconsole.widget.webhookConfig.testFailure", "Test failed: {{error}}", { error: u.errorMessage || f("bigconsole.widget.webhookConfig.unknownError", "Unknown error") }) })
399
+ }) }) : /* @__PURE__ */ o(a, { children: f("bigconsole.widget.webhookConfig.testFailure", "Test failed: {{error}}", { error: u.errorMessage || f("bigconsole.widget.webhookConfig.unknownError", "Unknown error") }) })
380
400
  }),
381
401
  /* @__PURE__ */ s("div", {
382
402
  style: c.webhookActions,
@@ -454,17 +474,16 @@ var c = {
454
474
  }, []);
455
475
  return /* @__PURE__ */ s("div", {
456
476
  style: c.container,
477
+ "data-testid": "webhook-config-panel",
457
478
  children: [
458
- /* @__PURE__ */ s("div", {
479
+ !m && /* @__PURE__ */ o("div", {
459
480
  style: c.header,
460
- children: [/* @__PURE__ */ o("h3", {
461
- style: c.title,
462
- children: p("bigconsole.widget.webhookConfig.title", "Webhook Configuration")
463
- }), !m && /* @__PURE__ */ o("button", {
481
+ children: /* @__PURE__ */ o("button", {
482
+ type: "button",
464
483
  onClick: () => h(!0),
465
484
  style: c.addButton,
466
485
  children: p("bigconsole.widget.webhookConfig.addWebhook", "+ Add Webhook")
467
- })]
486
+ })
468
487
  }),
469
488
  m && /* @__PURE__ */ o(l, {
470
489
  webhook: g || void 0,
@@ -476,12 +495,20 @@ var c = {
476
495
  }),
477
496
  C && S.length === 0 ? /* @__PURE__ */ o("div", {
478
497
  style: c.emptyState,
479
- children: p("bigconsole.widget.webhookConfig.loading", "Loading...")
498
+ role: "status",
499
+ children: /* @__PURE__ */ o("p", {
500
+ style: c.emptyTitle,
501
+ children: p("bigconsole.widget.webhookConfig.loading", "Loading...")
502
+ })
480
503
  }) : S.length === 0 ? /* @__PURE__ */ s("div", {
481
504
  style: c.emptyState,
482
- children: [/* @__PURE__ */ o("p", { children: p("bigconsole.widget.webhookConfig.noWebhooks", "No webhooks configured") }), /* @__PURE__ */ o("p", {
505
+ role: "status",
506
+ children: [/* @__PURE__ */ o("p", {
507
+ style: c.emptyTitle,
508
+ children: p("bigconsole.widget.webhookConfig.noWebhooks", "No webhooks configured")
509
+ }), /* @__PURE__ */ o("p", {
483
510
  style: {
484
- fontSize: "13px",
511
+ fontSize: "var(--font-size-body-sm)",
485
512
  marginTop: "8px"
486
513
  },
487
514
  children: p("bigconsole.widget.webhookConfig.noWebhooksHelp", "Add a webhook to receive events when actions are triggered.")