@burdenoff/microfe-bigconsole 2026.728.1 → 2026.729.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/dist/bigconsole/components/DrilldownDashboardRenderer.js +1 -1
  2. package/dist/bigconsole/components/DrilldownDashboardRenderer.js.map +1 -1
  3. package/dist/bigconsole/components/builder/inspector/DataBindingSection.js +4 -4
  4. package/dist/bigconsole/components/builder/inspector/DataBindingSection.js.map +1 -1
  5. package/dist/bigconsole/components/datasink/CacheTTLSelector.js +5 -5
  6. package/dist/bigconsole/components/datasink/CacheTTLSelector.js.map +1 -1
  7. package/dist/bigconsole/components/datasink/DataSinkCard.js +3 -3
  8. package/dist/bigconsole/components/datasink/DataSinkCard.js.map +1 -1
  9. package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js +4 -4
  10. package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js.map +1 -1
  11. package/dist/bigconsole/components/datasink/DataSinkStatusBadge.js +6 -6
  12. package/dist/bigconsole/components/datasink/DataSinkStatusBadge.js.map +1 -1
  13. package/dist/bigconsole/components/datasink/LinkedWorkflowsPanel.js +9 -9
  14. package/dist/bigconsole/components/datasink/LinkedWorkflowsPanel.js.map +1 -1
  15. package/dist/bigconsole/components/datasink/RefreshTypeSelector.js +2 -2
  16. package/dist/bigconsole/components/datasink/RefreshTypeSelector.js.map +1 -1
  17. package/dist/bigconsole/components/datasink/SetupStateBadge.js +8 -8
  18. package/dist/bigconsole/components/datasink/SetupStateBadge.js.map +1 -1
  19. package/dist/bigconsole/components/datasink/WorkflowStatusPanel.js +13 -13
  20. package/dist/bigconsole/components/datasink/WorkflowStatusPanel.js.map +1 -1
  21. package/dist/bigconsole/components/parser/DataSinkSelector.js +2 -2
  22. package/dist/bigconsole/components/parser/DataSinkSelector.js.map +1 -1
  23. package/dist/bigconsole/components/parser/ExpressionEditor.js +1 -1
  24. package/dist/bigconsole/components/parser/ExpressionEditor.js.map +1 -1
  25. package/dist/bigconsole/components/parser/ParserCard.js +1 -1
  26. package/dist/bigconsole/components/parser/ParserCard.js.map +1 -1
  27. package/dist/bigconsole/components/parser/ParserSelector.js +2 -2
  28. package/dist/bigconsole/components/parser/ParserSelector.js.map +1 -1
  29. package/dist/bigconsole/components/parser/ParserStatusBadge.js +2 -2
  30. package/dist/bigconsole/components/parser/ParserStatusBadge.js.map +1 -1
  31. package/dist/bigconsole/components/pipeline/PipelineCard.js +2 -2
  32. package/dist/bigconsole/components/pipeline/PipelineCard.js.map +1 -1
  33. package/dist/bigconsole/components/pipeline/PipelineDeleteDialog.js +5 -5
  34. package/dist/bigconsole/components/pipeline/PipelineDeleteDialog.js.map +1 -1
  35. package/dist/bigconsole/components/pipeline/PipelineStatusBadge.js +3 -3
  36. package/dist/bigconsole/components/pipeline/PipelineStatusBadge.js.map +1 -1
  37. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js +1 -1
  38. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js.map +1 -1
  39. package/dist/bigconsole/components/widgets/PropertiesPanel.js +3 -3
  40. package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
  41. package/dist/bigconsole/components/widgets/WidgetErrorBoundary.js +2 -2
  42. package/dist/bigconsole/components/widgets/WidgetErrorBoundary.js.map +1 -1
  43. package/dist/bigconsole/components/widgets/WidgetMenu.js +1 -1
  44. package/dist/bigconsole/components/widgets/WidgetMenu.js.map +1 -1
  45. package/dist/bigconsole/components/widgets/adaptive-card/AdaptiveCardWidget.js +3 -3
  46. package/dist/bigconsole/components/widgets/adaptive-card/AdaptiveCardWidget.js.map +1 -1
  47. package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js +1 -1
  48. package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js.map +1 -1
  49. package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js +3 -3
  50. package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js.map +1 -1
  51. package/dist/bigconsole/components/widgets/heatmap/HeatmapWidget.js +52 -32
  52. package/dist/bigconsole/components/widgets/heatmap/HeatmapWidget.js.map +1 -1
  53. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +3 -3
  54. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js.map +1 -1
  55. package/dist/bigconsole/components/widgets/kpi/KPIWidget.js +1 -1
  56. package/dist/bigconsole/components/widgets/kpi/KPIWidget.js.map +1 -1
  57. package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js +2 -2
  58. package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js.map +1 -1
  59. package/dist/bigconsole/components/widgets/list/ListItem.js +3 -3
  60. package/dist/bigconsole/components/widgets/list/ListItem.js.map +1 -1
  61. package/dist/bigconsole/components/widgets/metric-card/ComparisonBadge.js +1 -1
  62. package/dist/bigconsole/components/widgets/metric-card/ComparisonBadge.js.map +1 -1
  63. package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js +1 -1
  64. package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js.map +1 -1
  65. package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js +6 -6
  66. package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js.map +1 -1
  67. package/dist/bigconsole/components/widgets/metric-card/TrendIndicator.js +1 -1
  68. package/dist/bigconsole/components/widgets/metric-card/TrendIndicator.js.map +1 -1
  69. package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js +2 -2
  70. package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js.map +1 -1
  71. package/dist/bigconsole/components/widgets/progress/ProgressBar.js +4 -4
  72. package/dist/bigconsole/components/widgets/progress/ProgressBar.js.map +1 -1
  73. package/dist/bigconsole/components/widgets/progress/ProgressConfig.js +1 -1
  74. package/dist/bigconsole/components/widgets/progress/ProgressConfig.js.map +1 -1
  75. package/dist/bigconsole/components/widgets/progress/ProgressWidget.js +1 -1
  76. package/dist/bigconsole/components/widgets/progress/ProgressWidget.js.map +1 -1
  77. package/dist/bigconsole/components/widgets/retention/RetentionWidget.js +2 -2
  78. package/dist/bigconsole/components/widgets/retention/RetentionWidget.js.map +1 -1
  79. package/dist/bigconsole/components/widgets/states/ErrorState.js +2 -2
  80. package/dist/bigconsole/components/widgets/states/ErrorState.js.map +1 -1
  81. package/dist/bigconsole/components/widgets/table/TableConfig.js +2 -2
  82. package/dist/bigconsole/components/widgets/table/TableConfig.js.map +1 -1
  83. package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js +1 -1
  84. package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js.map +1 -1
  85. package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js +6 -6
  86. package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js.map +1 -1
  87. package/dist/bigconsole/components/workflow/WorkflowCard.js +1 -1
  88. package/dist/bigconsole/components/workflow/WorkflowCard.js.map +1 -1
  89. package/dist/bigconsole/components/workflow/WorkflowDeleteDialog.js +5 -5
  90. package/dist/bigconsole/components/workflow/WorkflowDeleteDialog.js.map +1 -1
  91. package/dist/bigconsole/components/workflow/WorkflowStatusBadge.js +6 -6
  92. package/dist/bigconsole/components/workflow/WorkflowStatusBadge.js.map +1 -1
  93. package/dist/bigconsole/pages/DataSinkBuilderPage.js +17 -17
  94. package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
  95. package/dist/bigconsole/pages/DataSinkViewPage.js +2 -2
  96. package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
  97. package/dist/bigconsole/pages/ParserBuilderPage.js +24 -24
  98. package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
  99. package/dist/bigconsole/pages/ParserViewPage.js +8 -8
  100. package/dist/bigconsole/pages/ParserViewPage.js.map +1 -1
  101. package/dist/bigconsole/pages/PipelineBuilderPage.js +9 -9
  102. package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
  103. package/dist/bigconsole/pages/PipelineViewPage.js +12 -12
  104. package/dist/bigconsole/pages/PipelineViewPage.js.map +1 -1
  105. package/dist/bigconsole/pages/WorkflowViewPage.js +6 -6
  106. package/dist/bigconsole/pages/WorkflowViewPage.js.map +1 -1
  107. package/dist/bigconsole/renderers/adapters/AdaptiveCardRenderer.js +1 -1
  108. package/dist/bigconsole/renderers/adapters/AdaptiveCardRenderer.js.map +1 -1
  109. package/dist/bigconsole/renderers/adapters/BlockKitRenderer.js +2 -2
  110. package/dist/bigconsole/renderers/adapters/BlockKitRenderer.js.map +1 -1
  111. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"TableConfig.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/table/TableConfig.tsx"],"sourcesContent":["/**\n * TableConfig Component\n *\n * Configuration panel for Table widgets.\n */\n\nimport { type FC, memo, useCallback, useMemo, useEffect, useState } from 'react';\nimport type { TableConfig as ConfigType, TableColumnConfig } from '../../../types';\nimport type { ConditionalRule, ConditionalOperator, SemanticIntent } from '../utils/conditionalFormat';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TableConfigProps {\n /** Current configuration */\n config: ConfigType;\n /** Callback when config changes */\n onChange: (config: ConfigType) => void;\n}\n\n// Operators offered in the conditional-formatting editor. Kept to the common,\n// self-explanatory set; the engine supports more (see conditionalFormat.ts).\nconst CF_OPERATORS: { value: ConditionalOperator; label: string }[] = [\n { value: 'gt', label: '> greater than' },\n { value: 'gte', label: '≥ at least' },\n { value: 'lt', label: '< less than' },\n { value: 'lte', label: '≤ at most' },\n { value: 'eq', label: '= equals' },\n { value: 'neq', label: '≠ not equal' },\n { value: 'between', label: 'between' },\n { value: 'outside', label: 'outside' },\n { value: 'contains', label: 'contains' },\n];\n\n// Semantic color intents — theme-safe (never raw hex). Resolved to status tokens.\nconst CF_INTENTS: { value: SemanticIntent; label: string }[] = [\n { value: 'danger', label: 'Red — danger' },\n { value: 'warning', label: 'Amber — warning' },\n { value: 'success', label: 'Green — good' },\n { value: 'info', label: 'Blue — info' },\n { value: 'neutral', label: 'Neutral' },\n];\n\nconst CF_FIELD_CLASS =\n 'px-2 py-1 text-xs text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg';\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const TableConfig: FC<TableConfigProps> = memo(function TableConfig({ config, onChange }) {\n // Normalize columns - convert string[] to TableColumnConfig[]\n const initialColumns = useMemo(() => {\n return ((config.columns || []) as (string | TableColumnConfig)[]).map((col) => {\n if (typeof col === 'string') {\n return {\n field: col,\n header: col.charAt(0).toUpperCase() + col.slice(1).replace(/_/g, ' '),\n };\n }\n return col as TableColumnConfig;\n });\n }, []); // Only run once on mount\n\n // Local state for columns to make them editable\n const [columns, setColumns] = useState<TableColumnConfig[]>(initialColumns);\n\n // Sync with parent when columns change\n useEffect(() => {\n // Only update if columns actually changed (deep compare)\n const currentStr = JSON.stringify(config.columns);\n const newStr = JSON.stringify(columns);\n if (currentStr !== newStr && columns.length > 0) {\n onChange({ ...config, columns });\n }\n }, [columns]);\n\n // Reset columns when config changes from outside\n useEffect(() => {\n const normalized = ((config.columns || []) as (string | TableColumnConfig)[]).map((col) => {\n if (typeof col === 'string') {\n return {\n field: col,\n header: col.charAt(0).toUpperCase() + col.slice(1).replace(/_/g, ' '),\n };\n }\n return col as TableColumnConfig;\n });\n setColumns(normalized);\n }, [config.columns]);\n\n const handleChange = useCallback(\n <K extends keyof ConfigType>(key: K, value: ConfigType[K]) => {\n onChange({ ...config, [key]: value });\n },\n [config, onChange]\n );\n\n const handleColumnChange = useCallback((index: number, field: keyof TableColumnConfig, value: string) => {\n setColumns((prev) => {\n const newColumns = [...prev];\n newColumns[index] = { ...newColumns[index], [field]: value };\n return newColumns;\n });\n }, []);\n\n // Conditional-formatting rule edits for a column. The rules array is stored on\n // `column.conditionalRules` and consumed at render time by TableCell.\n const handleColumnRules = useCallback((index: number, rules: ConditionalRule[]) => {\n setColumns((prev) => {\n const newColumns = [...prev];\n newColumns[index] = { ...newColumns[index], conditionalRules: rules };\n return newColumns;\n });\n }, []);\n\n const addRule = useCallback(\n (index: number) => {\n const existing = columns[index]?.conditionalRules ?? [];\n const next: ConditionalRule = {\n operator: 'gt',\n value: 0,\n style: { bgColor: 'danger', textColor: 'danger', bold: true },\n };\n handleColumnRules(index, [...existing, next]);\n },\n [columns, handleColumnRules]\n );\n\n const updateRule = useCallback(\n (colIndex: number, ruleIndex: number, patch: Partial<ConditionalRule>) => {\n const existing = columns[colIndex]?.conditionalRules ?? [];\n const next = existing.map((r, i) => (i === ruleIndex ? { ...r, ...patch } : r));\n handleColumnRules(colIndex, next);\n },\n [columns, handleColumnRules]\n );\n\n const updateRuleStyle = useCallback(\n (colIndex: number, ruleIndex: number, intent: SemanticIntent) => {\n const existing = columns[colIndex]?.conditionalRules ?? [];\n const next = existing.map((r, i) =>\n i === ruleIndex ? { ...r, style: { ...r.style, bgColor: intent, textColor: intent } } : r\n );\n handleColumnRules(colIndex, next);\n },\n [columns, handleColumnRules]\n );\n\n const removeRule = useCallback(\n (colIndex: number, ruleIndex: number) => {\n const existing = columns[colIndex]?.conditionalRules ?? [];\n handleColumnRules(\n colIndex,\n existing.filter((_, i) => i !== ruleIndex)\n );\n },\n [columns, handleColumnRules]\n );\n\n const addColumn = useCallback(() => {\n setColumns((prev) => [...prev, { field: '', header: '' }]);\n }, []);\n\n const removeColumn = useCallback((index: number) => {\n setColumns((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n return (\n <div className=\"space-y-4\">\n {/* Page Size */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Page Size</label>\n <select\n value={config.pageSize || 10}\n onChange={(e) => handleChange('pageSize', Number(e.target.value))}\n className=\"\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value={10}>10 rows</option>\n <option value={25}>25 rows</option>\n <option value={50}>50 rows</option>\n <option value={100}>100 rows</option>\n </select>\n </div>\n\n {/* Columns Configuration */}\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <label className=\"text-sm font-medium text-text-primary\">Columns</label>\n <button\n type=\"button\"\n onClick={addColumn}\n className=\"\n text-sm text-action-primary-bg\n hover:text-action-primary-bgHover\n \"\n >\n + Add Column\n </button>\n </div>\n\n <div className=\"space-y-3\">\n {columns.map((col, index) => (\n <div\n key={index}\n className=\"\n p-3\n bg-bg-sunken\n rounded-md\n space-y-2\n \"\n >\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-text-secondary\">Column {index + 1}</span>\n <button\n type=\"button\"\n onClick={() => removeColumn(index)}\n className=\"text-state-error hover:text-state-error/80\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <div className=\"grid grid-cols-2 gap-2\">\n <input\n type=\"text\"\n value={col.field || ''}\n onChange={(e) => handleColumnChange(index, 'field', e.target.value)}\n placeholder=\"Field name\"\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n <input\n type=\"text\"\n value={col.header || ''}\n onChange={(e) => handleColumnChange(index, 'header', e.target.value)}\n placeholder=\"Header label\"\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-2\">\n <select\n value={col.format || 'text'}\n onChange={(e) => handleColumnChange(index, 'format', e.target.value)}\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value=\"text\">Text</option>\n <option value=\"number\">Number</option>\n <option value=\"currency\">Currency</option>\n <option value=\"percentage\">Percentage</option>\n <option value=\"date\">Date</option>\n <option value=\"badge\">Badge</option>\n </select>\n <select\n value={col.align || 'left'}\n onChange={(e) => handleColumnChange(index, 'align', e.target.value)}\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value=\"left\">Left</option>\n <option value=\"center\">Center</option>\n <option value=\"right\">Right</option>\n </select>\n </div>\n\n {/* Conditional formatting rules */}\n <div className=\"pt-2 border-t border-border-default/60\">\n <div className=\"flex items-center justify-between mb-1\">\n <span className=\"text-xs font-medium text-text-secondary\">Conditional formatting</span>\n <button\n type=\"button\"\n onClick={() => addRule(index)}\n className=\"text-xs text-action-primary-bg hover:text-action-primary-bgHover\"\n >\n + Add rule\n </button>\n </div>\n\n {(col.conditionalRules?.length ?? 0) === 0 && (\n <p className=\"text-xs text-text-secondary\">No rules — cell shows its plain value.</p>\n )}\n\n <div className=\"space-y-2\">\n {(col.conditionalRules ?? []).map((rule, ruleIndex) => {\n const needsSecond = rule.operator === 'between' || rule.operator === 'outside';\n const currentIntent: SemanticIntent = rule.style?.bgColor ?? rule.style?.textColor ?? 'danger';\n return (\n <div\n key={ruleIndex}\n className=\"p-2 bg-bg-surface rounded-md border border-border-default space-y-2\"\n >\n <div className=\"flex items-center gap-2\">\n <select\n value={rule.operator}\n onChange={(e) =>\n updateRule(index, ruleIndex, { operator: e.target.value as ConditionalOperator })\n }\n className={`${CF_FIELD_CLASS} flex-1`}\n >\n {CF_OPERATORS.map((op) => (\n <option key={op.value} value={op.value}>\n {op.label}\n </option>\n ))}\n </select>\n <input\n type=\"text\"\n value={rule.value ?? ''}\n onChange={(e) => updateRule(index, ruleIndex, { value: e.target.value })}\n placeholder=\"value\"\n className={`${CF_FIELD_CLASS} w-20`}\n />\n {needsSecond && (\n <input\n type=\"text\"\n value={rule.value2 ?? ''}\n onChange={(e) => updateRule(index, ruleIndex, { value2: e.target.value })}\n placeholder=\"and\"\n className={`${CF_FIELD_CLASS} w-20`}\n />\n )}\n <button\n type=\"button\"\n onClick={() => removeRule(index, ruleIndex)}\n className=\"text-state-error hover:text-state-error/80\"\n aria-label=\"Remove rule\"\n >\n <svg className=\"w-3.5 h-3.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n <div className=\"flex items-center gap-2\">\n <select\n value={currentIntent}\n onChange={(e) => updateRuleStyle(index, ruleIndex, e.target.value as SemanticIntent)}\n className={`${CF_FIELD_CLASS} flex-1`}\n >\n {CF_INTENTS.map((it) => (\n <option key={it.value} value={it.value}>\n {it.label}\n </option>\n ))}\n </select>\n <label className=\"flex items-center gap-1 text-xs text-text-primary\">\n <input\n type=\"checkbox\"\n checked={rule.style?.bold === true}\n onChange={(e) =>\n updateRule(index, ruleIndex, { style: { ...rule.style, bold: e.target.checked } })\n }\n className=\"w-3.5 h-3.5 text-action-primary-bg bg-bg-surface border-border-default rounded focus:ring-action-primary-bg\"\n />\n Bold\n </label>\n </div>\n </div>\n );\n })}\n </div>\n </div>\n </div>\n ))}\n\n {columns.length === 0 && (\n <p className=\"text-sm text-text-secondary text-center py-4\">\n No columns configured. Columns will be auto-generated from data.\n </p>\n )}\n </div>\n </div>\n\n {/* Toggle Options */}\n <div className=\"space-y-3\">\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showSearch !== false}\n onChange={(e) => handleChange('showSearch', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Show search box</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showPagination !== false}\n onChange={(e) => handleChange('showPagination', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Show pagination</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showExport !== false}\n onChange={(e) => handleChange('showExport', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Show export button</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.stickyHeader === true}\n onChange={(e) => handleChange('stickyHeader', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Sticky header</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.stripedRows === true}\n onChange={(e) => handleChange('stripedRows', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Striped rows</span>\n </label>\n </div>\n </div>\n );\n});\n\nexport default TableConfig;\n"],"mappings":"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"}
1
+ {"version":3,"file":"TableConfig.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/table/TableConfig.tsx"],"sourcesContent":["/**\n * TableConfig Component\n *\n * Configuration panel for Table widgets.\n */\n\nimport { type FC, memo, useCallback, useMemo, useEffect, useState } from 'react';\nimport type { TableConfig as ConfigType, TableColumnConfig } from '../../../types';\nimport type { ConditionalRule, ConditionalOperator, SemanticIntent } from '../utils/conditionalFormat';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TableConfigProps {\n /** Current configuration */\n config: ConfigType;\n /** Callback when config changes */\n onChange: (config: ConfigType) => void;\n}\n\n// Operators offered in the conditional-formatting editor. Kept to the common,\n// self-explanatory set; the engine supports more (see conditionalFormat.ts).\nconst CF_OPERATORS: { value: ConditionalOperator; label: string }[] = [\n { value: 'gt', label: '> greater than' },\n { value: 'gte', label: '≥ at least' },\n { value: 'lt', label: '< less than' },\n { value: 'lte', label: '≤ at most' },\n { value: 'eq', label: '= equals' },\n { value: 'neq', label: '≠ not equal' },\n { value: 'between', label: 'between' },\n { value: 'outside', label: 'outside' },\n { value: 'contains', label: 'contains' },\n];\n\n// Semantic color intents — theme-safe (never raw hex). Resolved to status tokens.\nconst CF_INTENTS: { value: SemanticIntent; label: string }[] = [\n { value: 'danger', label: 'Red — danger' },\n { value: 'warning', label: 'Amber — warning' },\n { value: 'success', label: 'Green — good' },\n { value: 'info', label: 'Blue — info' },\n { value: 'neutral', label: 'Neutral' },\n];\n\nconst CF_FIELD_CLASS =\n 'px-2 py-1 text-xs text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg';\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const TableConfig: FC<TableConfigProps> = memo(function TableConfig({ config, onChange }) {\n // Normalize columns - convert string[] to TableColumnConfig[]\n const initialColumns = useMemo(() => {\n return ((config.columns || []) as (string | TableColumnConfig)[]).map((col) => {\n if (typeof col === 'string') {\n return {\n field: col,\n header: col.charAt(0).toUpperCase() + col.slice(1).replace(/_/g, ' '),\n };\n }\n return col as TableColumnConfig;\n });\n }, []); // Only run once on mount\n\n // Local state for columns to make them editable\n const [columns, setColumns] = useState<TableColumnConfig[]>(initialColumns);\n\n // Sync with parent when columns change\n useEffect(() => {\n // Only update if columns actually changed (deep compare)\n const currentStr = JSON.stringify(config.columns);\n const newStr = JSON.stringify(columns);\n if (currentStr !== newStr && columns.length > 0) {\n onChange({ ...config, columns });\n }\n }, [columns]);\n\n // Reset columns when config changes from outside\n useEffect(() => {\n const normalized = ((config.columns || []) as (string | TableColumnConfig)[]).map((col) => {\n if (typeof col === 'string') {\n return {\n field: col,\n header: col.charAt(0).toUpperCase() + col.slice(1).replace(/_/g, ' '),\n };\n }\n return col as TableColumnConfig;\n });\n setColumns(normalized);\n }, [config.columns]);\n\n const handleChange = useCallback(\n <K extends keyof ConfigType>(key: K, value: ConfigType[K]) => {\n onChange({ ...config, [key]: value });\n },\n [config, onChange]\n );\n\n const handleColumnChange = useCallback((index: number, field: keyof TableColumnConfig, value: string) => {\n setColumns((prev) => {\n const newColumns = [...prev];\n newColumns[index] = { ...newColumns[index], [field]: value };\n return newColumns;\n });\n }, []);\n\n // Conditional-formatting rule edits for a column. The rules array is stored on\n // `column.conditionalRules` and consumed at render time by TableCell.\n const handleColumnRules = useCallback((index: number, rules: ConditionalRule[]) => {\n setColumns((prev) => {\n const newColumns = [...prev];\n newColumns[index] = { ...newColumns[index], conditionalRules: rules };\n return newColumns;\n });\n }, []);\n\n const addRule = useCallback(\n (index: number) => {\n const existing = columns[index]?.conditionalRules ?? [];\n const next: ConditionalRule = {\n operator: 'gt',\n value: 0,\n style: { bgColor: 'danger', textColor: 'danger', bold: true },\n };\n handleColumnRules(index, [...existing, next]);\n },\n [columns, handleColumnRules]\n );\n\n const updateRule = useCallback(\n (colIndex: number, ruleIndex: number, patch: Partial<ConditionalRule>) => {\n const existing = columns[colIndex]?.conditionalRules ?? [];\n const next = existing.map((r, i) => (i === ruleIndex ? { ...r, ...patch } : r));\n handleColumnRules(colIndex, next);\n },\n [columns, handleColumnRules]\n );\n\n const updateRuleStyle = useCallback(\n (colIndex: number, ruleIndex: number, intent: SemanticIntent) => {\n const existing = columns[colIndex]?.conditionalRules ?? [];\n const next = existing.map((r, i) =>\n i === ruleIndex ? { ...r, style: { ...r.style, bgColor: intent, textColor: intent } } : r\n );\n handleColumnRules(colIndex, next);\n },\n [columns, handleColumnRules]\n );\n\n const removeRule = useCallback(\n (colIndex: number, ruleIndex: number) => {\n const existing = columns[colIndex]?.conditionalRules ?? [];\n handleColumnRules(\n colIndex,\n existing.filter((_, i) => i !== ruleIndex)\n );\n },\n [columns, handleColumnRules]\n );\n\n const addColumn = useCallback(() => {\n setColumns((prev) => [...prev, { field: '', header: '' }]);\n }, []);\n\n const removeColumn = useCallback((index: number) => {\n setColumns((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n return (\n <div className=\"space-y-4\">\n {/* Page Size */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Page Size</label>\n <select\n value={config.pageSize || 10}\n onChange={(e) => handleChange('pageSize', Number(e.target.value))}\n className=\"\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value={10}>10 rows</option>\n <option value={25}>25 rows</option>\n <option value={50}>50 rows</option>\n <option value={100}>100 rows</option>\n </select>\n </div>\n\n {/* Columns Configuration */}\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <label className=\"text-sm font-medium text-text-primary\">Columns</label>\n <button\n type=\"button\"\n onClick={addColumn}\n className=\"\n text-sm text-action-primary-bg\n hover:text-action-primary-bgHover\n \"\n >\n + Add Column\n </button>\n </div>\n\n <div className=\"space-y-3\">\n {columns.map((col, index) => (\n <div\n key={index}\n className=\"\n p-3\n bg-bg-sunken\n rounded-md\n space-y-2\n \"\n >\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-text-secondary\">Column {index + 1}</span>\n <button\n type=\"button\"\n onClick={() => removeColumn(index)}\n className=\"text-status-error-text hover:text-status-error-text/80\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <div className=\"grid grid-cols-2 gap-2\">\n <input\n type=\"text\"\n value={col.field || ''}\n onChange={(e) => handleColumnChange(index, 'field', e.target.value)}\n placeholder=\"Field name\"\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n <input\n type=\"text\"\n value={col.header || ''}\n onChange={(e) => handleColumnChange(index, 'header', e.target.value)}\n placeholder=\"Header label\"\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-2\">\n <select\n value={col.format || 'text'}\n onChange={(e) => handleColumnChange(index, 'format', e.target.value)}\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value=\"text\">Text</option>\n <option value=\"number\">Number</option>\n <option value=\"currency\">Currency</option>\n <option value=\"percentage\">Percentage</option>\n <option value=\"date\">Date</option>\n <option value=\"badge\">Badge</option>\n </select>\n <select\n value={col.align || 'left'}\n onChange={(e) => handleColumnChange(index, 'align', e.target.value)}\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value=\"left\">Left</option>\n <option value=\"center\">Center</option>\n <option value=\"right\">Right</option>\n </select>\n </div>\n\n {/* Conditional formatting rules */}\n <div className=\"pt-2 border-t border-border-default/60\">\n <div className=\"flex items-center justify-between mb-1\">\n <span className=\"text-xs font-medium text-text-secondary\">Conditional formatting</span>\n <button\n type=\"button\"\n onClick={() => addRule(index)}\n className=\"text-xs text-action-primary-bg hover:text-action-primary-bgHover\"\n >\n + Add rule\n </button>\n </div>\n\n {(col.conditionalRules?.length ?? 0) === 0 && (\n <p className=\"text-xs text-text-secondary\">No rules — cell shows its plain value.</p>\n )}\n\n <div className=\"space-y-2\">\n {(col.conditionalRules ?? []).map((rule, ruleIndex) => {\n const needsSecond = rule.operator === 'between' || rule.operator === 'outside';\n const currentIntent: SemanticIntent = rule.style?.bgColor ?? rule.style?.textColor ?? 'danger';\n return (\n <div\n key={ruleIndex}\n className=\"p-2 bg-bg-surface rounded-md border border-border-default space-y-2\"\n >\n <div className=\"flex items-center gap-2\">\n <select\n value={rule.operator}\n onChange={(e) =>\n updateRule(index, ruleIndex, { operator: e.target.value as ConditionalOperator })\n }\n className={`${CF_FIELD_CLASS} flex-1`}\n >\n {CF_OPERATORS.map((op) => (\n <option key={op.value} value={op.value}>\n {op.label}\n </option>\n ))}\n </select>\n <input\n type=\"text\"\n value={rule.value ?? ''}\n onChange={(e) => updateRule(index, ruleIndex, { value: e.target.value })}\n placeholder=\"value\"\n className={`${CF_FIELD_CLASS} w-20`}\n />\n {needsSecond && (\n <input\n type=\"text\"\n value={rule.value2 ?? ''}\n onChange={(e) => updateRule(index, ruleIndex, { value2: e.target.value })}\n placeholder=\"and\"\n className={`${CF_FIELD_CLASS} w-20`}\n />\n )}\n <button\n type=\"button\"\n onClick={() => removeRule(index, ruleIndex)}\n className=\"text-status-error-text hover:text-status-error-text/80\"\n aria-label=\"Remove rule\"\n >\n <svg className=\"w-3.5 h-3.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n <div className=\"flex items-center gap-2\">\n <select\n value={currentIntent}\n onChange={(e) => updateRuleStyle(index, ruleIndex, e.target.value as SemanticIntent)}\n className={`${CF_FIELD_CLASS} flex-1`}\n >\n {CF_INTENTS.map((it) => (\n <option key={it.value} value={it.value}>\n {it.label}\n </option>\n ))}\n </select>\n <label className=\"flex items-center gap-1 text-xs text-text-primary\">\n <input\n type=\"checkbox\"\n checked={rule.style?.bold === true}\n onChange={(e) =>\n updateRule(index, ruleIndex, { style: { ...rule.style, bold: e.target.checked } })\n }\n className=\"w-3.5 h-3.5 text-action-primary-bg bg-bg-surface border-border-default rounded focus:ring-action-primary-bg\"\n />\n Bold\n </label>\n </div>\n </div>\n );\n })}\n </div>\n </div>\n </div>\n ))}\n\n {columns.length === 0 && (\n <p className=\"text-sm text-text-secondary text-center py-4\">\n No columns configured. Columns will be auto-generated from data.\n </p>\n )}\n </div>\n </div>\n\n {/* Toggle Options */}\n <div className=\"space-y-3\">\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showSearch !== false}\n onChange={(e) => handleChange('showSearch', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Show search box</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showPagination !== false}\n onChange={(e) => handleChange('showPagination', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Show pagination</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showExport !== false}\n onChange={(e) => handleChange('showExport', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Show export button</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.stickyHeader === true}\n onChange={(e) => handleChange('stickyHeader', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Sticky header</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.stripedRows === true}\n onChange={(e) => handleChange('stripedRows', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Striped rows</span>\n </label>\n </div>\n </div>\n );\n});\n\nexport default TableConfig;\n"],"mappings":";;;AAuBA,IAAM,IAAgE;CACpE;EAAE,OAAO;EAAM,OAAO;EAAkB;CACxC;EAAE,OAAO;EAAO,OAAO;EAAc;CACrC;EAAE,OAAO;EAAM,OAAO;EAAe;CACrC;EAAE,OAAO;EAAO,OAAO;EAAa;CACpC;EAAE,OAAO;EAAM,OAAO;EAAY;CAClC;EAAE,OAAO;EAAO,OAAO;EAAe;CACtC;EAAE,OAAO;EAAW,OAAO;EAAW;CACtC;EAAE,OAAO;EAAW,OAAO;EAAW;CACtC;EAAE,OAAO;EAAY,OAAO;EAAY;CACzC,EAGK,IAAyD;CAC7D;EAAE,OAAO;EAAU,OAAO;EAAgB;CAC1C;EAAE,OAAO;EAAW,OAAO;EAAmB;CAC9C;EAAE,OAAO;EAAW,OAAO;EAAgB;CAC3C;EAAE,OAAO;EAAQ,OAAO;EAAe;CACvC;EAAE,OAAO;EAAW,OAAO;EAAW;CACvC,EAEK,IACJ,0JAMW,IAAoC,EAAK,SAAqB,EAAE,WAAQ,eAAY;CAe/F,IAAM,CAAC,GAAS,KAAc,EAbP,SACZ,EAAO,WAAW,EAAE,EAAqC,KAAK,MACjE,OAAO,KAAQ,WACV;EACL,OAAO;EACP,QAAQ,EAAI,OAAO,EAAE,CAAC,aAAa,GAAG,EAAI,MAAM,EAAE,CAAC,QAAQ,MAAM,IAAI;EACtE,GAEI,EACP,EACD,EAAE,CAAC,CAGqE;AAa3E,CAVA,QAAgB;AAId,EAFmB,KAAK,UAAU,EAAO,QAAQ,KAClC,KAAK,UAAU,EAAQ,IACT,EAAQ,SAAS,KAC5C,EAAS;GAAE,GAAG;GAAQ;GAAS,CAAC;IAEjC,CAAC,EAAQ,CAAC,EAGb,QAAgB;AAUd,KATqB,EAAO,WAAW,EAAE,EAAqC,KAAK,MAC7E,OAAO,KAAQ,WACV;GACL,OAAO;GACP,QAAQ,EAAI,OAAO,EAAE,CAAC,aAAa,GAAG,EAAI,MAAM,EAAE,CAAC,QAAQ,MAAM,IAAI;GACtE,GAEI,EACP,CACoB;IACrB,CAAC,EAAO,QAAQ,CAAC;CAEpB,IAAM,IAAe,GACU,GAAQ,MAAyB;AAC5D,IAAS;GAAE,GAAG;IAAS,IAAM;GAAO,CAAC;IAEvC,CAAC,GAAQ,EAAS,CACnB,EAEK,IAAqB,GAAa,GAAe,GAAgC,MAAkB;AACvG,KAAY,MAAS;GACnB,IAAM,IAAa,CAAC,GAAG,EAAK;AAE5B,UADA,EAAW,KAAS;IAAE,GAAG,EAAW;KAAS,IAAQ;IAAO,EACrD;IACP;IACD,EAAE,CAAC,EAIA,IAAoB,GAAa,GAAe,MAA6B;AACjF,KAAY,MAAS;GACnB,IAAM,IAAa,CAAC,GAAG,EAAK;AAE5B,UADA,EAAW,KAAS;IAAE,GAAG,EAAW;IAAQ,kBAAkB;IAAO,EAC9D;IACP;IACD,EAAE,CAAC,EAEA,IAAU,GACb,MAAkB;EACjB,IAAM,IAAW,EAAQ,IAAQ,oBAAoB,EAAE,EACjD,IAAwB;GAC5B,UAAU;GACV,OAAO;GACP,OAAO;IAAE,SAAS;IAAU,WAAW;IAAU,MAAM;IAAM;GAC9D;AACD,IAAkB,GAAO,CAAC,GAAG,GAAU,EAAK,CAAC;IAE/C,CAAC,GAAS,EAAkB,CAC7B,EAEK,IAAa,GAChB,GAAkB,GAAmB,MAAoC;AAGxE,IAAkB,IAFD,EAAQ,IAAW,oBAAoB,EAAE,EACpC,KAAK,GAAG,MAAO,MAAM,IAAY;GAAE,GAAG;GAAG,GAAG;GAAO,GAAG,EAAG,CAC9C;IAEnC,CAAC,GAAS,EAAkB,CAC7B,EAEK,IAAkB,GACrB,GAAkB,GAAmB,MAA2B;AAK/D,IAAkB,IAJD,EAAQ,IAAW,oBAAoB,EAAE,EACpC,KAAK,GAAG,MAC5B,MAAM,IAAY;GAAE,GAAG;GAAG,OAAO;IAAE,GAAG,EAAE;IAAO,SAAS;IAAQ,WAAW;IAAQ;GAAE,GAAG,EACzF,CACgC;IAEnC,CAAC,GAAS,EAAkB,CAC7B,EAEK,IAAa,GAChB,GAAkB,MAAsB;AAEvC,IACE,IAFe,EAAQ,IAAW,oBAAoB,EAAE,EAG/C,QAAQ,GAAG,MAAM,MAAM,EAAU,CAC3C;IAEH,CAAC,GAAS,EAAkB,CAC7B,EAEK,IAAY,QAAkB;AAClC,KAAY,MAAS,CAAC,GAAG,GAAM;GAAE,OAAO;GAAI,QAAQ;GAAI,CAAC,CAAC;IACzD,EAAE,CAAC,EAEA,IAAe,GAAa,MAAkB;AAClD,KAAY,MAAS,EAAK,QAAQ,GAAG,MAAM,MAAM,EAAM,CAAC;IACvD,EAAE,CAAC;AAEN,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;IAAO,WAAU;cAAmD;IAAiB,CAAA,EACrF,kBAAC,UAAD;IACE,OAAO,EAAO,YAAY;IAC1B,WAAW,MAAM,EAAa,YAAY,OAAO,EAAE,OAAO,MAAM,CAAC;IACjE,WAAU;cAHZ;KAYE,kBAAC,UAAD;MAAQ,OAAO;gBAAI;MAAgB,CAAA;KACnC,kBAAC,UAAD;MAAQ,OAAO;gBAAI;MAAgB,CAAA;KACnC,kBAAC,UAAD;MAAQ,OAAO;gBAAI;MAAgB,CAAA;KACnC,kBAAC,UAAD;MAAQ,OAAO;gBAAK;MAAiB,CAAA;KAC9B;MACL,EAAA,CAAA;GAGN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,SAAD;KAAO,WAAU;eAAwC;KAAe,CAAA,EACxE,kBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,WAAU;eAIX;KAEQ,CAAA,CACL;OAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,EAAQ,KAAK,GAAK,MACjB,kBAAC,OAAD;KAEE,WAAU;eAFZ;MASE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAhB,CAA8C,WAAQ,IAAQ,EAAS;WACvE,kBAAC,UAAD;QACE,MAAK;QACL,eAAe,EAAa,EAAM;QAClC,WAAU;kBAEV,kBAAC,OAAD;SAAK,WAAU;SAAU,MAAK;SAAO,QAAO;SAAe,SAAQ;mBACjE,kBAAC,QAAD;UAAM,eAAc;UAAQ,gBAAe;UAAQ,aAAa;UAAG,GAAE;UAAyB,CAAA;SAC1F,CAAA;QACC,CAAA,CACL;;MAEN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,SAAD;QACE,MAAK;QACL,OAAO,EAAI,SAAS;QACpB,WAAW,MAAM,EAAmB,GAAO,SAAS,EAAE,OAAO,MAAM;QACnE,aAAY;QACZ,WAAU;QAQV,CAAA,EACF,kBAAC,SAAD;QACE,MAAK;QACL,OAAO,EAAI,UAAU;QACrB,WAAW,MAAM,EAAmB,GAAO,UAAU,EAAE,OAAO,MAAM;QACpE,aAAY;QACZ,WAAU;QAQV,CAAA,CACE;;MAEN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,UAAD;QACE,OAAO,EAAI,UAAU;QACrB,WAAW,MAAM,EAAmB,GAAO,UAAU,EAAE,OAAO,MAAM;QACpE,WAAU;kBAHZ;SAYE,kBAAC,UAAD;UAAQ,OAAM;oBAAO;UAAa,CAAA;SAClC,kBAAC,UAAD;UAAQ,OAAM;oBAAS;UAAe,CAAA;SACtC,kBAAC,UAAD;UAAQ,OAAM;oBAAW;UAAiB,CAAA;SAC1C,kBAAC,UAAD;UAAQ,OAAM;oBAAa;UAAmB,CAAA;SAC9C,kBAAC,UAAD;UAAQ,OAAM;oBAAO;UAAa,CAAA;SAClC,kBAAC,UAAD;UAAQ,OAAM;oBAAQ;UAAc,CAAA;SAC7B;WACT,kBAAC,UAAD;QACE,OAAO,EAAI,SAAS;QACpB,WAAW,MAAM,EAAmB,GAAO,SAAS,EAAE,OAAO,MAAM;QACnE,WAAU;kBAHZ;SAYE,kBAAC,UAAD;UAAQ,OAAM;oBAAO;UAAa,CAAA;SAClC,kBAAC,UAAD;UAAQ,OAAM;oBAAS;UAAe,CAAA;SACtC,kBAAC,UAAD;UAAQ,OAAM;oBAAQ;UAAc,CAAA;SAC7B;UACL;;MAGN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,QAAD;UAAM,WAAU;oBAA0C;UAA6B,CAAA,EACvF,kBAAC,UAAD;UACE,MAAK;UACL,eAAe,EAAQ,EAAM;UAC7B,WAAU;oBACX;UAEQ,CAAA,CACL;;SAEJ,EAAI,kBAAkB,UAAU,OAAO,KACvC,kBAAC,KAAD;SAAG,WAAU;mBAA8B;SAA0C,CAAA;QAGvF,kBAAC,OAAD;SAAK,WAAU;oBACX,EAAI,oBAAoB,EAAE,EAAE,KAAK,GAAM,MAAc;UACrD,IAAM,IAAc,EAAK,aAAa,aAAa,EAAK,aAAa,WAC/D,IAAgC,EAAK,OAAO,WAAW,EAAK,OAAO,aAAa;AACtF,iBACE,kBAAC,OAAD;WAEE,WAAU;qBAFZ,CAIE,kBAAC,OAAD;YAAK,WAAU;sBAAf;aACE,kBAAC,UAAD;cACE,OAAO,EAAK;cACZ,WAAW,MACT,EAAW,GAAO,GAAW,EAAE,UAAU,EAAE,OAAO,OAA8B,CAAC;cAEnF,WAAW,GAAG,EAAe;wBAE5B,EAAa,KAAK,MACjB,kBAAC,UAAD;eAAuB,OAAO,EAAG;yBAC9B,EAAG;eACG,EAFI,EAAG,MAEP,CACT;cACK,CAAA;aACT,kBAAC,SAAD;cACE,MAAK;cACL,OAAO,EAAK,SAAS;cACrB,WAAW,MAAM,EAAW,GAAO,GAAW,EAAE,OAAO,EAAE,OAAO,OAAO,CAAC;cACxE,aAAY;cACZ,WAAW,GAAG,EAAe;cAC7B,CAAA;aACD,KACC,kBAAC,SAAD;cACE,MAAK;cACL,OAAO,EAAK,UAAU;cACtB,WAAW,MAAM,EAAW,GAAO,GAAW,EAAE,QAAQ,EAAE,OAAO,OAAO,CAAC;cACzE,aAAY;cACZ,WAAW,GAAG,EAAe;cAC7B,CAAA;aAEJ,kBAAC,UAAD;cACE,MAAK;cACL,eAAe,EAAW,GAAO,EAAU;cAC3C,WAAU;cACV,cAAW;wBAEX,kBAAC,OAAD;eAAK,WAAU;eAAc,MAAK;eAAO,QAAO;eAAe,SAAQ;yBACrE,kBAAC,QAAD;gBACE,eAAc;gBACd,gBAAe;gBACf,aAAa;gBACb,GAAE;gBACF,CAAA;eACE,CAAA;cACC,CAAA;aACL;eACN,kBAAC,OAAD;YAAK,WAAU;sBAAf,CACE,kBAAC,UAAD;aACE,OAAO;aACP,WAAW,MAAM,EAAgB,GAAO,GAAW,EAAE,OAAO,MAAwB;aACpF,WAAW,GAAG,EAAe;uBAE5B,EAAW,KAAK,MACf,kBAAC,UAAD;cAAuB,OAAO,EAAG;wBAC9B,EAAG;cACG,EAFI,EAAG,MAEP,CACT;aACK,CAAA,EACT,kBAAC,SAAD;aAAO,WAAU;uBAAjB,CACE,kBAAC,SAAD;cACE,MAAK;cACL,SAAS,EAAK,OAAO,SAAS;cAC9B,WAAW,MACT,EAAW,GAAO,GAAW,EAAE,OAAO;eAAE,GAAG,EAAK;eAAO,MAAM,EAAE,OAAO;eAAS,EAAE,CAAC;cAEpF,WAAU;cACV,CAAA,EAAA,OAEI;eACJ;cACF;aAzEC,EAyED;WAER;SACE,CAAA;QACF;;MACF;OA/LC,EA+LD,CACN,EAED,EAAQ,WAAW,KAClB,kBAAC,KAAD;KAAG,WAAU;eAA+C;KAExD,CAAA,CAEF;MACF,EAAA,CAAA;GAGN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,SAAD;MAAO,WAAU;gBAAjB,CACE,kBAAC,SAAD;OACE,MAAK;OACL,SAAS,EAAO,eAAe;OAC/B,WAAW,MAAM,EAAa,cAAc,EAAE,OAAO,QAAQ;OAC7D,WAAU;OAQV,CAAA,EACF,kBAAC,QAAD;OAAM,WAAU;iBAA4B;OAAsB,CAAA,CAC5D;;KAER,kBAAC,SAAD;MAAO,WAAU;gBAAjB,CACE,kBAAC,SAAD;OACE,MAAK;OACL,SAAS,EAAO,mBAAmB;OACnC,WAAW,MAAM,EAAa,kBAAkB,EAAE,OAAO,QAAQ;OACjE,WAAU;OAQV,CAAA,EACF,kBAAC,QAAD;OAAM,WAAU;iBAA4B;OAAsB,CAAA,CAC5D;;KAER,kBAAC,SAAD;MAAO,WAAU;gBAAjB,CACE,kBAAC,SAAD;OACE,MAAK;OACL,SAAS,EAAO,eAAe;OAC/B,WAAW,MAAM,EAAa,cAAc,EAAE,OAAO,QAAQ;OAC7D,WAAU;OAQV,CAAA,EACF,kBAAC,QAAD;OAAM,WAAU;iBAA4B;OAAyB,CAAA,CAC/D;;KAER,kBAAC,SAAD;MAAO,WAAU;gBAAjB,CACE,kBAAC,SAAD;OACE,MAAK;OACL,SAAS,EAAO,iBAAiB;OACjC,WAAW,MAAM,EAAa,gBAAgB,EAAE,OAAO,QAAQ;OAC/D,WAAU;OAQV,CAAA,EACF,kBAAC,QAAD;OAAM,WAAU;iBAA4B;OAAoB,CAAA,CAC1D;;KAER,kBAAC,SAAD;MAAO,WAAU;gBAAjB,CACE,kBAAC,SAAD;OACE,MAAK;OACL,SAAS,EAAO,gBAAgB;OAChC,WAAW,MAAM,EAAa,eAAe,EAAE,OAAO,QAAQ;OAC9D,WAAU;OAQV,CAAA,EACF,kBAAC,QAAD;OAAM,WAAU;iBAA4B;OAAmB,CAAA,CACzD;;KACJ;;GACF;;EAER"}
@@ -37,7 +37,7 @@ function a(e) {
37
37
  }).filter((e) => e !== null) : [];
38
38
  }
39
39
  function o(e) {
40
- return e >= 100 ? "bg-state-success" : e >= 50 ? "bg-action-primary-bg" : e > 0 ? "bg-state-warning" : "bg-bg-sunken";
40
+ return e >= 100 ? "bg-status-success-bg" : e >= 50 ? "bg-action-primary-bg" : e > 0 ? "bg-status-warning-bg" : "bg-bg-sunken";
41
41
  }
42
42
  var s = e(function({ widget: e, data: i, onClick: s }) {
43
43
  let c = t(() => a(i), [i]), l = i?.milestones || [], { minDate: u, maxDate: d, totalDays: f } = t(() => {
@@ -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-state-success';\n if (progress >= 50) return 'bg-action-primary-bg';\n if (progress > 0) return 'bg-state-warning';\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\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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"}
@@ -10,9 +10,9 @@ function u(e, t, n) {
10
10
  }, i = {
11
11
  PRIMARY: "bg-action-primary text-white hover:bg-action-primary/90 focus:ring-action-primary/50 transition-colors",
12
12
  SECONDARY: "bg-bg-sunken text-primary hover:bg-bg-sunken/80 focus:ring-muted transition-colors",
13
- DANGER: "bg-state-error text-white hover:bg-state-error/90 focus:ring-state-error/50 transition-colors",
14
- SUCCESS: "bg-state-success text-white hover:bg-state-success/90 focus:ring-state-success/50 transition-colors",
15
- WARNING: "bg-state-warning text-white hover:bg-state-warning/90 focus:ring-state-warning/50 transition-colors"
13
+ DANGER: "bg-status-error-bg text-white hover:bg-status-error-bg/90 focus:ring-status-error-border/50 transition-colors",
14
+ SUCCESS: "bg-status-success-bg text-white hover:bg-status-success-bg/90 focus:ring-status-success-border/50 transition-colors",
15
+ WARNING: "bg-status-warning-bg text-white hover:bg-status-warning-bg/90 focus:ring-status-warning-border/50 transition-colors"
16
16
  }, a = n ? "opacity-50 cursor-not-allowed" : "cursor-pointer", o = i[e || "SECONDARY"] || i.SECONDARY;
17
17
  return `inline-flex items-center justify-center font-medium rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 ${r[t]} ${o} ${a}`;
18
18
  }
@@ -45,9 +45,9 @@ function f(e) {
45
45
  let t = {
46
46
  PRIMARY: "bg-action-primary text-white hover:bg-action-primary/90",
47
47
  SECONDARY: "bg-secondary text-white hover:bg-secondary/90",
48
- DANGER: "bg-state-error text-white hover:bg-state-error/90",
49
- SUCCESS: "bg-state-success text-white hover:bg-state-success/90",
50
- WARNING: "bg-state-warning text-white hover:bg-state-warning/90"
48
+ DANGER: "bg-status-error-bg text-white hover:bg-status-error-bg/90",
49
+ SUCCESS: "bg-status-success-bg text-white hover:bg-status-success-bg/90",
50
+ WARNING: "bg-status-warning-bg text-white hover:bg-status-warning-bg/90"
51
51
  };
52
52
  return `px-4 py-2 text-sm font-medium rounded-md transition-colors ${t[e || "PRIMARY"] || t.PRIMARY}`;
53
53
  }
@@ -1 +1 @@
1
- {"version":3,"file":"WidgetActions.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/widget-actions/WidgetActions.tsx"],"sourcesContent":["/**\n * Widget Actions Component (v2.0)\n *\n * Renders interactive action buttons for widgets.\n * Supports multiple action types, styles, confirmation dialogs, and icons.\n */\n\nimport React, { memo, useCallback, useState, useMemo, useRef, useEffect } from 'react';\nimport { createPortal } from 'react-dom';\nimport type { WidgetAction, ActionContext, ActionResult } from '../../../renderers/types/renderer';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface WidgetActionsProps {\n /** List of actions to render */\n actions: WidgetAction[];\n /** Action context (widget ID, data, etc.) */\n context: ActionContext;\n /** Callback when action is triggered */\n onAction?: (action: WidgetAction, context: ActionContext) => Promise<ActionResult | void>;\n /** Whether actions are disabled */\n disabled?: boolean;\n /** Layout direction */\n layout?: 'horizontal' | 'vertical';\n /** Size of action buttons */\n size?: 'sm' | 'md' | 'lg';\n /** Whether to show labels */\n showLabels?: boolean;\n /** Maximum number of visible actions (rest go to overflow menu) */\n maxVisible?: number;\n /** Custom class name */\n className?: string;\n}\n\ninterface ConfirmationDialogProps {\n title: string;\n message: string;\n confirmLabel: string;\n cancelLabel: string;\n style: WidgetAction['style'];\n onConfirm: () => void;\n onCancel: () => void;\n}\n\n// ============================================================================\n// Style Utilities\n// ============================================================================\n\nfunction getButtonClasses(\n style: WidgetAction['style'] | undefined,\n size: 'sm' | 'md' | 'lg',\n disabled: boolean\n): string {\n const baseClasses =\n 'inline-flex items-center justify-center font-medium rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2';\n\n const sizeClasses = {\n sm: 'px-2.5 py-1.5 text-xs',\n md: 'px-4 py-2 text-sm',\n lg: 'px-6 py-3 text-base',\n };\n\n const styleClasses: Record<string, string> = {\n PRIMARY: 'bg-action-primary text-white hover:bg-action-primary/90 focus:ring-action-primary/50 transition-colors',\n SECONDARY: 'bg-bg-sunken text-primary hover:bg-bg-sunken/80 focus:ring-muted transition-colors',\n DANGER: 'bg-state-error text-white hover:bg-state-error/90 focus:ring-state-error/50 transition-colors',\n SUCCESS: 'bg-state-success text-white hover:bg-state-success/90 focus:ring-state-success/50 transition-colors',\n WARNING: 'bg-state-warning text-white hover:bg-state-warning/90 focus:ring-state-warning/50 transition-colors',\n };\n\n const disabledClasses = disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer';\n\n // Default to SECONDARY if style is undefined\n const effectiveStyle = style || 'SECONDARY';\n const styleClass = styleClasses[effectiveStyle] || styleClasses.SECONDARY;\n\n return `${baseClasses} ${sizeClasses[size]} ${styleClass} ${disabledClasses}`;\n}\n\n// Get inline styles as fallback for button visibility\nfunction getButtonInlineStyles(style: WidgetAction['style'] | undefined): React.CSSProperties {\n const styles: Record<string, React.CSSProperties> = {\n PRIMARY: { backgroundColor: 'var(--color-action-primary-bg)', color: 'var(--color-action-primary-text)' },\n SECONDARY: { backgroundColor: 'var(--color-bg-muted)', color: 'var(--color-text-primary)' },\n DANGER: { backgroundColor: 'var(--color-status-error-bg)', color: 'var(--color-action-primary-text)' },\n SUCCESS: { backgroundColor: 'var(--color-status-success-bg)', color: 'var(--color-action-primary-text)' },\n WARNING: { backgroundColor: 'var(--color-status-warning-bg)', color: 'var(--color-action-primary-text)' },\n };\n const effectiveStyle = style || 'SECONDARY';\n return styles[effectiveStyle] || styles.SECONDARY;\n}\n\nfunction getConfirmButtonClasses(style: WidgetAction['style']): string {\n const styleClasses = {\n PRIMARY: 'bg-action-primary text-white hover:bg-action-primary/90',\n SECONDARY: 'bg-secondary text-white hover:bg-secondary/90',\n DANGER: 'bg-state-error text-white hover:bg-state-error/90',\n SUCCESS: 'bg-state-success text-white hover:bg-state-success/90',\n WARNING: 'bg-state-warning text-white hover:bg-state-warning/90',\n };\n\n const effectiveStyle = style || 'PRIMARY';\n return `px-4 py-2 text-sm font-medium rounded-md transition-colors ${styleClasses[effectiveStyle] || styleClasses.PRIMARY}`;\n}\n\n// Get inline styles for confirm button to ensure visibility\nfunction getConfirmButtonInlineStyles(style: WidgetAction['style'] | undefined): React.CSSProperties {\n const styles: Record<string, React.CSSProperties> = {\n PRIMARY: {\n backgroundColor: 'var(--color-action-primary-bg)',\n color: 'var(--color-action-primary-text)',\n padding: '8px 16px',\n borderRadius: '6px',\n fontWeight: 500,\n },\n SECONDARY: {\n backgroundColor: 'var(--color-text-secondary)',\n color: 'var(--color-action-primary-text)',\n padding: '8px 16px',\n borderRadius: '6px',\n fontWeight: 500,\n },\n DANGER: {\n backgroundColor: 'var(--color-status-error-bg)',\n color: 'var(--color-action-primary-text)',\n padding: '8px 16px',\n borderRadius: '6px',\n fontWeight: 500,\n },\n SUCCESS: {\n backgroundColor: 'var(--color-status-success-bg)',\n color: 'var(--color-action-primary-text)',\n padding: '8px 16px',\n borderRadius: '6px',\n fontWeight: 500,\n },\n WARNING: {\n backgroundColor: 'var(--color-status-warning-bg)',\n color: 'var(--color-action-primary-text)',\n padding: '8px 16px',\n borderRadius: '6px',\n fontWeight: 500,\n },\n };\n const effectiveStyle = style || 'PRIMARY';\n return styles[effectiveStyle] || styles.PRIMARY;\n}\n\n// ============================================================================\n// Icon Component\n// ============================================================================\n\ninterface ActionIconProps {\n name: string;\n className?: string;\n}\n\nconst ActionIcon: React.FC<ActionIconProps> = memo(function ActionIcon({ name, className = 'w-4 h-4' }) {\n // Common icons used in actions\n const icons: Record<string, React.ReactNode> = {\n 'external-link': (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14\"\n />\n </svg>\n ),\n save: (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4\"\n />\n </svg>\n ),\n trash: (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n />\n </svg>\n ),\n edit: (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z\"\n />\n </svg>\n ),\n refresh: (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\"\n />\n </svg>\n ),\n download: (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\"\n />\n </svg>\n ),\n upload: (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12\"\n />\n </svg>\n ),\n plus: (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 4v16m8-8H4\" />\n </svg>\n ),\n check: (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M5 13l4 4L19 7\" />\n </svg>\n ),\n x: (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n ),\n 'more-horizontal': (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 12h.01M12 12h.01M19 12h.01M6 12a1 1 0 11-2 0 1 1 0 012 0zm7 0a1 1 0 11-2 0 1 1 0 012 0zm7 0a1 1 0 11-2 0 1 1 0 012 0z\"\n />\n </svg>\n ),\n };\n\n return icons[name] || null;\n});\n\n// ============================================================================\n// Confirmation Dialog\n// ============================================================================\n\nconst ConfirmationDialog: React.FC<ConfirmationDialogProps> = memo(function ConfirmationDialog({\n title,\n message,\n confirmLabel,\n cancelLabel,\n style,\n onConfirm,\n onCancel,\n}) {\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center\"\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 9999,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n {/* Backdrop */}\n <div\n className=\"absolute inset-0 bg-black/50\"\n style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, backgroundColor: 'rgba(0,0,0,0.5)' }}\n onClick={onCancel}\n />\n\n {/* Dialog */}\n <div\n className=\"relative bg-surface rounded-lg shadow-xl max-w-md w-full mx-4 p-6 animate-in fade-in zoom-in-95 duration-200\"\n style={{\n position: 'relative',\n backgroundColor: 'var(--color-bg-surface)',\n borderRadius: '8px',\n boxShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.25)',\n maxWidth: '28rem',\n width: '100%',\n margin: '0 16px',\n padding: '24px',\n zIndex: 10000,\n }}\n >\n <h3\n className=\"text-lg font-semibold text-primary\"\n style={{ fontSize: '18px', fontWeight: 600, color: 'var(--color-text-primary)', margin: 0 }}\n >\n {title}\n </h3>\n <p\n className=\"mt-2 text-sm text-secondary\"\n style={{ marginTop: '8px', fontSize: '14px', color: 'var(--color-text-secondary)' }}\n >\n {message}\n </p>\n <div\n className=\"mt-4 flex justify-end gap-3\"\n style={{ marginTop: '16px', display: 'flex', justifyContent: 'flex-end', gap: '12px' }}\n >\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-4 py-2 text-sm font-medium text-secondary bg-bg-sunken hover:bg-bg-sunken/80 rounded-md transition-colors\"\n style={{\n padding: '8px 16px',\n fontSize: '14px',\n fontWeight: 500,\n color: 'var(--color-text-secondary)',\n backgroundColor: 'var(--color-bg-muted)',\n borderRadius: '6px',\n border: 'none',\n cursor: 'pointer',\n }}\n >\n {cancelLabel}\n </button>\n <button\n type=\"button\"\n onClick={onConfirm}\n className={getConfirmButtonClasses(style)}\n style={getConfirmButtonInlineStyles(style)}\n >\n {confirmLabel}\n </button>\n </div>\n </div>\n </div>\n );\n});\n\n// ============================================================================\n// Overflow Menu\n// ============================================================================\n\ninterface OverflowMenuProps {\n actions: WidgetAction[];\n context: ActionContext;\n onAction: (action: WidgetAction) => void;\n disabled?: boolean;\n size: 'sm' | 'md' | 'lg';\n}\n\nconst OverflowMenu: React.FC<OverflowMenuProps> = memo(function OverflowMenu({\n actions,\n context: _context,\n onAction,\n disabled,\n size,\n}) {\n const [isOpen, setIsOpen] = useState(false);\n const buttonRef = useRef<HTMLButtonElement>(null);\n const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 });\n\n const handleToggle = useCallback(() => {\n if (!disabled) {\n setIsOpen((prev) => !prev);\n }\n }, [disabled]);\n\n const handleAction = useCallback(\n (action: WidgetAction) => {\n setIsOpen(false);\n onAction(action);\n },\n [onAction]\n );\n\n const handleClickOutside = useCallback(() => {\n setIsOpen(false);\n }, []);\n\n // Calculate menu position when opening\n useEffect(() => {\n if (isOpen && buttonRef.current) {\n const rect = buttonRef.current.getBoundingClientRect();\n setMenuPosition({\n top: rect.bottom + 4, // 4px gap below button\n left: rect.right - 192, // 192px = w-48, align right edge\n });\n }\n }, [isOpen]);\n\n if (actions.length === 0) return null;\n\n return (\n <div className=\"relative\">\n <button\n ref={buttonRef}\n type=\"button\"\n onClick={handleToggle}\n disabled={disabled}\n className={getButtonClasses('SECONDARY', size, disabled ?? false)}\n aria-label=\"More actions\"\n >\n <ActionIcon name=\"more-horizontal\" />\n </button>\n\n {isOpen &&\n createPortal(\n <>\n {/* Click-outside handler */}\n <div className=\"fixed inset-0 z-[9998]\" onClick={handleClickOutside} />\n\n {/* Menu - rendered via portal at body level */}\n <div\n className=\"fixed w-48 bg-surface rounded-md shadow-lg ring-1 ring-border z-[9999] animate-in fade-in slide-in-from-top-2 duration-150\"\n style={{\n top: menuPosition.top,\n left: Math.max(8, menuPosition.left), // Ensure at least 8px from left edge\n }}\n >\n <div className=\"py-1\">\n {actions.map((action) => (\n <button\n key={action.id}\n type=\"button\"\n onClick={() => handleAction(action)}\n disabled={action.disabled}\n className=\"w-full text-left px-4 py-2 text-sm text-secondary hover:bg-bg-sunken hover:text-primary disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2 transition-colors\"\n >\n {action.icon && <ActionIcon name={action.icon} className=\"w-4 h-4\" />}\n {action.label}\n </button>\n ))}\n </div>\n </div>\n </>,\n document.body\n )}\n </div>\n );\n});\n\n// ============================================================================\n// Action Button\n// ============================================================================\n\ninterface ActionButtonProps {\n action: WidgetAction;\n context: ActionContext;\n onAction: (action: WidgetAction) => void;\n disabled?: boolean;\n size: 'sm' | 'md' | 'lg';\n showLabel?: boolean;\n}\n\nconst ActionButton: React.FC<ActionButtonProps> = memo(function ActionButton({\n action,\n context: _context,\n onAction,\n disabled,\n size,\n showLabel = true,\n}) {\n const isDisabled = disabled || action.disabled;\n\n const handleClick = useCallback(() => {\n if (!isDisabled) {\n onAction(action);\n }\n }, [action, isDisabled, onAction]);\n\n // Get both classes and inline styles for guaranteed visibility\n const buttonClasses = getButtonClasses(action.style, size, isDisabled);\n const buttonInlineStyles = getButtonInlineStyles(action.style);\n\n // Handle LINK type\n if (action.type === 'LINK' && action.metadata?.url) {\n return (\n <a\n href={action.metadata.url as string}\n target={(action.metadata.target as string) || '_blank'}\n rel=\"noopener noreferrer\"\n className={buttonClasses}\n style={buttonInlineStyles}\n aria-disabled={isDisabled}\n >\n {action.icon && <ActionIcon name={action.icon} className=\"w-4 h-4 mr-1.5\" />}\n {showLabel && action.label}\n {!action.icon && <ActionIcon name=\"external-link\" className=\"w-4 h-4 ml-1.5\" />}\n </a>\n );\n }\n\n return (\n <button\n type={action.type === 'SUBMIT' ? 'submit' : 'button'}\n onClick={handleClick}\n disabled={isDisabled}\n className={buttonClasses}\n style={buttonInlineStyles}\n >\n {action.icon && <ActionIcon name={action.icon} className=\"w-4 h-4 mr-1.5\" />}\n {showLabel && action.label}\n </button>\n );\n});\n\n// ============================================================================\n// Main Component\n// ============================================================================\n\nexport const WidgetActions: React.FC<WidgetActionsProps> = memo(function WidgetActions({\n actions,\n context,\n onAction,\n disabled = false,\n layout = 'horizontal',\n size = 'md',\n showLabels = true,\n maxVisible = 3,\n className = '',\n}) {\n const [pendingAction, setPendingAction] = useState<WidgetAction | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n\n // Filter visible actions (not hidden)\n const visibleActions = useMemo(() => {\n return actions.filter((a) => !a.hidden).sort((a, b) => a.order - b.order);\n }, [actions]);\n\n // Split into main and overflow actions\n const { mainActions, overflowActions } = useMemo(() => {\n if (visibleActions.length <= maxVisible) {\n return { mainActions: visibleActions, overflowActions: [] };\n }\n return {\n mainActions: visibleActions.slice(0, maxVisible - 1),\n overflowActions: visibleActions.slice(maxVisible - 1),\n };\n }, [visibleActions, maxVisible]);\n\n // Execute action\n const executeAction = useCallback(\n async (action: WidgetAction) => {\n if (!onAction) return;\n\n setIsLoading(true);\n try {\n await onAction(action, context);\n } catch (error) {\n } finally {\n setIsLoading(false);\n }\n },\n [onAction, context]\n );\n\n // Handle action trigger\n const handleTriggerAction = useCallback(\n (action: WidgetAction) => {\n // If action has confirmation, show dialog\n if (action.confirmation) {\n setPendingAction(action);\n return;\n }\n\n // Execute action immediately\n executeAction(action);\n },\n [executeAction]\n );\n\n // Handle confirmation\n const handleConfirm = useCallback(() => {\n if (pendingAction) {\n executeAction(pendingAction);\n setPendingAction(null);\n }\n }, [pendingAction, executeAction]);\n\n const handleCancel = useCallback(() => {\n setPendingAction(null);\n }, []);\n\n // No actions to render\n if (visibleActions.length === 0) {\n return null;\n }\n\n const layoutClasses = layout === 'horizontal' ? 'flex flex-row flex-wrap gap-2' : 'flex flex-col gap-2';\n\n return (\n <>\n <div className={`${layoutClasses} ${className}`}>\n {mainActions.map((action) => (\n <ActionButton\n key={action.id}\n action={action}\n context={context}\n onAction={handleTriggerAction}\n disabled={disabled || isLoading}\n size={size}\n showLabel={showLabels}\n />\n ))}\n\n {overflowActions.length > 0 && (\n <OverflowMenu\n actions={overflowActions}\n context={context}\n onAction={handleTriggerAction}\n disabled={disabled || isLoading}\n size={size}\n />\n )}\n </div>\n\n {/* Confirmation Dialog */}\n {pendingAction?.confirmation && (\n <ConfirmationDialog\n title={pendingAction.confirmation.title || 'Confirm Action'}\n message={pendingAction.confirmation.message || 'Are you sure you want to proceed?'}\n confirmLabel={pendingAction.confirmation.confirmLabel || 'OK'}\n cancelLabel={pendingAction.confirmation.cancelLabel || 'Cancel'}\n style={pendingAction.style}\n onConfirm={handleConfirm}\n onCancel={handleCancel}\n />\n )}\n </>\n );\n});\n\nexport default WidgetActions;\n"],"mappings":"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"}
1
+ {"version":3,"file":"WidgetActions.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/widget-actions/WidgetActions.tsx"],"sourcesContent":["/**\n * Widget Actions Component (v2.0)\n *\n * Renders interactive action buttons for widgets.\n * Supports multiple action types, styles, confirmation dialogs, and icons.\n */\n\nimport React, { memo, useCallback, useState, useMemo, useRef, useEffect } from 'react';\nimport { createPortal } from 'react-dom';\nimport type { WidgetAction, ActionContext, ActionResult } from '../../../renderers/types/renderer';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface WidgetActionsProps {\n /** List of actions to render */\n actions: WidgetAction[];\n /** Action context (widget ID, data, etc.) */\n context: ActionContext;\n /** Callback when action is triggered */\n onAction?: (action: WidgetAction, context: ActionContext) => Promise<ActionResult | void>;\n /** Whether actions are disabled */\n disabled?: boolean;\n /** Layout direction */\n layout?: 'horizontal' | 'vertical';\n /** Size of action buttons */\n size?: 'sm' | 'md' | 'lg';\n /** Whether to show labels */\n showLabels?: boolean;\n /** Maximum number of visible actions (rest go to overflow menu) */\n maxVisible?: number;\n /** Custom class name */\n className?: string;\n}\n\ninterface ConfirmationDialogProps {\n title: string;\n message: string;\n confirmLabel: string;\n cancelLabel: string;\n style: WidgetAction['style'];\n onConfirm: () => void;\n onCancel: () => void;\n}\n\n// ============================================================================\n// Style Utilities\n// ============================================================================\n\nfunction getButtonClasses(\n style: WidgetAction['style'] | undefined,\n size: 'sm' | 'md' | 'lg',\n disabled: boolean\n): string {\n const baseClasses =\n 'inline-flex items-center justify-center font-medium rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2';\n\n const sizeClasses = {\n sm: 'px-2.5 py-1.5 text-xs',\n md: 'px-4 py-2 text-sm',\n lg: 'px-6 py-3 text-base',\n };\n\n const styleClasses: Record<string, string> = {\n PRIMARY: 'bg-action-primary text-white hover:bg-action-primary/90 focus:ring-action-primary/50 transition-colors',\n SECONDARY: 'bg-bg-sunken text-primary hover:bg-bg-sunken/80 focus:ring-muted transition-colors',\n DANGER:\n 'bg-status-error-bg text-white hover:bg-status-error-bg/90 focus:ring-status-error-border/50 transition-colors',\n SUCCESS:\n 'bg-status-success-bg text-white hover:bg-status-success-bg/90 focus:ring-status-success-border/50 transition-colors',\n WARNING:\n 'bg-status-warning-bg text-white hover:bg-status-warning-bg/90 focus:ring-status-warning-border/50 transition-colors',\n };\n\n const disabledClasses = disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer';\n\n // Default to SECONDARY if style is undefined\n const effectiveStyle = style || 'SECONDARY';\n const styleClass = styleClasses[effectiveStyle] || styleClasses.SECONDARY;\n\n return `${baseClasses} ${sizeClasses[size]} ${styleClass} ${disabledClasses}`;\n}\n\n// Get inline styles as fallback for button visibility\nfunction getButtonInlineStyles(style: WidgetAction['style'] | undefined): React.CSSProperties {\n const styles: Record<string, React.CSSProperties> = {\n PRIMARY: { backgroundColor: 'var(--color-action-primary-bg)', color: 'var(--color-action-primary-text)' },\n SECONDARY: { backgroundColor: 'var(--color-bg-muted)', color: 'var(--color-text-primary)' },\n DANGER: { backgroundColor: 'var(--color-status-error-bg)', color: 'var(--color-action-primary-text)' },\n SUCCESS: { backgroundColor: 'var(--color-status-success-bg)', color: 'var(--color-action-primary-text)' },\n WARNING: { backgroundColor: 'var(--color-status-warning-bg)', color: 'var(--color-action-primary-text)' },\n };\n const effectiveStyle = style || 'SECONDARY';\n return styles[effectiveStyle] || styles.SECONDARY;\n}\n\nfunction getConfirmButtonClasses(style: WidgetAction['style']): string {\n const styleClasses = {\n PRIMARY: 'bg-action-primary text-white hover:bg-action-primary/90',\n SECONDARY: 'bg-secondary text-white hover:bg-secondary/90',\n DANGER: 'bg-status-error-bg text-white hover:bg-status-error-bg/90',\n SUCCESS: 'bg-status-success-bg text-white hover:bg-status-success-bg/90',\n WARNING: 'bg-status-warning-bg text-white hover:bg-status-warning-bg/90',\n };\n\n const effectiveStyle = style || 'PRIMARY';\n return `px-4 py-2 text-sm font-medium rounded-md transition-colors ${styleClasses[effectiveStyle] || styleClasses.PRIMARY}`;\n}\n\n// Get inline styles for confirm button to ensure visibility\nfunction getConfirmButtonInlineStyles(style: WidgetAction['style'] | undefined): React.CSSProperties {\n const styles: Record<string, React.CSSProperties> = {\n PRIMARY: {\n backgroundColor: 'var(--color-action-primary-bg)',\n color: 'var(--color-action-primary-text)',\n padding: '8px 16px',\n borderRadius: '6px',\n fontWeight: 500,\n },\n SECONDARY: {\n backgroundColor: 'var(--color-text-secondary)',\n color: 'var(--color-action-primary-text)',\n padding: '8px 16px',\n borderRadius: '6px',\n fontWeight: 500,\n },\n DANGER: {\n backgroundColor: 'var(--color-status-error-bg)',\n color: 'var(--color-action-primary-text)',\n padding: '8px 16px',\n borderRadius: '6px',\n fontWeight: 500,\n },\n SUCCESS: {\n backgroundColor: 'var(--color-status-success-bg)',\n color: 'var(--color-action-primary-text)',\n padding: '8px 16px',\n borderRadius: '6px',\n fontWeight: 500,\n },\n WARNING: {\n backgroundColor: 'var(--color-status-warning-bg)',\n color: 'var(--color-action-primary-text)',\n padding: '8px 16px',\n borderRadius: '6px',\n fontWeight: 500,\n },\n };\n const effectiveStyle = style || 'PRIMARY';\n return styles[effectiveStyle] || styles.PRIMARY;\n}\n\n// ============================================================================\n// Icon Component\n// ============================================================================\n\ninterface ActionIconProps {\n name: string;\n className?: string;\n}\n\nconst ActionIcon: React.FC<ActionIconProps> = memo(function ActionIcon({ name, className = 'w-4 h-4' }) {\n // Common icons used in actions\n const icons: Record<string, React.ReactNode> = {\n 'external-link': (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14\"\n />\n </svg>\n ),\n save: (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4\"\n />\n </svg>\n ),\n trash: (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n />\n </svg>\n ),\n edit: (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z\"\n />\n </svg>\n ),\n refresh: (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\"\n />\n </svg>\n ),\n download: (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\"\n />\n </svg>\n ),\n upload: (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12\"\n />\n </svg>\n ),\n plus: (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 4v16m8-8H4\" />\n </svg>\n ),\n check: (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M5 13l4 4L19 7\" />\n </svg>\n ),\n x: (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n ),\n 'more-horizontal': (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 12h.01M12 12h.01M19 12h.01M6 12a1 1 0 11-2 0 1 1 0 012 0zm7 0a1 1 0 11-2 0 1 1 0 012 0zm7 0a1 1 0 11-2 0 1 1 0 012 0z\"\n />\n </svg>\n ),\n };\n\n return icons[name] || null;\n});\n\n// ============================================================================\n// Confirmation Dialog\n// ============================================================================\n\nconst ConfirmationDialog: React.FC<ConfirmationDialogProps> = memo(function ConfirmationDialog({\n title,\n message,\n confirmLabel,\n cancelLabel,\n style,\n onConfirm,\n onCancel,\n}) {\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center\"\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 9999,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n {/* Backdrop */}\n <div\n className=\"absolute inset-0 bg-black/50\"\n style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, backgroundColor: 'rgba(0,0,0,0.5)' }}\n onClick={onCancel}\n />\n\n {/* Dialog */}\n <div\n className=\"relative bg-surface rounded-lg shadow-xl max-w-md w-full mx-4 p-6 animate-in fade-in zoom-in-95 duration-200\"\n style={{\n position: 'relative',\n backgroundColor: 'var(--color-bg-surface)',\n borderRadius: '8px',\n boxShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.25)',\n maxWidth: '28rem',\n width: '100%',\n margin: '0 16px',\n padding: '24px',\n zIndex: 10000,\n }}\n >\n <h3\n className=\"text-lg font-semibold text-primary\"\n style={{ fontSize: '18px', fontWeight: 600, color: 'var(--color-text-primary)', margin: 0 }}\n >\n {title}\n </h3>\n <p\n className=\"mt-2 text-sm text-secondary\"\n style={{ marginTop: '8px', fontSize: '14px', color: 'var(--color-text-secondary)' }}\n >\n {message}\n </p>\n <div\n className=\"mt-4 flex justify-end gap-3\"\n style={{ marginTop: '16px', display: 'flex', justifyContent: 'flex-end', gap: '12px' }}\n >\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-4 py-2 text-sm font-medium text-secondary bg-bg-sunken hover:bg-bg-sunken/80 rounded-md transition-colors\"\n style={{\n padding: '8px 16px',\n fontSize: '14px',\n fontWeight: 500,\n color: 'var(--color-text-secondary)',\n backgroundColor: 'var(--color-bg-muted)',\n borderRadius: '6px',\n border: 'none',\n cursor: 'pointer',\n }}\n >\n {cancelLabel}\n </button>\n <button\n type=\"button\"\n onClick={onConfirm}\n className={getConfirmButtonClasses(style)}\n style={getConfirmButtonInlineStyles(style)}\n >\n {confirmLabel}\n </button>\n </div>\n </div>\n </div>\n );\n});\n\n// ============================================================================\n// Overflow Menu\n// ============================================================================\n\ninterface OverflowMenuProps {\n actions: WidgetAction[];\n context: ActionContext;\n onAction: (action: WidgetAction) => void;\n disabled?: boolean;\n size: 'sm' | 'md' | 'lg';\n}\n\nconst OverflowMenu: React.FC<OverflowMenuProps> = memo(function OverflowMenu({\n actions,\n context: _context,\n onAction,\n disabled,\n size,\n}) {\n const [isOpen, setIsOpen] = useState(false);\n const buttonRef = useRef<HTMLButtonElement>(null);\n const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 });\n\n const handleToggle = useCallback(() => {\n if (!disabled) {\n setIsOpen((prev) => !prev);\n }\n }, [disabled]);\n\n const handleAction = useCallback(\n (action: WidgetAction) => {\n setIsOpen(false);\n onAction(action);\n },\n [onAction]\n );\n\n const handleClickOutside = useCallback(() => {\n setIsOpen(false);\n }, []);\n\n // Calculate menu position when opening\n useEffect(() => {\n if (isOpen && buttonRef.current) {\n const rect = buttonRef.current.getBoundingClientRect();\n setMenuPosition({\n top: rect.bottom + 4, // 4px gap below button\n left: rect.right - 192, // 192px = w-48, align right edge\n });\n }\n }, [isOpen]);\n\n if (actions.length === 0) return null;\n\n return (\n <div className=\"relative\">\n <button\n ref={buttonRef}\n type=\"button\"\n onClick={handleToggle}\n disabled={disabled}\n className={getButtonClasses('SECONDARY', size, disabled ?? false)}\n aria-label=\"More actions\"\n >\n <ActionIcon name=\"more-horizontal\" />\n </button>\n\n {isOpen &&\n createPortal(\n <>\n {/* Click-outside handler */}\n <div className=\"fixed inset-0 z-[9998]\" onClick={handleClickOutside} />\n\n {/* Menu - rendered via portal at body level */}\n <div\n className=\"fixed w-48 bg-surface rounded-md shadow-lg ring-1 ring-border z-[9999] animate-in fade-in slide-in-from-top-2 duration-150\"\n style={{\n top: menuPosition.top,\n left: Math.max(8, menuPosition.left), // Ensure at least 8px from left edge\n }}\n >\n <div className=\"py-1\">\n {actions.map((action) => (\n <button\n key={action.id}\n type=\"button\"\n onClick={() => handleAction(action)}\n disabled={action.disabled}\n className=\"w-full text-left px-4 py-2 text-sm text-secondary hover:bg-bg-sunken hover:text-primary disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2 transition-colors\"\n >\n {action.icon && <ActionIcon name={action.icon} className=\"w-4 h-4\" />}\n {action.label}\n </button>\n ))}\n </div>\n </div>\n </>,\n document.body\n )}\n </div>\n );\n});\n\n// ============================================================================\n// Action Button\n// ============================================================================\n\ninterface ActionButtonProps {\n action: WidgetAction;\n context: ActionContext;\n onAction: (action: WidgetAction) => void;\n disabled?: boolean;\n size: 'sm' | 'md' | 'lg';\n showLabel?: boolean;\n}\n\nconst ActionButton: React.FC<ActionButtonProps> = memo(function ActionButton({\n action,\n context: _context,\n onAction,\n disabled,\n size,\n showLabel = true,\n}) {\n const isDisabled = disabled || action.disabled;\n\n const handleClick = useCallback(() => {\n if (!isDisabled) {\n onAction(action);\n }\n }, [action, isDisabled, onAction]);\n\n // Get both classes and inline styles for guaranteed visibility\n const buttonClasses = getButtonClasses(action.style, size, isDisabled);\n const buttonInlineStyles = getButtonInlineStyles(action.style);\n\n // Handle LINK type\n if (action.type === 'LINK' && action.metadata?.url) {\n return (\n <a\n href={action.metadata.url as string}\n target={(action.metadata.target as string) || '_blank'}\n rel=\"noopener noreferrer\"\n className={buttonClasses}\n style={buttonInlineStyles}\n aria-disabled={isDisabled}\n >\n {action.icon && <ActionIcon name={action.icon} className=\"w-4 h-4 mr-1.5\" />}\n {showLabel && action.label}\n {!action.icon && <ActionIcon name=\"external-link\" className=\"w-4 h-4 ml-1.5\" />}\n </a>\n );\n }\n\n return (\n <button\n type={action.type === 'SUBMIT' ? 'submit' : 'button'}\n onClick={handleClick}\n disabled={isDisabled}\n className={buttonClasses}\n style={buttonInlineStyles}\n >\n {action.icon && <ActionIcon name={action.icon} className=\"w-4 h-4 mr-1.5\" />}\n {showLabel && action.label}\n </button>\n );\n});\n\n// ============================================================================\n// Main Component\n// ============================================================================\n\nexport const WidgetActions: React.FC<WidgetActionsProps> = memo(function WidgetActions({\n actions,\n context,\n onAction,\n disabled = false,\n layout = 'horizontal',\n size = 'md',\n showLabels = true,\n maxVisible = 3,\n className = '',\n}) {\n const [pendingAction, setPendingAction] = useState<WidgetAction | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n\n // Filter visible actions (not hidden)\n const visibleActions = useMemo(() => {\n return actions.filter((a) => !a.hidden).sort((a, b) => a.order - b.order);\n }, [actions]);\n\n // Split into main and overflow actions\n const { mainActions, overflowActions } = useMemo(() => {\n if (visibleActions.length <= maxVisible) {\n return { mainActions: visibleActions, overflowActions: [] };\n }\n return {\n mainActions: visibleActions.slice(0, maxVisible - 1),\n overflowActions: visibleActions.slice(maxVisible - 1),\n };\n }, [visibleActions, maxVisible]);\n\n // Execute action\n const executeAction = useCallback(\n async (action: WidgetAction) => {\n if (!onAction) return;\n\n setIsLoading(true);\n try {\n await onAction(action, context);\n } catch (error) {\n } finally {\n setIsLoading(false);\n }\n },\n [onAction, context]\n );\n\n // Handle action trigger\n const handleTriggerAction = useCallback(\n (action: WidgetAction) => {\n // If action has confirmation, show dialog\n if (action.confirmation) {\n setPendingAction(action);\n return;\n }\n\n // Execute action immediately\n executeAction(action);\n },\n [executeAction]\n );\n\n // Handle confirmation\n const handleConfirm = useCallback(() => {\n if (pendingAction) {\n executeAction(pendingAction);\n setPendingAction(null);\n }\n }, [pendingAction, executeAction]);\n\n const handleCancel = useCallback(() => {\n setPendingAction(null);\n }, []);\n\n // No actions to render\n if (visibleActions.length === 0) {\n return null;\n }\n\n const layoutClasses = layout === 'horizontal' ? 'flex flex-row flex-wrap gap-2' : 'flex flex-col gap-2';\n\n return (\n <>\n <div className={`${layoutClasses} ${className}`}>\n {mainActions.map((action) => (\n <ActionButton\n key={action.id}\n action={action}\n context={context}\n onAction={handleTriggerAction}\n disabled={disabled || isLoading}\n size={size}\n showLabel={showLabels}\n />\n ))}\n\n {overflowActions.length > 0 && (\n <OverflowMenu\n actions={overflowActions}\n context={context}\n onAction={handleTriggerAction}\n disabled={disabled || isLoading}\n size={size}\n />\n )}\n </div>\n\n {/* Confirmation Dialog */}\n {pendingAction?.confirmation && (\n <ConfirmationDialog\n title={pendingAction.confirmation.title || 'Confirm Action'}\n message={pendingAction.confirmation.message || 'Are you sure you want to proceed?'}\n confirmLabel={pendingAction.confirmation.confirmLabel || 'OK'}\n cancelLabel={pendingAction.confirmation.cancelLabel || 'Cancel'}\n style={pendingAction.style}\n onConfirm={handleConfirm}\n onCancel={handleCancel}\n />\n )}\n </>\n );\n});\n\nexport default WidgetActions;\n"],"mappings":"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"}
@@ -115,7 +115,7 @@ var o = ({ className: e }) => /* @__PURE__ */ r("svg", {
115
115
  }), p && /* @__PURE__ */ r("button", {
116
116
  type: "button",
117
117
  onClick: v,
118
- className: "\n p-1 rounded-md\n text-text-secondary\n hover:text-state-error\n hover:bg-state-error/10\n transition-colors\n ",
118
+ className: "\n p-1 rounded-md\n text-text-secondary\n hover:text-status-error-text\n hover:bg-status-error-bg/10\n transition-colors\n ",
119
119
  title: "Delete Workflow",
120
120
  children: /* @__PURE__ */ r(c, { className: "w-4 h-4" })
121
121
  })]
@@ -1 +1 @@
1
- {"version":3,"file":"WorkflowCard.js","names":[],"sources":["../../../../src/bigconsole/components/workflow/WorkflowCard.tsx"],"sourcesContent":["/**\n * WorkflowCard Component\n *\n * Card component displaying a FluidGrids Workflow summary.\n * Shows name, status, linked DataSinks count, and execution stats.\n */\n\nimport { memo, useCallback } from 'react';\nimport { formatDistanceToNow } from 'date-fns';\nimport { WorkflowStatusBadge } from './WorkflowStatusBadge';\nimport type { FluidGridsWorkflow } from '../../types';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface WorkflowCardProps {\n workflow: FluidGridsWorkflow;\n onView?: (id: string) => void;\n onEdit?: (id: string) => void;\n onDelete?: (id: string) => void;\n}\n\n// ============================================================================\n// ICONS\n// ============================================================================\n\nconst WorkflowIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5} d=\"M13 10V3L4 14h7v7l9-11h-7z\" />\n </svg>\n);\n\nconst EditIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z\"\n />\n </svg>\n);\n\nconst DeleteIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n />\n </svg>\n);\n\nconst DataSinkIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4\"\n />\n </svg>\n);\n\nconst PlayIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z\"\n />\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n);\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const WorkflowCard = memo(function WorkflowCard({ workflow, onView, onEdit, onDelete }: WorkflowCardProps) {\n // Calculate linked DataSinks count\n const linkedDataSinkCount = workflow.dataSinkLinks?.length ?? workflow.linkedDataSinkCount ?? 0;\n\n // Format last executed time\n const formatLastExecuted = useCallback((dateStr: string | null): string => {\n if (!dateStr) return 'Never';\n try {\n const date = new Date(dateStr);\n return formatDistanceToNow(date, { addSuffix: true });\n } catch {\n return 'Unknown';\n }\n }, []);\n\n // Event handlers\n const handleCardClick = useCallback(() => {\n onView?.(workflow.id);\n }, [onView, workflow.id]);\n\n const handleEditClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onEdit?.(workflow.id);\n },\n [onEdit, workflow.id]\n );\n\n const handleDeleteClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onDelete?.(workflow.id);\n },\n [onDelete, workflow.id]\n );\n\n return (\n <div\n onClick={handleCardClick}\n className=\"\n bg-bg-surface\n border border-border-default\n rounded-lg\n overflow-hidden\n cursor-pointer\n hover:border-action-primary-bg\n transition-colors\n \"\n >\n {/* Header with Icon */}\n <div className=\"h-24 bg-bg-sunken flex items-center justify-center relative\">\n <WorkflowIcon className=\"w-10 h-10 text-text-secondary/50\" />\n <div className=\"absolute top-2 right-2\">\n <WorkflowStatusBadge status={workflow.status} size=\"sm\" />\n </div>\n </div>\n\n {/* Content */}\n <div className=\"p-4\">\n {/* Title and Actions */}\n <div className=\"flex items-start justify-between mb-2\">\n <div className=\"flex-1 min-w-0\">\n <h3 className=\"text-sm font-semibold text-text-primary truncate\">{workflow.name}</h3>\n <p className=\"text-xs text-text-secondary truncate mt-0.5\">{workflow.key}</p>\n </div>\n\n <div className=\"flex items-center gap-1 ml-2\">\n {onEdit && (\n <button\n type=\"button\"\n onClick={handleEditClick}\n className=\"\n p-1 rounded-md\n text-text-secondary\n hover:text-text-primary\n hover:bg-bg-sunken\n transition-colors\n \"\n title=\"Edit Workflow\"\n >\n <EditIcon className=\"w-4 h-4\" />\n </button>\n )}\n {onDelete && (\n <button\n type=\"button\"\n onClick={handleDeleteClick}\n className=\"\n p-1 rounded-md\n text-text-secondary\n hover:text-state-error\n hover:bg-state-error/10\n transition-colors\n \"\n title=\"Delete Workflow\"\n >\n <DeleteIcon className=\"w-4 h-4\" />\n </button>\n )}\n </div>\n </div>\n\n {/* Description */}\n {workflow.description && (\n <p className=\"text-xs text-text-secondary mb-3 line-clamp-2\">{workflow.description}</p>\n )}\n\n {/* Stats Footer */}\n <div className=\"flex items-center justify-between text-xs text-text-secondary\">\n <div className=\"flex items-center gap-3\">\n {/* DataSinks Count */}\n <span className=\"flex items-center gap-1\" title={`${linkedDataSinkCount} linked DataSinks`}>\n <DataSinkIcon className=\"w-3.5 h-3.5\" />\n {linkedDataSinkCount} DataSink{linkedDataSinkCount !== 1 ? 's' : ''}\n </span>\n\n {/* Execution Count */}\n <span className=\"flex items-center gap-1\" title={`${workflow.executionCount} executions`}>\n <PlayIcon className=\"w-3.5 h-3.5\" />\n {workflow.executionCount}\n </span>\n </div>\n\n {/* Last Executed */}\n <span\n title={\n workflow.lastExecutedAt\n ? `Last executed: ${new Date(workflow.lastExecutedAt).toLocaleString()}`\n : 'Never executed'\n }\n >\n {formatLastExecuted(workflow.lastExecutedAt)}\n </span>\n </div>\n </div>\n </div>\n );\n});\n\nexport default WorkflowCard;\n"],"mappings":"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"}
1
+ {"version":3,"file":"WorkflowCard.js","names":[],"sources":["../../../../src/bigconsole/components/workflow/WorkflowCard.tsx"],"sourcesContent":["/**\n * WorkflowCard Component\n *\n * Card component displaying a FluidGrids Workflow summary.\n * Shows name, status, linked DataSinks count, and execution stats.\n */\n\nimport { memo, useCallback } from 'react';\nimport { formatDistanceToNow } from 'date-fns';\nimport { WorkflowStatusBadge } from './WorkflowStatusBadge';\nimport type { FluidGridsWorkflow } from '../../types';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface WorkflowCardProps {\n workflow: FluidGridsWorkflow;\n onView?: (id: string) => void;\n onEdit?: (id: string) => void;\n onDelete?: (id: string) => void;\n}\n\n// ============================================================================\n// ICONS\n// ============================================================================\n\nconst WorkflowIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5} d=\"M13 10V3L4 14h7v7l9-11h-7z\" />\n </svg>\n);\n\nconst EditIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z\"\n />\n </svg>\n);\n\nconst DeleteIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n />\n </svg>\n);\n\nconst DataSinkIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4\"\n />\n </svg>\n);\n\nconst PlayIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z\"\n />\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n);\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const WorkflowCard = memo(function WorkflowCard({ workflow, onView, onEdit, onDelete }: WorkflowCardProps) {\n // Calculate linked DataSinks count\n const linkedDataSinkCount = workflow.dataSinkLinks?.length ?? workflow.linkedDataSinkCount ?? 0;\n\n // Format last executed time\n const formatLastExecuted = useCallback((dateStr: string | null): string => {\n if (!dateStr) return 'Never';\n try {\n const date = new Date(dateStr);\n return formatDistanceToNow(date, { addSuffix: true });\n } catch {\n return 'Unknown';\n }\n }, []);\n\n // Event handlers\n const handleCardClick = useCallback(() => {\n onView?.(workflow.id);\n }, [onView, workflow.id]);\n\n const handleEditClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onEdit?.(workflow.id);\n },\n [onEdit, workflow.id]\n );\n\n const handleDeleteClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onDelete?.(workflow.id);\n },\n [onDelete, workflow.id]\n );\n\n return (\n <div\n onClick={handleCardClick}\n className=\"\n bg-bg-surface\n border border-border-default\n rounded-lg\n overflow-hidden\n cursor-pointer\n hover:border-action-primary-bg\n transition-colors\n \"\n >\n {/* Header with Icon */}\n <div className=\"h-24 bg-bg-sunken flex items-center justify-center relative\">\n <WorkflowIcon className=\"w-10 h-10 text-text-secondary/50\" />\n <div className=\"absolute top-2 right-2\">\n <WorkflowStatusBadge status={workflow.status} size=\"sm\" />\n </div>\n </div>\n\n {/* Content */}\n <div className=\"p-4\">\n {/* Title and Actions */}\n <div className=\"flex items-start justify-between mb-2\">\n <div className=\"flex-1 min-w-0\">\n <h3 className=\"text-sm font-semibold text-text-primary truncate\">{workflow.name}</h3>\n <p className=\"text-xs text-text-secondary truncate mt-0.5\">{workflow.key}</p>\n </div>\n\n <div className=\"flex items-center gap-1 ml-2\">\n {onEdit && (\n <button\n type=\"button\"\n onClick={handleEditClick}\n className=\"\n p-1 rounded-md\n text-text-secondary\n hover:text-text-primary\n hover:bg-bg-sunken\n transition-colors\n \"\n title=\"Edit Workflow\"\n >\n <EditIcon className=\"w-4 h-4\" />\n </button>\n )}\n {onDelete && (\n <button\n type=\"button\"\n onClick={handleDeleteClick}\n className=\"\n p-1 rounded-md\n text-text-secondary\n hover:text-status-error-text\n hover:bg-status-error-bg/10\n transition-colors\n \"\n title=\"Delete Workflow\"\n >\n <DeleteIcon className=\"w-4 h-4\" />\n </button>\n )}\n </div>\n </div>\n\n {/* Description */}\n {workflow.description && (\n <p className=\"text-xs text-text-secondary mb-3 line-clamp-2\">{workflow.description}</p>\n )}\n\n {/* Stats Footer */}\n <div className=\"flex items-center justify-between text-xs text-text-secondary\">\n <div className=\"flex items-center gap-3\">\n {/* DataSinks Count */}\n <span className=\"flex items-center gap-1\" title={`${linkedDataSinkCount} linked DataSinks`}>\n <DataSinkIcon className=\"w-3.5 h-3.5\" />\n {linkedDataSinkCount} DataSink{linkedDataSinkCount !== 1 ? 's' : ''}\n </span>\n\n {/* Execution Count */}\n <span className=\"flex items-center gap-1\" title={`${workflow.executionCount} executions`}>\n <PlayIcon className=\"w-3.5 h-3.5\" />\n {workflow.executionCount}\n </span>\n </div>\n\n {/* Last Executed */}\n <span\n title={\n workflow.lastExecutedAt\n ? `Last executed: ${new Date(workflow.lastExecutedAt).toLocaleString()}`\n : 'Never executed'\n }\n >\n {formatLastExecuted(workflow.lastExecutedAt)}\n </span>\n </div>\n </div>\n </div>\n );\n});\n\nexport default WorkflowCard;\n"],"mappings":"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"}
@@ -29,8 +29,8 @@ var i = ({ className: e }) => /* @__PURE__ */ n("svg", {
29
29
  /* @__PURE__ */ r("div", {
30
30
  className: "flex items-center gap-3 mb-4",
31
31
  children: [/* @__PURE__ */ n("div", {
32
- className: "p-2 rounded-full bg-state-error/10",
33
- children: /* @__PURE__ */ n(i, { className: "w-6 h-6 text-state-error" })
32
+ className: "p-2 rounded-full bg-status-error-bg/10",
33
+ children: /* @__PURE__ */ n(i, { className: "w-6 h-6 text-status-error-text" })
34
34
  }), /* @__PURE__ */ n("h2", {
35
35
  className: "text-lg font-semibold text-text-primary",
36
36
  children: "Delete Workflow"
@@ -52,9 +52,9 @@ var i = ({ className: e }) => /* @__PURE__ */ n("svg", {
52
52
  ]
53
53
  }),
54
54
  c > 0 && /* @__PURE__ */ n("div", {
55
- className: "p-3 bg-state-warning/10 rounded-md",
55
+ className: "p-3 bg-status-warning-bg/10 rounded-md",
56
56
  children: /* @__PURE__ */ r("p", {
57
- className: "text-sm text-state-warning",
57
+ className: "text-sm text-status-warning-text",
58
58
  children: [
59
59
  "This workflow has ",
60
60
  c,
@@ -80,7 +80,7 @@ var i = ({ className: e }) => /* @__PURE__ */ n("svg", {
80
80
  }), /* @__PURE__ */ n("button", {
81
81
  type: "button",
82
82
  onClick: u,
83
- className: "\n px-4 py-2\n text-sm font-medium\n text-white\n bg-state-error\n hover:bg-state-error/90\n rounded-md\n transition-colors\n ",
83
+ className: "\n px-4 py-2\n text-sm font-medium\n text-white\n bg-status-error-bg\n hover:bg-status-error-bg/90\n rounded-md\n transition-colors\n ",
84
84
  children: "Delete Workflow"
85
85
  })]
86
86
  })
@@ -1 +1 @@
1
- {"version":3,"file":"WorkflowDeleteDialog.js","names":[],"sources":["../../../../src/bigconsole/components/workflow/WorkflowDeleteDialog.tsx"],"sourcesContent":["/**\n * WorkflowDeleteDialog Component\n *\n * Confirmation dialog for deleting a FluidGrids Workflow.\n * Shows warning about linked DataSinks before deletion.\n */\n\nimport { memo, useCallback } from 'react';\nimport type { FluidGridsWorkflow } from '../../types';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface WorkflowDeleteDialogProps {\n workflow: FluidGridsWorkflow;\n isOpen: boolean;\n onClose: () => void;\n onConfirm: () => void | Promise<void>;\n}\n\n// ============================================================================\n// ICONS\n// ============================================================================\n\nconst WarningIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n);\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const WorkflowDeleteDialog = memo(function WorkflowDeleteDialog({\n workflow,\n isOpen,\n onClose,\n onConfirm,\n}: WorkflowDeleteDialogProps) {\n // Calculate linked DataSinks count\n const linkedDataSinkCount = workflow.dataSinkLinks?.length ?? workflow.linkedDataSinkCount ?? 0;\n\n // Event handlers\n const handleBackdropClick = useCallback(() => {\n onClose();\n }, [onClose]);\n\n const handleConfirmClick = useCallback(() => {\n onConfirm();\n }, [onConfirm]);\n\n // Don't render if not open\n if (!isOpen) {\n return null;\n }\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n {/* Backdrop */}\n <div className=\"absolute inset-0 bg-black/50\" onClick={handleBackdropClick} />\n\n {/* Dialog */}\n <div className=\"relative bg-bg-surface rounded-lg shadow-xl max-w-md w-full mx-4 p-6\">\n {/* Header */}\n <div className=\"flex items-center gap-3 mb-4\">\n <div className=\"p-2 rounded-full bg-state-error/10\">\n <WarningIcon className=\"w-6 h-6 text-state-error\" />\n </div>\n <h2 className=\"text-lg font-semibold text-text-primary\">Delete Workflow</h2>\n </div>\n\n {/* Content */}\n <div className=\"mb-6\">\n <p className=\"text-sm text-text-secondary mb-3\">\n Are you sure you want to delete the workflow{' '}\n <span className=\"font-medium text-text-primary\">{workflow.name}</span>?\n </p>\n\n {/* Warning about linked DataSinks */}\n {linkedDataSinkCount > 0 && (\n <div className=\"p-3 bg-state-warning/10 rounded-md\">\n <p className=\"text-sm text-state-warning\">\n This workflow has {linkedDataSinkCount} linked DataSink\n {linkedDataSinkCount !== 1 ? 's' : ''}. Deleting this workflow will remove the links, but the DataSinks\n will not be deleted.\n </p>\n </div>\n )}\n\n <p className=\"text-sm text-text-secondary mt-3\">This action cannot be undone.</p>\n </div>\n\n {/* Actions */}\n <div className=\"flex justify-end gap-3\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"\n px-4 py-2\n text-sm font-medium\n text-text-primary\n bg-bg-sunken\n hover:bg-border-default\n rounded-md\n transition-colors\n \"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleConfirmClick}\n className=\"\n px-4 py-2\n text-sm font-medium\n text-white\n bg-state-error\n hover:bg-state-error/90\n rounded-md\n transition-colors\n \"\n >\n Delete Workflow\n </button>\n </div>\n </div>\n </div>\n );\n});\n\nexport default WorkflowDeleteDialog;\n"],"mappings":";;;AAyBA,IAAM,KAAe,EAAE,mBACrB,kBAAC,OAAD;CAAgB;CAAW,MAAK;CAAO,QAAO;CAAe,SAAQ;WACnE,kBAAC,QAAD;EACE,eAAc;EACd,gBAAe;EACf,aAAa;EACb,GAAE;EACF,CAAA;CACE,CAAA,EAOK,IAAuB,EAAK,SAA8B,EACrE,aACA,WACA,YACA,gBAC4B;CAE5B,IAAM,IAAsB,EAAS,eAAe,UAAU,EAAS,uBAAuB,GAGxF,IAAsB,QAAkB;AAC5C,KAAS;IACR,CAAC,EAAQ,CAAC,EAEP,IAAqB,QAAkB;AAC3C,KAAW;IACV,CAAC,EAAU,CAAC;AAOf,QAJK,IAKH,kBAAC,OAAD;EAAK,WAAU;YAAf,CAEE,kBAAC,OAAD;GAAK,WAAU;GAA+B,SAAS;GAAuB,CAAA,EAG9E,kBAAC,OAAD;GAAK,WAAU;aAAf;IAEE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,GAAD,EAAa,WAAU,4BAA6B,CAAA;MAChD,CAAA,EACN,kBAAC,MAAD;MAAI,WAAU;gBAA0C;MAAoB,CAAA,CACxE;;IAGN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,KAAD;OAAG,WAAU;iBAAb;QAAgD;QACD;QAC7C,kBAAC,QAAD;SAAM,WAAU;mBAAiC,EAAS;SAAY,CAAA;;QACpE;;MAGH,IAAsB,KACrB,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,KAAD;QAAG,WAAU;kBAAb;SAA0C;SACrB;SAAoB;SACtC,MAAwB,IAAU,KAAN;SAAS;SAEpC;;OACA,CAAA;MAGR,kBAAC,KAAD;OAAG,WAAU;iBAAmC;OAAiC,CAAA;MAC7E;;IAGN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,WAAU;gBASX;MAEQ,CAAA,EACT,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,WAAU;gBASX;MAEQ,CAAA,CACL;;IACF;KACF;MAzEC;EA2ET"}
1
+ {"version":3,"file":"WorkflowDeleteDialog.js","names":[],"sources":["../../../../src/bigconsole/components/workflow/WorkflowDeleteDialog.tsx"],"sourcesContent":["/**\n * WorkflowDeleteDialog Component\n *\n * Confirmation dialog for deleting a FluidGrids Workflow.\n * Shows warning about linked DataSinks before deletion.\n */\n\nimport { memo, useCallback } from 'react';\nimport type { FluidGridsWorkflow } from '../../types';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface WorkflowDeleteDialogProps {\n workflow: FluidGridsWorkflow;\n isOpen: boolean;\n onClose: () => void;\n onConfirm: () => void | Promise<void>;\n}\n\n// ============================================================================\n// ICONS\n// ============================================================================\n\nconst WarningIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n);\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const WorkflowDeleteDialog = memo(function WorkflowDeleteDialog({\n workflow,\n isOpen,\n onClose,\n onConfirm,\n}: WorkflowDeleteDialogProps) {\n // Calculate linked DataSinks count\n const linkedDataSinkCount = workflow.dataSinkLinks?.length ?? workflow.linkedDataSinkCount ?? 0;\n\n // Event handlers\n const handleBackdropClick = useCallback(() => {\n onClose();\n }, [onClose]);\n\n const handleConfirmClick = useCallback(() => {\n onConfirm();\n }, [onConfirm]);\n\n // Don't render if not open\n if (!isOpen) {\n return null;\n }\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n {/* Backdrop */}\n <div className=\"absolute inset-0 bg-black/50\" onClick={handleBackdropClick} />\n\n {/* Dialog */}\n <div className=\"relative bg-bg-surface rounded-lg shadow-xl max-w-md w-full mx-4 p-6\">\n {/* Header */}\n <div className=\"flex items-center gap-3 mb-4\">\n <div className=\"p-2 rounded-full bg-status-error-bg/10\">\n <WarningIcon className=\"w-6 h-6 text-status-error-text\" />\n </div>\n <h2 className=\"text-lg font-semibold text-text-primary\">Delete Workflow</h2>\n </div>\n\n {/* Content */}\n <div className=\"mb-6\">\n <p className=\"text-sm text-text-secondary mb-3\">\n Are you sure you want to delete the workflow{' '}\n <span className=\"font-medium text-text-primary\">{workflow.name}</span>?\n </p>\n\n {/* Warning about linked DataSinks */}\n {linkedDataSinkCount > 0 && (\n <div className=\"p-3 bg-status-warning-bg/10 rounded-md\">\n <p className=\"text-sm text-status-warning-text\">\n This workflow has {linkedDataSinkCount} linked DataSink\n {linkedDataSinkCount !== 1 ? 's' : ''}. Deleting this workflow will remove the links, but the DataSinks\n will not be deleted.\n </p>\n </div>\n )}\n\n <p className=\"text-sm text-text-secondary mt-3\">This action cannot be undone.</p>\n </div>\n\n {/* Actions */}\n <div className=\"flex justify-end gap-3\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"\n px-4 py-2\n text-sm font-medium\n text-text-primary\n bg-bg-sunken\n hover:bg-border-default\n rounded-md\n transition-colors\n \"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleConfirmClick}\n className=\"\n px-4 py-2\n text-sm font-medium\n text-white\n bg-status-error-bg\n hover:bg-status-error-bg/90\n rounded-md\n transition-colors\n \"\n >\n Delete Workflow\n </button>\n </div>\n </div>\n </div>\n );\n});\n\nexport default WorkflowDeleteDialog;\n"],"mappings":";;;AAyBA,IAAM,KAAe,EAAE,mBACrB,kBAAC,OAAD;CAAgB;CAAW,MAAK;CAAO,QAAO;CAAe,SAAQ;WACnE,kBAAC,QAAD;EACE,eAAc;EACd,gBAAe;EACf,aAAa;EACb,GAAE;EACF,CAAA;CACE,CAAA,EAOK,IAAuB,EAAK,SAA8B,EACrE,aACA,WACA,YACA,gBAC4B;CAE5B,IAAM,IAAsB,EAAS,eAAe,UAAU,EAAS,uBAAuB,GAGxF,IAAsB,QAAkB;AAC5C,KAAS;IACR,CAAC,EAAQ,CAAC,EAEP,IAAqB,QAAkB;AAC3C,KAAW;IACV,CAAC,EAAU,CAAC;AAOf,QAJK,IAKH,kBAAC,OAAD;EAAK,WAAU;YAAf,CAEE,kBAAC,OAAD;GAAK,WAAU;GAA+B,SAAS;GAAuB,CAAA,EAG9E,kBAAC,OAAD;GAAK,WAAU;aAAf;IAEE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,GAAD,EAAa,WAAU,kCAAmC,CAAA;MACtD,CAAA,EACN,kBAAC,MAAD;MAAI,WAAU;gBAA0C;MAAoB,CAAA,CACxE;;IAGN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,KAAD;OAAG,WAAU;iBAAb;QAAgD;QACD;QAC7C,kBAAC,QAAD;SAAM,WAAU;mBAAiC,EAAS;SAAY,CAAA;;QACpE;;MAGH,IAAsB,KACrB,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,KAAD;QAAG,WAAU;kBAAb;SAAgD;SAC3B;SAAoB;SACtC,MAAwB,IAAU,KAAN;SAAS;SAEpC;;OACA,CAAA;MAGR,kBAAC,KAAD;OAAG,WAAU;iBAAmC;OAAiC,CAAA;MAC7E;;IAGN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,WAAU;gBASX;MAEQ,CAAA,EACT,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,WAAU;gBASX;MAEQ,CAAA,CACL;;IACF;KACF;MAzEC;EA2ET"}
@@ -29,8 +29,8 @@ var r = e(function({ status: e, size: r = "md", showIcon: i = !0 }) {
29
29
  label: "Draft"
30
30
  },
31
31
  active: {
32
- bg: "bg-state-success/10",
33
- text: "text-state-success",
32
+ bg: "bg-status-success-bg/10",
33
+ text: "text-status-success-text",
34
34
  icon: /* @__PURE__ */ t("svg", {
35
35
  className: o[r],
36
36
  fill: "none",
@@ -46,8 +46,8 @@ var r = e(function({ status: e, size: r = "md", showIcon: i = !0 }) {
46
46
  label: "Active"
47
47
  },
48
48
  paused: {
49
- bg: "bg-state-warning/10",
50
- text: "text-state-warning",
49
+ bg: "bg-status-warning-bg/10",
50
+ text: "text-status-warning-text",
51
51
  icon: /* @__PURE__ */ t("svg", {
52
52
  className: o[r],
53
53
  fill: "none",
@@ -63,8 +63,8 @@ var r = e(function({ status: e, size: r = "md", showIcon: i = !0 }) {
63
63
  label: "Paused"
64
64
  },
65
65
  error: {
66
- bg: "bg-state-error/10",
67
- text: "text-state-error",
66
+ bg: "bg-status-error-bg/10",
67
+ text: "text-status-error-text",
68
68
  icon: /* @__PURE__ */ t("svg", {
69
69
  className: o[r],
70
70
  fill: "none",