@burdenoff/microfe-bigconsole 2026.805.3 → 2026.812.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (232) 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 +712 -803
  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/WidgetWrapper.js +8 -7
  125. package/dist/bigconsole/components/widgets/WidgetWrapper.js.map +1 -1
  126. package/dist/bigconsole/components/widgets/adaptive-card/AdaptiveCardWidget.js +1 -1
  127. package/dist/bigconsole/components/widgets/adaptive-card/AdaptiveCardWidget.js.map +1 -1
  128. package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js +2 -2
  129. package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js.map +1 -1
  130. package/dist/bigconsole/components/widgets/chart/ChartConfig.js +11 -5
  131. package/dist/bigconsole/components/widgets/chart/ChartConfig.js.map +1 -1
  132. package/dist/bigconsole/components/widgets/comments/WidgetComments.js +19 -15
  133. package/dist/bigconsole/components/widgets/comments/WidgetComments.js.map +1 -1
  134. package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js +154 -102
  135. package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js.map +1 -1
  136. package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js +28 -13
  137. package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js.map +1 -1
  138. package/dist/bigconsole/components/widgets/gauge/GaugeWidget.js +1 -1
  139. package/dist/bigconsole/components/widgets/gauge/GaugeWidget.js.map +1 -1
  140. package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js +35 -24
  141. package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js.map +1 -1
  142. package/dist/bigconsole/components/widgets/iframe-widget/IframeWidget.js +2 -2
  143. package/dist/bigconsole/components/widgets/iframe-widget/IframeWidget.js.map +1 -1
  144. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +4 -4
  145. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js.map +1 -1
  146. package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js +2 -2
  147. package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js.map +1 -1
  148. package/dist/bigconsole/components/widgets/list/ListConfig.js +8 -2
  149. package/dist/bigconsole/components/widgets/list/ListConfig.js.map +1 -1
  150. package/dist/bigconsole/components/widgets/list/ListItem.js +1 -1
  151. package/dist/bigconsole/components/widgets/list/ListItem.js.map +1 -1
  152. package/dist/bigconsole/components/widgets/map-widget/MapWidget.js +1 -1
  153. package/dist/bigconsole/components/widgets/map-widget/MapWidget.js.map +1 -1
  154. package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js +9 -3
  155. package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js.map +1 -1
  156. package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js +3 -3
  157. package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js.map +1 -1
  158. package/dist/bigconsole/components/widgets/progress/ProgressConfig.js +34 -25
  159. package/dist/bigconsole/components/widgets/progress/ProgressConfig.js.map +1 -1
  160. package/dist/bigconsole/components/widgets/retention/RetentionWidget.js +3 -3
  161. package/dist/bigconsole/components/widgets/retention/RetentionWidget.js.map +1 -1
  162. package/dist/bigconsole/components/widgets/states/EmptyState.js +6 -4
  163. package/dist/bigconsole/components/widgets/states/EmptyState.js.map +1 -1
  164. package/dist/bigconsole/components/widgets/states/ErrorState.js +7 -5
  165. package/dist/bigconsole/components/widgets/states/ErrorState.js.map +1 -1
  166. package/dist/bigconsole/components/widgets/states/LoadingState.js +5 -4
  167. package/dist/bigconsole/components/widgets/states/LoadingState.js.map +1 -1
  168. package/dist/bigconsole/components/widgets/table/TableConfig.js +10 -4
  169. package/dist/bigconsole/components/widgets/table/TableConfig.js.map +1 -1
  170. package/dist/bigconsole/components/widgets/table/TableHeader.js +1 -1
  171. package/dist/bigconsole/components/widgets/table/TableHeader.js.map +1 -1
  172. package/dist/bigconsole/components/widgets/table/TableWidget.js +1 -1
  173. package/dist/bigconsole/components/widgets/table/TableWidget.js.map +1 -1
  174. package/dist/bigconsole/components/widgets/text-widget/TextWidget.js +1 -1
  175. package/dist/bigconsole/components/widgets/text-widget/TextWidget.js.map +1 -1
  176. package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js +3 -3
  177. package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js.map +1 -1
  178. package/dist/bigconsole/components/widgets/utils/conditionalFormat.js +2 -2
  179. package/dist/bigconsole/components/widgets/utils/conditionalFormat.js.map +1 -1
  180. package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js +112 -85
  181. package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js.map +1 -1
  182. package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js +28 -20
  183. package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js.map +1 -1
  184. package/dist/bigconsole/components/workflow/WorkflowCard.js +92 -77
  185. package/dist/bigconsole/components/workflow/WorkflowCard.js.map +1 -1
  186. package/dist/bigconsole/components/workflow/WorkflowDeleteDialog.js +70 -51
  187. package/dist/bigconsole/components/workflow/WorkflowDeleteDialog.js.map +1 -1
  188. package/dist/bigconsole/components/workflow/WorkflowStatusBadge.js +16 -17
  189. package/dist/bigconsole/components/workflow/WorkflowStatusBadge.js.map +1 -1
  190. package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js +6 -4
  191. package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js.map +1 -1
  192. package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js +360 -338
  193. package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js.map +1 -1
  194. package/dist/bigconsole/hooks/useModalFocusTrap.js +53 -0
  195. package/dist/bigconsole/hooks/useModalFocusTrap.js.map +1 -0
  196. package/dist/bigconsole/pages/DashboardBuilderPage.js +209 -203
  197. package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
  198. package/dist/bigconsole/pages/DashboardViewPage.js +126 -120
  199. package/dist/bigconsole/pages/DashboardViewPage.js.map +1 -1
  200. package/dist/bigconsole/pages/DashboardsPage.js +838 -800
  201. package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
  202. package/dist/bigconsole/pages/DataParsersPage.js +263 -315
  203. package/dist/bigconsole/pages/DataParsersPage.js.map +1 -1
  204. package/dist/bigconsole/pages/DataSinkBuilderPage.js +301 -341
  205. package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
  206. package/dist/bigconsole/pages/DataSinkViewPage.js +346 -339
  207. package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
  208. package/dist/bigconsole/pages/DataSinksPage.js +356 -458
  209. package/dist/bigconsole/pages/DataSinksPage.js.map +1 -1
  210. package/dist/bigconsole/pages/DataSourcesPage.js +7 -2
  211. package/dist/bigconsole/pages/DataSourcesPage.js.map +1 -1
  212. package/dist/bigconsole/pages/HomePage.js +186 -193
  213. package/dist/bigconsole/pages/HomePage.js.map +1 -1
  214. package/dist/bigconsole/pages/InsightsPage.js +887 -740
  215. package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
  216. package/dist/bigconsole/pages/ParserBuilderPage.js +679 -637
  217. package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
  218. package/dist/bigconsole/pages/ParserViewPage.js +368 -342
  219. package/dist/bigconsole/pages/ParserViewPage.js.map +1 -1
  220. package/dist/bigconsole/pages/PipelineBuilderPage.js +537 -444
  221. package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
  222. package/dist/bigconsole/pages/PipelineViewPage.js +412 -377
  223. package/dist/bigconsole/pages/PipelineViewPage.js.map +1 -1
  224. package/dist/bigconsole/pages/PipelinesPage.js +248 -298
  225. package/dist/bigconsole/pages/PipelinesPage.js.map +1 -1
  226. package/dist/bigconsole/pages/WidgetDemoPage.js +251 -153
  227. package/dist/bigconsole/pages/WidgetDemoPage.js.map +1 -1
  228. package/dist/bigconsole/pages/WorkflowViewPage.js +381 -371
  229. package/dist/bigconsole/pages/WorkflowViewPage.js.map +1 -1
  230. package/dist/bigconsole/pages/WorkflowsPage.js +171 -286
  231. package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
  232. package/package.json +1 -1
@@ -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":"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"}
@@ -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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"}
@@ -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.")