@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.
- package/dist/bigconsole/components/DrilldownDashboardRenderer.js +118 -106
- package/dist/bigconsole/components/DrilldownDashboardRenderer.js.map +1 -1
- package/dist/bigconsole/components/DrilldownModal.js +54 -50
- package/dist/bigconsole/components/DrilldownModal.js.map +1 -1
- package/dist/bigconsole/components/builder/BuilderCanvas.js +2 -2
- package/dist/bigconsole/components/builder/BuilderCanvas.js.map +1 -1
- package/dist/bigconsole/components/builder/BuilderTopbar.js +3 -3
- package/dist/bigconsole/components/builder/BuilderTopbar.js.map +1 -1
- package/dist/bigconsole/components/builder/inspector/AdvancedSection.js +24 -25
- package/dist/bigconsole/components/builder/inspector/AdvancedSection.js.map +1 -1
- package/dist/bigconsole/components/builder/inspector/AppearanceSection.js +40 -29
- package/dist/bigconsole/components/builder/inspector/AppearanceSection.js.map +1 -1
- package/dist/bigconsole/components/builder/inspector/DataBindingSection.js +135 -97
- package/dist/bigconsole/components/builder/inspector/DataBindingSection.js.map +1 -1
- package/dist/bigconsole/components/builder/inspector/GeneralSection.js +58 -44
- package/dist/bigconsole/components/builder/inspector/GeneralSection.js.map +1 -1
- package/dist/bigconsole/components/common/Section.js +70 -0
- package/dist/bigconsole/components/common/Section.js.map +1 -0
- package/dist/bigconsole/components/common/index.js +2 -0
- package/dist/bigconsole/components/common/sectionStyles.js +42 -0
- package/dist/bigconsole/components/common/sectionStyles.js.map +1 -0
- package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js +209 -193
- package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/DashboardCanvas.js +213 -231
- package/dist/bigconsole/components/dashboard/DashboardCanvas.js.map +1 -1
- package/dist/bigconsole/components/dashboard/DashboardGrid.js +12 -18
- package/dist/bigconsole/components/dashboard/DashboardGrid.js.map +1 -1
- package/dist/bigconsole/components/dashboard/DashboardToolbar.js +109 -102
- package/dist/bigconsole/components/dashboard/DashboardToolbar.js.map +1 -1
- package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js +81 -70
- package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js.map +1 -1
- package/dist/bigconsole/components/dashboard/ExportDashboardDialog.js +125 -159
- package/dist/bigconsole/components/dashboard/ExportDashboardDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterChip.js +25 -23
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterChip.js.map +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js +3 -3
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js.map +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js +5 -3
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js.map +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js +170 -284
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js.map +1 -1
- package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js +147 -151
- package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/LiveBoardBanner.js +45 -53
- package/dist/bigconsole/components/dashboard/LiveBoardBanner.js.map +1 -1
- package/dist/bigconsole/components/dashboard/PageTabsManager/PageTabsManager.js +157 -148
- package/dist/bigconsole/components/dashboard/PageTabsManager/PageTabsManager.js.map +1 -1
- package/dist/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.js +17 -8
- package/dist/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.js.map +1 -1
- package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js +101 -95
- package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/StoreTemplatePicker.js +20 -18
- package/dist/bigconsole/components/dashboard/StoreTemplatePicker.js.map +1 -1
- package/dist/bigconsole/components/dashboard/TemplateSetupBanner.js +26 -58
- package/dist/bigconsole/components/dashboard/TemplateSetupBanner.js.map +1 -1
- package/dist/bigconsole/components/dashboard/WidgetPalette.js +307 -231
- package/dist/bigconsole/components/dashboard/WidgetPalette.js.map +1 -1
- package/dist/bigconsole/components/datasink/CacheTTLSelector.js +29 -29
- package/dist/bigconsole/components/datasink/CacheTTLSelector.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkCard.js +78 -79
- package/dist/bigconsole/components/datasink/DataSinkCard.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkDataViewer.js +33 -34
- package/dist/bigconsole/components/datasink/DataSinkDataViewer.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js +79 -56
- package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js +75 -65
- package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkStatusBadge.js +1 -1
- package/dist/bigconsole/components/datasink/DataSinkStatusBadge.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkTableViewer.js +20 -19
- package/dist/bigconsole/components/datasink/DataSinkTableViewer.js.map +1 -1
- package/dist/bigconsole/components/datasink/ExportDataSinkDialog.js +127 -171
- package/dist/bigconsole/components/datasink/ExportDataSinkDialog.js.map +1 -1
- package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js +263 -243
- package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js.map +1 -1
- package/dist/bigconsole/components/datasink/LinkedParsersPanel.js +65 -66
- package/dist/bigconsole/components/datasink/LinkedParsersPanel.js.map +1 -1
- package/dist/bigconsole/components/datasink/LinkedWorkflowsPanel.js +121 -127
- package/dist/bigconsole/components/datasink/LinkedWorkflowsPanel.js.map +1 -1
- package/dist/bigconsole/components/datasink/RefreshTypeSelector.js +33 -26
- package/dist/bigconsole/components/datasink/RefreshTypeSelector.js.map +1 -1
- package/dist/bigconsole/components/datasink/SetupStateBadge.js +3 -3
- package/dist/bigconsole/components/datasink/SetupStateBadge.js.map +1 -1
- package/dist/bigconsole/components/datasink/WorkflowStatusPanel.js +95 -95
- package/dist/bigconsole/components/datasink/WorkflowStatusPanel.js.map +1 -1
- package/dist/bigconsole/components/parser/DataSinkSelector.js +154 -123
- package/dist/bigconsole/components/parser/DataSinkSelector.js.map +1 -1
- package/dist/bigconsole/components/parser/ExpressionEditor.js +3 -3
- package/dist/bigconsole/components/parser/ExpressionEditor.js.map +1 -1
- package/dist/bigconsole/components/parser/ImportParserDialog.js +235 -275
- package/dist/bigconsole/components/parser/ImportParserDialog.js.map +1 -1
- package/dist/bigconsole/components/parser/ParserCard.js +133 -114
- package/dist/bigconsole/components/parser/ParserCard.js.map +1 -1
- package/dist/bigconsole/components/parser/ParserSelector.js +191 -174
- package/dist/bigconsole/components/parser/ParserSelector.js.map +1 -1
- package/dist/bigconsole/components/parser/ParserStatusBadge.js +2 -2
- package/dist/bigconsole/components/parser/ParserStatusBadge.js.map +1 -1
- package/dist/bigconsole/components/parser/ParserTypeBadge.js +4 -4
- package/dist/bigconsole/components/parser/ParserTypeBadge.js.map +1 -1
- package/dist/bigconsole/components/pipeline/PipelineCard.js +134 -89
- package/dist/bigconsole/components/pipeline/PipelineCard.js.map +1 -1
- package/dist/bigconsole/components/pipeline/PipelineDeleteDialog.js +77 -64
- package/dist/bigconsole/components/pipeline/PipelineDeleteDialog.js.map +1 -1
- package/dist/bigconsole/components/pipeline/PipelineStatusBadge.js +7 -10
- package/dist/bigconsole/components/pipeline/PipelineStatusBadge.js.map +1 -1
- package/dist/bigconsole/components/preview/AiPreviewContent.js +31 -32
- package/dist/bigconsole/components/preview/AiPreviewContent.js.map +1 -1
- package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js +152 -106
- package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js.map +1 -1
- package/dist/bigconsole/components/preview/AiPreviewPanel.js +193 -152
- package/dist/bigconsole/components/preview/AiPreviewPanel.js.map +1 -1
- package/dist/bigconsole/components/preview/previewShared.js +41 -23
- package/dist/bigconsole/components/preview/previewShared.js.map +1 -1
- package/dist/bigconsole/components/widgets/ActionConfigDialog.js +342 -308
- package/dist/bigconsole/components/widgets/ActionConfigDialog.js.map +1 -1
- package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js +262 -238
- package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/PropertiesPanel.js +783 -867
- package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetErrorBoundary.js +7 -5
- package/dist/bigconsole/components/widgets/WidgetErrorBoundary.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetHeader.js +7 -8
- package/dist/bigconsole/components/widgets/WidgetHeader.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetRegistry.js +4 -4
- package/dist/bigconsole/components/widgets/WidgetRegistry.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetWrapper.js +8 -7
- package/dist/bigconsole/components/widgets/WidgetWrapper.js.map +1 -1
- package/dist/bigconsole/components/widgets/adaptive-card/AdaptiveCardWidget.js +1 -1
- package/dist/bigconsole/components/widgets/adaptive-card/AdaptiveCardWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js +2 -2
- package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/chart/ChartConfig.js +11 -5
- package/dist/bigconsole/components/widgets/chart/ChartConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/comments/WidgetComments.js +19 -15
- package/dist/bigconsole/components/widgets/comments/WidgetComments.js.map +1 -1
- package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js +154 -102
- package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js.map +1 -1
- package/dist/bigconsole/components/widgets/gauge/CircularGauge.js +36 -32
- package/dist/bigconsole/components/widgets/gauge/CircularGauge.js.map +1 -1
- package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js +85 -60
- package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/gauge/GaugeWidget.js +64 -35
- package/dist/bigconsole/components/widgets/gauge/GaugeWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/gauge/LinearGauge.js +46 -45
- package/dist/bigconsole/components/widgets/gauge/LinearGauge.js.map +1 -1
- package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js +35 -24
- package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/iframe-widget/IframeWidget.js +2 -2
- package/dist/bigconsole/components/widgets/iframe-widget/IframeWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +4 -4
- package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js +153 -90
- package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/list/ListConfig.js +8 -2
- package/dist/bigconsole/components/widgets/list/ListConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/list/ListItem.js +1 -1
- package/dist/bigconsole/components/widgets/list/ListItem.js.map +1 -1
- package/dist/bigconsole/components/widgets/map-widget/MapWidget.js +1 -1
- package/dist/bigconsole/components/widgets/map-widget/MapWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js +14 -4
- package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js +112 -89
- package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js +21 -13
- package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/index.js +4 -4
- package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js +3 -3
- package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/progress/ProgressConfig.js +34 -25
- package/dist/bigconsole/components/widgets/progress/ProgressConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/progress/ProgressWidget.js +129 -114
- package/dist/bigconsole/components/widgets/progress/ProgressWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/retention/RetentionWidget.js +3 -3
- package/dist/bigconsole/components/widgets/retention/RetentionWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/states/EmptyState.js +6 -4
- package/dist/bigconsole/components/widgets/states/EmptyState.js.map +1 -1
- package/dist/bigconsole/components/widgets/states/ErrorState.js +7 -5
- package/dist/bigconsole/components/widgets/states/ErrorState.js.map +1 -1
- package/dist/bigconsole/components/widgets/states/LoadingState.js +5 -4
- package/dist/bigconsole/components/widgets/states/LoadingState.js.map +1 -1
- package/dist/bigconsole/components/widgets/table/TableConfig.js +10 -4
- package/dist/bigconsole/components/widgets/table/TableConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/table/TableHeader.js +1 -1
- package/dist/bigconsole/components/widgets/table/TableHeader.js.map +1 -1
- package/dist/bigconsole/components/widgets/table/TableWidget.js +1 -1
- package/dist/bigconsole/components/widgets/table/TableWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/text-widget/TextWidget.js +1 -1
- package/dist/bigconsole/components/widgets/text-widget/TextWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js +3 -3
- package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/utils/conditionalFormat.js +2 -2
- package/dist/bigconsole/components/widgets/utils/conditionalFormat.js.map +1 -1
- package/dist/bigconsole/components/widgets/utils/targetProgress.js +13 -0
- package/dist/bigconsole/components/widgets/utils/targetProgress.js.map +1 -0
- package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js +112 -85
- package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js +28 -20
- package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js.map +1 -1
- package/dist/bigconsole/components/workflow/WorkflowCard.js +92 -77
- package/dist/bigconsole/components/workflow/WorkflowCard.js.map +1 -1
- package/dist/bigconsole/components/workflow/WorkflowDeleteDialog.js +70 -51
- package/dist/bigconsole/components/workflow/WorkflowDeleteDialog.js.map +1 -1
- package/dist/bigconsole/components/workflow/WorkflowStatusBadge.js +16 -17
- package/dist/bigconsole/components/workflow/WorkflowStatusBadge.js.map +1 -1
- package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js +6 -4
- package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js.map +1 -1
- package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js +360 -338
- package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js.map +1 -1
- package/dist/bigconsole/hooks/useModalFocusTrap.js +53 -0
- package/dist/bigconsole/hooks/useModalFocusTrap.js.map +1 -0
- package/dist/bigconsole/pages/DashboardBuilderPage.js +209 -203
- package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/DashboardViewPage.js +126 -120
- package/dist/bigconsole/pages/DashboardViewPage.js.map +1 -1
- package/dist/bigconsole/pages/DashboardsPage.js +838 -800
- package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
- package/dist/bigconsole/pages/DataParsersPage.js +263 -315
- package/dist/bigconsole/pages/DataParsersPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkBuilderPage.js +301 -341
- package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkViewPage.js +346 -339
- package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinksPage.js +356 -458
- package/dist/bigconsole/pages/DataSinksPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSourcesPage.js +7 -2
- package/dist/bigconsole/pages/DataSourcesPage.js.map +1 -1
- package/dist/bigconsole/pages/HomePage.js +186 -193
- package/dist/bigconsole/pages/HomePage.js.map +1 -1
- package/dist/bigconsole/pages/InsightsPage.js +887 -740
- package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
- package/dist/bigconsole/pages/ParserBuilderPage.js +679 -637
- package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/ParserViewPage.js +368 -342
- package/dist/bigconsole/pages/ParserViewPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelineBuilderPage.js +537 -444
- package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelineViewPage.js +412 -377
- package/dist/bigconsole/pages/PipelineViewPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelinesPage.js +248 -298
- package/dist/bigconsole/pages/PipelinesPage.js.map +1 -1
- package/dist/bigconsole/pages/WidgetDemoPage.js +251 -153
- package/dist/bigconsole/pages/WidgetDemoPage.js.map +1 -1
- package/dist/bigconsole/pages/WorkflowViewPage.js +381 -371
- package/dist/bigconsole/pages/WorkflowViewPage.js.map +1 -1
- package/dist/bigconsole/pages/WorkflowsPage.js +171 -286
- package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
- 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, '&').replace(/</g, '<').replace(/>/g, '>');\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
|
|
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, '&').replace(/</g, '<').replace(/>/g, '>');\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-
|
|
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-
|
|
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-
|
|
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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"}
|
|
@@ -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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
display: "flex",
|
|
9
|
+
flexDirection: "column",
|
|
10
|
+
gap: "var(--space-formGap)",
|
|
11
|
+
minWidth: 0
|
|
11
12
|
},
|
|
12
13
|
header: {
|
|
13
14
|
display: "flex",
|
|
14
|
-
|
|
15
|
+
flexWrap: "wrap",
|
|
16
|
+
justifyContent: "flex-end",
|
|
15
17
|
alignItems: "center",
|
|
16
|
-
|
|
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
|
-
|
|
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
|
|
24
|
+
color: "var(--color-action-primary-text)",
|
|
28
25
|
border: "none",
|
|
29
|
-
borderRadius: "
|
|
30
|
-
fontSize: "
|
|
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: "
|
|
41
|
-
backgroundColor: "var(--color-bg-
|
|
42
|
-
borderRadius: "
|
|
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
|
-
|
|
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: "
|
|
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: "
|
|
77
|
-
color: "var(--color-text-
|
|
80
|
+
fontSize: "var(--font-size-body-sm)",
|
|
81
|
+
color: "var(--color-text-secondary)",
|
|
78
82
|
marginBottom: "4px"
|
|
79
83
|
},
|
|
80
84
|
webhookUrl: {
|
|
81
|
-
fontSize: "
|
|
82
|
-
color: "var(--color-text-
|
|
83
|
-
fontFamily: "
|
|
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
|
-
|
|
93
|
-
|
|
97
|
+
minHeight: "var(--size-controlHeight-md)",
|
|
98
|
+
padding: "0 12px",
|
|
99
|
+
fontSize: "var(--font-size-body-sm)",
|
|
94
100
|
fontWeight: 500,
|
|
95
|
-
borderRadius: "
|
|
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: "
|
|
118
|
-
color: "var(--color-text-
|
|
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: "
|
|
122
|
-
backgroundColor: "var(--color-bg-
|
|
123
|
-
|
|
124
|
-
|
|
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: "
|
|
138
|
-
|
|
139
|
-
|
|
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: "
|
|
146
|
-
|
|
147
|
-
|
|
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: "
|
|
155
|
-
|
|
156
|
-
|
|
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: "
|
|
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: "
|
|
190
|
+
marginTop: "var(--space-formGap)"
|
|
167
191
|
},
|
|
168
192
|
cancelButton: {
|
|
169
|
-
|
|
170
|
-
|
|
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: "
|
|
173
|
-
borderRadius: "
|
|
174
|
-
fontSize: "
|
|
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
|
-
|
|
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
|
|
206
|
+
color: "var(--color-action-primary-text)",
|
|
181
207
|
border: "none",
|
|
182
|
-
borderRadius: "
|
|
183
|
-
fontSize: "
|
|
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
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
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", "
|
|
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", "
|
|
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__ */
|
|
479
|
+
!m && /* @__PURE__ */ o("div", {
|
|
459
480
|
style: c.header,
|
|
460
|
-
children:
|
|
461
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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: "
|
|
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.")
|