@burdenoff/microfe-bigconsole 2026.610.1 → 2026.612.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. package/dist/bigconsole/components/widgets/WidgetRegistry.js +2 -1
  2. package/dist/bigconsole/components/widgets/WidgetRegistry.js.map +1 -1
  3. package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js +4 -4
  4. package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js.map +1 -1
  5. package/dist/bigconsole/components/widgets/form/FormWidget.js +20 -20
  6. package/dist/bigconsole/components/widgets/form/FormWidget.js.map +1 -1
  7. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +1 -1
  8. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js.map +1 -1
  9. package/dist/bigconsole/components/widgets/map-widget/MapWidget.js +2 -2
  10. package/dist/bigconsole/components/widgets/map-widget/MapWidget.js.map +1 -1
  11. package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js +2 -2
  12. package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js.map +1 -1
  13. package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js +37 -37
  14. package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js.map +1 -1
  15. package/dist/bigconsole/hooks/useDashboardOperations.js +92 -70
  16. package/dist/bigconsole/hooks/useDashboardOperations.js.map +1 -1
  17. package/dist/bigconsole/pages/DashboardsPage.js +109 -72
  18. package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
  19. package/dist/bigconsole/pages/InsightsPage.js +783 -395
  20. package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
  21. package/dist/generated/wspace-operations.js +105 -107
  22. package/dist/generated/wspace-operations.js.map +1 -1
  23. package/package.json +1 -1
@@ -567,7 +567,8 @@ var e = {
567
567
  xAxisField: "",
568
568
  yAxisField: "",
569
569
  valueField: "",
570
- colorScale: ["#f0f9ff", "#0369a1"],
570
+ colorScale: [],
571
+ colorScheme: "blue",
571
572
  showValues: !0
572
573
  },
573
574
  defaultSize: {
@@ -1 +1 @@
1
- {"version":3,"file":"WidgetRegistry.js","names":[],"sources":["../../../../src/bigconsole/components/widgets/WidgetRegistry.ts"],"sourcesContent":["/**\n * Widget Registry\n *\n * Central registry mapping widget types to their components,\n * metadata, and configuration schemas.\n */\n\nimport type { ComponentType } from 'react';\nimport type { WidgetType, WidgetCategory, Widget } from '../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface WidgetComponentProps {\n /** The widget data */\n widget: Widget;\n /** Widget data (processed) */\n data: Record<string, unknown>;\n /** Whether the widget is in edit mode */\n isEditMode?: boolean;\n /** Whether the widget is selected */\n isSelected?: boolean;\n /** Whether data is loading */\n isLoading?: boolean;\n /** Error message if any */\n error?: string | null;\n /** Callback when widget is clicked */\n onClick?: () => void;\n /** Callback for drilldown navigation */\n onDrilldown?: (params: Record<string, unknown>) => void;\n}\n\nexport interface WidgetDefinition {\n /** Widget type */\n type: WidgetType;\n /** Human-readable name */\n name: string;\n /** Description */\n description: string;\n /** Lucide icon name */\n icon: string;\n /** Category for grouping */\n category: WidgetCategory;\n /** Component to render. Null for all current widget types because the render path\n * uses WidgetRendererFactory + RendererRegistry instead of this field. */\n component: ComponentType<WidgetComponentProps> | null;\n /** Default configuration */\n defaultConfig: Record<string, unknown>;\n /** Default size (fixed grid) */\n defaultSize: { width: number; height: number };\n /** Default responsive position (v1.0 spec) */\n defaultResponsive: { xs: number; sm: number; md: number; lg: number };\n /** Minimum size constraints */\n minSize: { width: number; height: number };\n /** Maximum size constraints */\n maxSize: { width: number; height: number };\n /** Whether the widget supports data binding */\n supportsDataBinding: boolean;\n /** Whether the widget supports drilldown */\n supportsDrilldown: boolean;\n /** Whether the widget supports auto-refresh */\n supportsAutoRefresh: boolean;\n /** Tags for search/filter */\n tags: string[];\n}\n\n// ============================================================================\n// Widget Definitions\n// ============================================================================\n\nexport const WIDGET_DEFINITIONS: Record<WidgetType, WidgetDefinition> = {\n // ============================================================================\n // Core Visualization (6 types)\n // ============================================================================\n\n kpi_card_comparison: {\n type: 'kpi_card_comparison',\n name: 'KPI Card Comparison',\n description: 'Compare multiple KPIs side by side with trends',\n icon: 'LayoutDashboard',\n category: 'KPI',\n component: null,\n defaultConfig: {\n comparisons: [],\n showSparklines: true,\n layout: 'horizontal',\n format: 'number',\n },\n defaultSize: { width: 6, height: 3 },\n defaultResponsive: { xs: 12, sm: 6, md: 6, lg: 4 },\n minSize: { width: 4, height: 2 },\n maxSize: { width: 12, height: 6 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['kpi', 'comparison', 'metrics', 'multi'],\n },\n\n metric_card: {\n type: 'metric_card',\n name: 'Metric Card',\n description: 'Display a single KPI value with trend indicator',\n icon: 'TrendingUp',\n category: 'KPI',\n component: null,\n defaultConfig: {\n format: 'number',\n decimalPlaces: 0,\n showTrend: true,\n showSparkline: false,\n },\n defaultSize: { width: 3, height: 2 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 3 },\n minSize: { width: 2, height: 2 },\n maxSize: { width: 6, height: 4 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['kpi', 'metric', 'number', 'trend'],\n },\n\n chart: {\n type: 'chart',\n name: 'Chart',\n description: 'Multi-type chart (Line, Bar, Area, Pie)',\n icon: 'BarChart3',\n category: 'Visualization',\n component: null,\n defaultConfig: {\n chartType: 'line',\n showLegend: true,\n legendPosition: 'bottom',\n showGrid: true,\n showTooltip: true,\n },\n defaultSize: { width: 6, height: 4 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 3, height: 3 },\n maxSize: { width: 12, height: 8 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['chart', 'graph', 'visualization', 'line', 'bar', 'area', 'pie'],\n },\n\n funnel_chart: {\n type: 'funnel_chart',\n name: 'Funnel Chart',\n description: 'Visualize conversion or drop-off stages',\n icon: 'Filter',\n category: 'Visualization',\n component: null,\n defaultConfig: {\n showLabels: true,\n showValues: true,\n showPercentages: true,\n orientation: 'vertical',\n },\n defaultSize: { width: 4, height: 5 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 3, height: 4 },\n maxSize: { width: 8, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['funnel', 'conversion', 'stages', 'pipeline'],\n },\n\n table: {\n type: 'table',\n name: 'Data Table',\n description: 'Display data in sortable, filterable rows and columns',\n icon: 'Table',\n category: 'Data',\n component: null,\n defaultConfig: {\n pageSize: 10,\n sortable: true,\n filterable: true,\n stickyHeader: true,\n columns: [],\n },\n defaultSize: { width: 8, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 8, lg: 8 },\n minSize: { width: 4, height: 3 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['table', 'data', 'grid', 'rows'],\n },\n\n pivot_table: {\n type: 'pivot_table',\n name: 'Pivot Table',\n description: 'Interactive pivot table for data analysis',\n icon: 'Grid3x3',\n category: 'Data',\n component: null,\n defaultConfig: {\n rows: [],\n columns: [],\n values: [],\n aggregation: 'sum',\n showTotals: true,\n },\n defaultSize: { width: 10, height: 6 },\n defaultResponsive: { xs: 12, sm: 12, md: 12, lg: 10 },\n minSize: { width: 6, height: 4 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['pivot', 'table', 'analysis', 'aggregation'],\n },\n\n // ============================================================================\n // Indicators (2 types)\n // ============================================================================\n\n gauge: {\n type: 'gauge',\n name: 'Gauge',\n description: 'Display a value within a range',\n icon: 'Gauge',\n category: 'KPI',\n component: null,\n defaultConfig: {\n variant: 'circular',\n min: 0,\n max: 100,\n showValue: true,\n showLabels: true,\n thresholds: [\n { value: 33, color: 'red' },\n { value: 66, color: 'yellow' },\n { value: 100, color: 'green' },\n ],\n },\n defaultSize: { width: 3, height: 3 },\n defaultResponsive: { xs: 6, sm: 4, md: 3, lg: 3 },\n minSize: { width: 2, height: 2 },\n maxSize: { width: 6, height: 6 },\n supportsDataBinding: true,\n supportsDrilldown: false,\n supportsAutoRefresh: true,\n tags: ['gauge', 'meter', 'dial', 'indicator'],\n },\n\n progress: {\n type: 'progress',\n name: 'Progress Bar',\n description: 'Show progress towards a goal with milestones',\n icon: 'Activity',\n category: 'KPI',\n component: null,\n defaultConfig: {\n showPercentage: true,\n showValue: false,\n target: null,\n milestones: [],\n },\n defaultSize: { width: 4, height: 2 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 3, height: 2 },\n maxSize: { width: 12, height: 3 },\n supportsDataBinding: true,\n supportsDrilldown: false,\n supportsAutoRefresh: true,\n tags: ['progress', 'bar', 'goal', 'completion'],\n },\n\n // ============================================================================\n // Data Display (2 types)\n // ============================================================================\n\n list: {\n type: 'list',\n name: 'List',\n description: 'Display items in a scrollable list',\n icon: 'List',\n category: 'Data',\n component: null,\n defaultConfig: {\n showMetadata: true,\n showActions: false,\n showBadges: true,\n maxItems: 10,\n itemClickable: true,\n },\n defaultSize: { width: 4, height: 5 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 3, height: 3 },\n maxSize: { width: 8, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['list', 'items', 'scroll'],\n },\n\n form: {\n type: 'form',\n name: 'Form',\n description: 'Interactive form widget for data input',\n icon: 'FileText',\n category: 'Data',\n component: null,\n defaultConfig: {\n fields: [],\n submitAction: null,\n layout: 'vertical',\n showLabels: true,\n },\n defaultSize: { width: 6, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 4, height: 3 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: false,\n supportsAutoRefresh: false,\n tags: ['form', 'input', 'submit', 'fields'],\n },\n\n // ============================================================================\n // Content (2 types)\n // ============================================================================\n\n text: {\n type: 'text',\n name: 'Text',\n description: 'Rich text or markdown content widget',\n icon: 'Type',\n category: 'Content',\n component: null,\n defaultConfig: {\n content: '',\n format: 'markdown',\n alignment: 'left',\n },\n defaultSize: { width: 4, height: 3 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 2, height: 1 },\n maxSize: { width: 12, height: 12 },\n supportsDataBinding: false,\n supportsDrilldown: false,\n supportsAutoRefresh: false,\n tags: ['text', 'markdown', 'content', 'rich text'],\n },\n\n iframe: {\n type: 'iframe',\n name: 'Iframe',\n description: 'Embed external content via iframe',\n icon: 'ExternalLink',\n category: 'Content',\n component: null,\n defaultConfig: {\n url: '',\n sandbox: 'allow-scripts allow-same-origin',\n allowFullscreen: false,\n },\n defaultSize: { width: 6, height: 4 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 3, height: 2 },\n maxSize: { width: 12, height: 12 },\n supportsDataBinding: false,\n supportsDrilldown: false,\n supportsAutoRefresh: false,\n tags: ['iframe', 'embed', 'external', 'web'],\n },\n\n // ============================================================================\n // Spatial & Temporal (5 types)\n // ============================================================================\n\n map: {\n type: 'map',\n name: 'Map',\n description: 'Geographic map visualization with markers',\n icon: 'MapPin',\n category: 'Visualization',\n component: null,\n defaultConfig: {\n provider: 'mapbox',\n center: { lat: 0, lng: 0 },\n zoom: 2,\n showMarkers: true,\n showRegions: false,\n },\n defaultSize: { width: 6, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 4, height: 3 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['map', 'geo', 'location', 'markers'],\n },\n\n heatmap: {\n type: 'heatmap',\n name: 'Heatmap',\n description: 'Display values in a color-coded grid',\n icon: 'Grid3x3',\n category: 'Visualization',\n component: null,\n defaultConfig: {\n xAxisField: '',\n yAxisField: '',\n valueField: '',\n colorScale: ['#f0f9ff', '#0369a1'],\n showValues: true,\n },\n defaultSize: { width: 6, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 4, height: 4 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['heatmap', 'grid', 'density', 'color'],\n },\n\n calendar: {\n type: 'calendar',\n name: 'Calendar',\n description: 'Calendar view for events and schedules',\n icon: 'Calendar',\n category: 'Temporal',\n component: null,\n defaultConfig: {\n view: 'month',\n showWeekNumbers: false,\n firstDayOfWeek: 0,\n eventField: '',\n },\n defaultSize: { width: 8, height: 6 },\n defaultResponsive: { xs: 12, sm: 12, md: 8, lg: 8 },\n minSize: { width: 6, height: 4 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['calendar', 'events', 'schedule', 'dates'],\n },\n\n kanban: {\n type: 'kanban',\n name: 'Kanban Board',\n description: 'Kanban board for task and workflow management',\n icon: 'Columns',\n category: 'Data',\n component: null,\n defaultConfig: {\n columns: [],\n cardTitleField: '',\n cardDescriptionField: '',\n columnField: '',\n allowDragDrop: true,\n },\n defaultSize: { width: 12, height: 6 },\n defaultResponsive: { xs: 12, sm: 12, md: 12, lg: 12 },\n minSize: { width: 8, height: 4 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['kanban', 'board', 'tasks', 'workflow'],\n },\n\n timeline: {\n type: 'timeline',\n name: 'Timeline',\n description: 'Timeline or Gantt chart for project scheduling',\n icon: 'GitBranch',\n category: 'Temporal',\n component: null,\n defaultConfig: {\n startDateField: '',\n endDateField: '',\n titleField: '',\n groupField: '',\n showToday: true,\n },\n defaultSize: { width: 12, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 12, lg: 12 },\n minSize: { width: 8, height: 3 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['timeline', 'gantt', 'project', 'schedule'],\n },\n\n // ============================================================================\n // Extensibility (1 type)\n // ============================================================================\n\n custom: {\n type: 'custom',\n name: 'Custom Widget',\n description: 'Custom widget with user-defined rendering',\n icon: 'Puzzle',\n category: 'Custom',\n component: null,\n defaultConfig: {\n componentId: '',\n props: {},\n },\n defaultSize: { width: 4, height: 4 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 2, height: 2 },\n maxSize: { width: 12, height: 12 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['custom', 'plugin', 'extension'],\n },\n};\n\n// ============================================================================\n// Registry Functions\n// ============================================================================\n\n/**\n * Default widget definition for unknown types\n */\nconst DEFAULT_WIDGET_DEFINITION: WidgetDefinition = {\n type: 'custom' as WidgetType,\n name: 'Unknown Widget',\n description: 'Unknown widget type',\n icon: 'Puzzle',\n category: 'Custom',\n component: null,\n defaultConfig: {},\n defaultSize: { width: 4, height: 4 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 2, height: 2 },\n maxSize: { width: 12, height: 12 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['unknown'],\n};\n\n/**\n * Get widget definition by type\n * Handles both lowercase (frontend) and uppercase (backend) types\n */\nexport function getWidgetDefinition(type: WidgetType | string): WidgetDefinition {\n // Try exact match first\n if (WIDGET_DEFINITIONS[type as WidgetType]) {\n return WIDGET_DEFINITIONS[type as WidgetType];\n }\n\n // Try lowercase version (backend returns uppercase for some types)\n const lowerType = type.toLowerCase() as WidgetType;\n if (WIDGET_DEFINITIONS[lowerType]) {\n return WIDGET_DEFINITIONS[lowerType];\n }\n\n // Return default definition for unknown types\n return { ...DEFAULT_WIDGET_DEFINITION, type: type as WidgetType };\n}\n\n/**\n * Get all widget definitions\n */\nexport function getAllWidgetDefinitions(): WidgetDefinition[] {\n return Object.values(WIDGET_DEFINITIONS);\n}\n\n/**\n * Get widget definitions by category\n */\nexport function getWidgetsByCategory(category: WidgetCategory): WidgetDefinition[] {\n return Object.values(WIDGET_DEFINITIONS).filter((def) => def.category === category);\n}\n\n/**\n * Search widget definitions by query\n */\nexport function searchWidgets(query: string): WidgetDefinition[] {\n const lowerQuery = query.toLowerCase();\n return Object.values(WIDGET_DEFINITIONS).filter(\n (def) =>\n def.name.toLowerCase().includes(lowerQuery) ||\n def.description.toLowerCase().includes(lowerQuery) ||\n def.tags.some((tag) => tag.includes(lowerQuery))\n );\n}\n\n/**\n * Canonical mapping from widget category to human-readable label.\n * Shared across WidgetTypeSelector, WidgetPalette, and other UI.\n */\nexport const WIDGET_CATEGORY_LABELS: Record<WidgetCategory, string> = {\n KPI: 'Metrics & KPIs',\n Visualization: 'Charts & Visualization',\n Data: 'Data Display',\n Content: 'Content',\n Temporal: 'Temporal & Scheduling',\n Custom: 'Custom',\n Installed: 'Installed from Store',\n};\n\n/**\n * Get widget categories with their definitions\n */\nexport function getWidgetCategories(): {\n category: WidgetCategory;\n label: string;\n widgets: WidgetDefinition[];\n}[] {\n const categories: WidgetCategory[] = ['KPI', 'Visualization', 'Data', 'Content', 'Temporal', 'Custom', 'Installed'];\n\n return categories.map((category) => ({\n category,\n label: WIDGET_CATEGORY_LABELS[category],\n widgets: getWidgetsByCategory(category),\n }));\n}\n\n/**\n * Validate widget size constraints\n */\nexport function validateWidgetSize(\n type: WidgetType,\n width: number,\n height: number\n): { valid: boolean; width: number; height: number } {\n const def = WIDGET_DEFINITIONS[type];\n\n const clampedWidth = Math.min(Math.max(width, def.minSize.width), def.maxSize.width);\n const clampedHeight = Math.min(Math.max(height, def.minSize.height), def.maxSize.height);\n\n return {\n valid: width === clampedWidth && height === clampedHeight,\n width: clampedWidth,\n height: clampedHeight,\n };\n}\n\n/**\n * Get a stable key for a widget definition (handles installed widgets with componentId)\n */\nexport function getWidgetKey(widget: WidgetDefinition): string {\n if (widget.defaultConfig?.componentId) {\n return `installed-${widget.defaultConfig.componentId}`;\n }\n if (widget.category === 'Installed') {\n return `installed-${widget.name}`;\n }\n return widget.type;\n}\n\nexport default WIDGET_DEFINITIONS;\n"],"mappings":"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"}
1
+ {"version":3,"file":"WidgetRegistry.js","names":[],"sources":["../../../../src/bigconsole/components/widgets/WidgetRegistry.ts"],"sourcesContent":["/**\n * Widget Registry\n *\n * Central registry mapping widget types to their components,\n * metadata, and configuration schemas.\n */\n\nimport type { ComponentType } from 'react';\nimport type { WidgetType, WidgetCategory, Widget } from '../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface WidgetComponentProps {\n /** The widget data */\n widget: Widget;\n /** Widget data (processed) */\n data: Record<string, unknown>;\n /** Whether the widget is in edit mode */\n isEditMode?: boolean;\n /** Whether the widget is selected */\n isSelected?: boolean;\n /** Whether data is loading */\n isLoading?: boolean;\n /** Error message if any */\n error?: string | null;\n /** Callback when widget is clicked */\n onClick?: () => void;\n /** Callback for drilldown navigation */\n onDrilldown?: (params: Record<string, unknown>) => void;\n}\n\nexport interface WidgetDefinition {\n /** Widget type */\n type: WidgetType;\n /** Human-readable name */\n name: string;\n /** Description */\n description: string;\n /** Lucide icon name */\n icon: string;\n /** Category for grouping */\n category: WidgetCategory;\n /** Component to render. Null for all current widget types because the render path\n * uses WidgetRendererFactory + RendererRegistry instead of this field. */\n component: ComponentType<WidgetComponentProps> | null;\n /** Default configuration */\n defaultConfig: Record<string, unknown>;\n /** Default size (fixed grid) */\n defaultSize: { width: number; height: number };\n /** Default responsive position (v1.0 spec) */\n defaultResponsive: { xs: number; sm: number; md: number; lg: number };\n /** Minimum size constraints */\n minSize: { width: number; height: number };\n /** Maximum size constraints */\n maxSize: { width: number; height: number };\n /** Whether the widget supports data binding */\n supportsDataBinding: boolean;\n /** Whether the widget supports drilldown */\n supportsDrilldown: boolean;\n /** Whether the widget supports auto-refresh */\n supportsAutoRefresh: boolean;\n /** Tags for search/filter */\n tags: string[];\n}\n\n// ============================================================================\n// Widget Definitions\n// ============================================================================\n\nexport const WIDGET_DEFINITIONS: Record<WidgetType, WidgetDefinition> = {\n // ============================================================================\n // Core Visualization (6 types)\n // ============================================================================\n\n kpi_card_comparison: {\n type: 'kpi_card_comparison',\n name: 'KPI Card Comparison',\n description: 'Compare multiple KPIs side by side with trends',\n icon: 'LayoutDashboard',\n category: 'KPI',\n component: null,\n defaultConfig: {\n comparisons: [],\n showSparklines: true,\n layout: 'horizontal',\n format: 'number',\n },\n defaultSize: { width: 6, height: 3 },\n defaultResponsive: { xs: 12, sm: 6, md: 6, lg: 4 },\n minSize: { width: 4, height: 2 },\n maxSize: { width: 12, height: 6 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['kpi', 'comparison', 'metrics', 'multi'],\n },\n\n metric_card: {\n type: 'metric_card',\n name: 'Metric Card',\n description: 'Display a single KPI value with trend indicator',\n icon: 'TrendingUp',\n category: 'KPI',\n component: null,\n defaultConfig: {\n format: 'number',\n decimalPlaces: 0,\n showTrend: true,\n showSparkline: false,\n },\n defaultSize: { width: 3, height: 2 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 3 },\n minSize: { width: 2, height: 2 },\n maxSize: { width: 6, height: 4 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['kpi', 'metric', 'number', 'trend'],\n },\n\n chart: {\n type: 'chart',\n name: 'Chart',\n description: 'Multi-type chart (Line, Bar, Area, Pie)',\n icon: 'BarChart3',\n category: 'Visualization',\n component: null,\n defaultConfig: {\n chartType: 'line',\n showLegend: true,\n legendPosition: 'bottom',\n showGrid: true,\n showTooltip: true,\n },\n defaultSize: { width: 6, height: 4 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 3, height: 3 },\n maxSize: { width: 12, height: 8 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['chart', 'graph', 'visualization', 'line', 'bar', 'area', 'pie'],\n },\n\n funnel_chart: {\n type: 'funnel_chart',\n name: 'Funnel Chart',\n description: 'Visualize conversion or drop-off stages',\n icon: 'Filter',\n category: 'Visualization',\n component: null,\n defaultConfig: {\n showLabels: true,\n showValues: true,\n showPercentages: true,\n orientation: 'vertical',\n },\n defaultSize: { width: 4, height: 5 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 3, height: 4 },\n maxSize: { width: 8, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['funnel', 'conversion', 'stages', 'pipeline'],\n },\n\n table: {\n type: 'table',\n name: 'Data Table',\n description: 'Display data in sortable, filterable rows and columns',\n icon: 'Table',\n category: 'Data',\n component: null,\n defaultConfig: {\n pageSize: 10,\n sortable: true,\n filterable: true,\n stickyHeader: true,\n columns: [],\n },\n defaultSize: { width: 8, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 8, lg: 8 },\n minSize: { width: 4, height: 3 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['table', 'data', 'grid', 'rows'],\n },\n\n pivot_table: {\n type: 'pivot_table',\n name: 'Pivot Table',\n description: 'Interactive pivot table for data analysis',\n icon: 'Grid3x3',\n category: 'Data',\n component: null,\n defaultConfig: {\n rows: [],\n columns: [],\n values: [],\n aggregation: 'sum',\n showTotals: true,\n },\n defaultSize: { width: 10, height: 6 },\n defaultResponsive: { xs: 12, sm: 12, md: 12, lg: 10 },\n minSize: { width: 6, height: 4 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['pivot', 'table', 'analysis', 'aggregation'],\n },\n\n // ============================================================================\n // Indicators (2 types)\n // ============================================================================\n\n gauge: {\n type: 'gauge',\n name: 'Gauge',\n description: 'Display a value within a range',\n icon: 'Gauge',\n category: 'KPI',\n component: null,\n defaultConfig: {\n variant: 'circular',\n min: 0,\n max: 100,\n showValue: true,\n showLabels: true,\n thresholds: [\n { value: 33, color: 'red' },\n { value: 66, color: 'yellow' },\n { value: 100, color: 'green' },\n ],\n },\n defaultSize: { width: 3, height: 3 },\n defaultResponsive: { xs: 6, sm: 4, md: 3, lg: 3 },\n minSize: { width: 2, height: 2 },\n maxSize: { width: 6, height: 6 },\n supportsDataBinding: true,\n supportsDrilldown: false,\n supportsAutoRefresh: true,\n tags: ['gauge', 'meter', 'dial', 'indicator'],\n },\n\n progress: {\n type: 'progress',\n name: 'Progress Bar',\n description: 'Show progress towards a goal with milestones',\n icon: 'Activity',\n category: 'KPI',\n component: null,\n defaultConfig: {\n showPercentage: true,\n showValue: false,\n target: null,\n milestones: [],\n },\n defaultSize: { width: 4, height: 2 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 3, height: 2 },\n maxSize: { width: 12, height: 3 },\n supportsDataBinding: true,\n supportsDrilldown: false,\n supportsAutoRefresh: true,\n tags: ['progress', 'bar', 'goal', 'completion'],\n },\n\n // ============================================================================\n // Data Display (2 types)\n // ============================================================================\n\n list: {\n type: 'list',\n name: 'List',\n description: 'Display items in a scrollable list',\n icon: 'List',\n category: 'Data',\n component: null,\n defaultConfig: {\n showMetadata: true,\n showActions: false,\n showBadges: true,\n maxItems: 10,\n itemClickable: true,\n },\n defaultSize: { width: 4, height: 5 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 3, height: 3 },\n maxSize: { width: 8, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['list', 'items', 'scroll'],\n },\n\n form: {\n type: 'form',\n name: 'Form',\n description: 'Interactive form widget for data input',\n icon: 'FileText',\n category: 'Data',\n component: null,\n defaultConfig: {\n fields: [],\n submitAction: null,\n layout: 'vertical',\n showLabels: true,\n },\n defaultSize: { width: 6, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 4, height: 3 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: false,\n supportsAutoRefresh: false,\n tags: ['form', 'input', 'submit', 'fields'],\n },\n\n // ============================================================================\n // Content (2 types)\n // ============================================================================\n\n text: {\n type: 'text',\n name: 'Text',\n description: 'Rich text or markdown content widget',\n icon: 'Type',\n category: 'Content',\n component: null,\n defaultConfig: {\n content: '',\n format: 'markdown',\n alignment: 'left',\n },\n defaultSize: { width: 4, height: 3 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 2, height: 1 },\n maxSize: { width: 12, height: 12 },\n supportsDataBinding: false,\n supportsDrilldown: false,\n supportsAutoRefresh: false,\n tags: ['text', 'markdown', 'content', 'rich text'],\n },\n\n iframe: {\n type: 'iframe',\n name: 'Iframe',\n description: 'Embed external content via iframe',\n icon: 'ExternalLink',\n category: 'Content',\n component: null,\n defaultConfig: {\n url: '',\n sandbox: 'allow-scripts allow-same-origin',\n allowFullscreen: false,\n },\n defaultSize: { width: 6, height: 4 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 3, height: 2 },\n maxSize: { width: 12, height: 12 },\n supportsDataBinding: false,\n supportsDrilldown: false,\n supportsAutoRefresh: false,\n tags: ['iframe', 'embed', 'external', 'web'],\n },\n\n // ============================================================================\n // Spatial & Temporal (5 types)\n // ============================================================================\n\n map: {\n type: 'map',\n name: 'Map',\n description: 'Geographic map visualization with markers',\n icon: 'MapPin',\n category: 'Visualization',\n component: null,\n defaultConfig: {\n provider: 'mapbox',\n center: { lat: 0, lng: 0 },\n zoom: 2,\n showMarkers: true,\n showRegions: false,\n },\n defaultSize: { width: 6, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 4, height: 3 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['map', 'geo', 'location', 'markers'],\n },\n\n heatmap: {\n type: 'heatmap',\n name: 'Heatmap',\n description: 'Display values in a color-coded grid',\n icon: 'Grid3x3',\n category: 'Visualization',\n component: null,\n defaultConfig: {\n xAxisField: '',\n yAxisField: '',\n valueField: '',\n // HeatmapWidget renders intensity from `colorScheme` (token-based Tailwind\n // classes), not `colorScale`; keep the scale empty rather than seeding it\n // with CSS var() strings that a data array can never resolve.\n colorScale: [],\n colorScheme: 'blue',\n showValues: true,\n },\n defaultSize: { width: 6, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 4, height: 4 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['heatmap', 'grid', 'density', 'color'],\n },\n\n calendar: {\n type: 'calendar',\n name: 'Calendar',\n description: 'Calendar view for events and schedules',\n icon: 'Calendar',\n category: 'Temporal',\n component: null,\n defaultConfig: {\n view: 'month',\n showWeekNumbers: false,\n firstDayOfWeek: 0,\n eventField: '',\n },\n defaultSize: { width: 8, height: 6 },\n defaultResponsive: { xs: 12, sm: 12, md: 8, lg: 8 },\n minSize: { width: 6, height: 4 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['calendar', 'events', 'schedule', 'dates'],\n },\n\n kanban: {\n type: 'kanban',\n name: 'Kanban Board',\n description: 'Kanban board for task and workflow management',\n icon: 'Columns',\n category: 'Data',\n component: null,\n defaultConfig: {\n columns: [],\n cardTitleField: '',\n cardDescriptionField: '',\n columnField: '',\n allowDragDrop: true,\n },\n defaultSize: { width: 12, height: 6 },\n defaultResponsive: { xs: 12, sm: 12, md: 12, lg: 12 },\n minSize: { width: 8, height: 4 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['kanban', 'board', 'tasks', 'workflow'],\n },\n\n timeline: {\n type: 'timeline',\n name: 'Timeline',\n description: 'Timeline or Gantt chart for project scheduling',\n icon: 'GitBranch',\n category: 'Temporal',\n component: null,\n defaultConfig: {\n startDateField: '',\n endDateField: '',\n titleField: '',\n groupField: '',\n showToday: true,\n },\n defaultSize: { width: 12, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 12, lg: 12 },\n minSize: { width: 8, height: 3 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['timeline', 'gantt', 'project', 'schedule'],\n },\n\n // ============================================================================\n // Extensibility (1 type)\n // ============================================================================\n\n custom: {\n type: 'custom',\n name: 'Custom Widget',\n description: 'Custom widget with user-defined rendering',\n icon: 'Puzzle',\n category: 'Custom',\n component: null,\n defaultConfig: {\n componentId: '',\n props: {},\n },\n defaultSize: { width: 4, height: 4 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 2, height: 2 },\n maxSize: { width: 12, height: 12 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['custom', 'plugin', 'extension'],\n },\n};\n\n// ============================================================================\n// Registry Functions\n// ============================================================================\n\n/**\n * Default widget definition for unknown types\n */\nconst DEFAULT_WIDGET_DEFINITION: WidgetDefinition = {\n type: 'custom' as WidgetType,\n name: 'Unknown Widget',\n description: 'Unknown widget type',\n icon: 'Puzzle',\n category: 'Custom',\n component: null,\n defaultConfig: {},\n defaultSize: { width: 4, height: 4 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 2, height: 2 },\n maxSize: { width: 12, height: 12 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['unknown'],\n};\n\n/**\n * Get widget definition by type\n * Handles both lowercase (frontend) and uppercase (backend) types\n */\nexport function getWidgetDefinition(type: WidgetType | string): WidgetDefinition {\n // Try exact match first\n if (WIDGET_DEFINITIONS[type as WidgetType]) {\n return WIDGET_DEFINITIONS[type as WidgetType];\n }\n\n // Try lowercase version (backend returns uppercase for some types)\n const lowerType = type.toLowerCase() as WidgetType;\n if (WIDGET_DEFINITIONS[lowerType]) {\n return WIDGET_DEFINITIONS[lowerType];\n }\n\n // Return default definition for unknown types\n return { ...DEFAULT_WIDGET_DEFINITION, type: type as WidgetType };\n}\n\n/**\n * Get all widget definitions\n */\nexport function getAllWidgetDefinitions(): WidgetDefinition[] {\n return Object.values(WIDGET_DEFINITIONS);\n}\n\n/**\n * Get widget definitions by category\n */\nexport function getWidgetsByCategory(category: WidgetCategory): WidgetDefinition[] {\n return Object.values(WIDGET_DEFINITIONS).filter((def) => def.category === category);\n}\n\n/**\n * Search widget definitions by query\n */\nexport function searchWidgets(query: string): WidgetDefinition[] {\n const lowerQuery = query.toLowerCase();\n return Object.values(WIDGET_DEFINITIONS).filter(\n (def) =>\n def.name.toLowerCase().includes(lowerQuery) ||\n def.description.toLowerCase().includes(lowerQuery) ||\n def.tags.some((tag) => tag.includes(lowerQuery))\n );\n}\n\n/**\n * Canonical mapping from widget category to human-readable label.\n * Shared across WidgetTypeSelector, WidgetPalette, and other UI.\n */\nexport const WIDGET_CATEGORY_LABELS: Record<WidgetCategory, string> = {\n KPI: 'Metrics & KPIs',\n Visualization: 'Charts & Visualization',\n Data: 'Data Display',\n Content: 'Content',\n Temporal: 'Temporal & Scheduling',\n Custom: 'Custom',\n Installed: 'Installed from Store',\n};\n\n/**\n * Get widget categories with their definitions\n */\nexport function getWidgetCategories(): {\n category: WidgetCategory;\n label: string;\n widgets: WidgetDefinition[];\n}[] {\n const categories: WidgetCategory[] = ['KPI', 'Visualization', 'Data', 'Content', 'Temporal', 'Custom', 'Installed'];\n\n return categories.map((category) => ({\n category,\n label: WIDGET_CATEGORY_LABELS[category],\n widgets: getWidgetsByCategory(category),\n }));\n}\n\n/**\n * Validate widget size constraints\n */\nexport function validateWidgetSize(\n type: WidgetType,\n width: number,\n height: number\n): { valid: boolean; width: number; height: number } {\n const def = WIDGET_DEFINITIONS[type];\n\n const clampedWidth = Math.min(Math.max(width, def.minSize.width), def.maxSize.width);\n const clampedHeight = Math.min(Math.max(height, def.minSize.height), def.maxSize.height);\n\n return {\n valid: width === clampedWidth && height === clampedHeight,\n width: clampedWidth,\n height: clampedHeight,\n };\n}\n\n/**\n * Get a stable key for a widget definition (handles installed widgets with componentId)\n */\nexport function getWidgetKey(widget: WidgetDefinition): string {\n if (widget.defaultConfig?.componentId) {\n return `installed-${widget.defaultConfig.componentId}`;\n }\n if (widget.category === 'Installed') {\n return `installed-${widget.name}`;\n }\n return widget.type;\n}\n\nexport default WIDGET_DEFINITIONS;\n"],"mappings":"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"}
@@ -167,7 +167,7 @@ var f = i(function({ log: e, onRetry: i, retrying: a, expanded: o, onToggleExpan
167
167
  }), e.actionName && /* @__PURE__ */ l("div", {
168
168
  style: {
169
169
  fontSize: "11px",
170
- color: "#9ca3af"
170
+ color: "var(--color-text-placeholder)"
171
171
  },
172
172
  children: ["Action: ", e.actionName]
173
173
  })]
@@ -184,13 +184,13 @@ var f = i(function({ log: e, onRetry: i, retrying: a, expanded: o, onToggleExpan
184
184
  children: e.webhookUrl ? /* @__PURE__ */ c("span", {
185
185
  style: {
186
186
  fontSize: "12px",
187
- color: "#6b7280"
187
+ color: "var(--color-text-muted)"
188
188
  },
189
189
  children: new URL(e.webhookUrl).hostname
190
190
  }) : /* @__PURE__ */ c("span", {
191
191
  style: {
192
192
  fontSize: "12px",
193
- color: "#d1d5db"
193
+ color: "var(--color-text-placeholder)"
194
194
  },
195
195
  children: "—"
196
196
  })
@@ -218,7 +218,7 @@ var f = i(function({ log: e, onRetry: i, retrying: a, expanded: o, onToggleExpan
218
218
  e.errorMessage && /* @__PURE__ */ l(s, { children: [
219
219
  "\n\n",
220
220
  /* @__PURE__ */ c("strong", {
221
- style: { color: "#dc2626" },
221
+ style: { color: "var(--color-status-error-text)" },
222
222
  children: "Error:"
223
223
  }),
224
224
  "\n",
@@ -1 +1 @@
1
- {"version":3,"file":"EventLogViewer.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/event-logs/EventLogViewer.tsx"],"sourcesContent":["/**\n * EventLogViewer Component (v2.0)\n *\n * Component for viewing event history and managing failed deliveries.\n * Shows event status, allows filtering, and supports retry functionality.\n */\n\nimport React, { memo, useState, useCallback } from 'react';\nimport {\n useEventLogs,\n getEventStatusColor,\n getEventStatusLabel,\n getEventStatusIcon,\n type EventStatus,\n type EventLog,\n} from '../../../hooks/useEventLogs';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface EventLogViewerProps {\n /** Dashboard ID to filter logs */\n dashboardId?: string;\n /** Widget ID to filter logs */\n widgetId?: string;\n /** Maximum height of the viewer */\n maxHeight?: string;\n /** Callback when retry is successful */\n onRetrySuccess?: (eventLog: EventLog) => void;\n}\n\n// ============================================================================\n// Styles\n// ============================================================================\n\nconst styles = {\n container: {\n padding: '16px',\n backgroundColor: 'var(--color-bg-surface)',\n borderRadius: '8px',\n } as React.CSSProperties,\n header: {\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n marginBottom: '16px',\n } as React.CSSProperties,\n title: {\n fontSize: '16px',\n fontWeight: 600,\n color: 'var(--color-text-primary)',\n margin: 0,\n } as React.CSSProperties,\n headerActions: {\n display: 'flex',\n gap: '8px',\n alignItems: 'center',\n } as React.CSSProperties,\n filterSelect: {\n padding: '6px 12px',\n fontSize: '13px',\n border: '1px solid var(--color-border)',\n borderRadius: '6px',\n backgroundColor: 'var(--color-bg-surface)',\n } as React.CSSProperties,\n refreshButton: {\n padding: '6px 12px',\n fontSize: '13px',\n backgroundColor: 'var(--color-bg-muted)',\n border: 'none',\n borderRadius: '6px',\n cursor: 'pointer',\n transition: 'background-color 0.15s ease',\n } as React.CSSProperties,\n table: {\n width: '100%',\n borderCollapse: 'collapse',\n fontSize: '13px',\n } as React.CSSProperties,\n tableHeader: {\n backgroundColor: 'var(--color-bg-sunken)',\n borderBottom: '1px solid var(--color-border)',\n } as React.CSSProperties,\n th: {\n padding: '10px 12px',\n textAlign: 'left',\n fontWeight: 600,\n color: 'var(--color-text-secondary)',\n } as React.CSSProperties,\n td: {\n padding: '10px 12px',\n borderBottom: '1px solid var(--color-border)',\n color: 'var(--color-text-secondary)',\n } as React.CSSProperties,\n statusCell: {\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n } as React.CSSProperties,\n statusBadge: {\n padding: '2px 8px',\n borderRadius: '12px',\n fontSize: '11px',\n fontWeight: 500,\n } as React.CSSProperties,\n eventName: {\n fontFamily: 'monospace',\n fontSize: '12px',\n color: 'var(--color-text-secondary)',\n } as React.CSSProperties,\n timeAgo: {\n fontSize: '12px',\n color: 'var(--color-text-muted)',\n } as React.CSSProperties,\n retryButton: {\n padding: '4px 8px',\n fontSize: '11px',\n backgroundColor: 'var(--color-action-primary-bg)',\n color: 'var(--color-action-primary-text)',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n transition: 'opacity 0.15s ease',\n } as React.CSSProperties,\n emptyState: {\n textAlign: 'center',\n padding: '32px',\n color: 'var(--color-text-muted)',\n } as React.CSSProperties,\n loadMoreButton: {\n width: '100%',\n padding: '10px',\n marginTop: '12px',\n backgroundColor: 'var(--color-bg-muted)',\n border: 'none',\n borderRadius: '6px',\n fontSize: '13px',\n color: 'var(--color-text-secondary)',\n cursor: 'pointer',\n transition: 'background-color 0.15s ease',\n } as React.CSSProperties,\n totalCount: {\n fontSize: '12px',\n color: 'var(--color-text-muted)',\n } as React.CSSProperties,\n tableContainer: {\n overflowX: 'auto',\n } as React.CSSProperties,\n detailRow: {\n backgroundColor: 'var(--color-bg-sunken)',\n } as React.CSSProperties,\n detailContent: {\n padding: '12px',\n fontSize: '12px',\n fontFamily: 'monospace',\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-all',\n color: 'var(--color-text-secondary)',\n } as React.CSSProperties,\n expandButton: {\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: '4px',\n fontSize: '14px',\n } as React.CSSProperties,\n};\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\nfunction formatTimeAgo(dateString: string): string {\n const date = new Date(dateString);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffMins = Math.floor(diffMs / 60000);\n const diffHours = Math.floor(diffMins / 60);\n const diffDays = Math.floor(diffHours / 24);\n\n if (diffMins < 1) return 'Just now';\n if (diffMins < 60) return `${diffMins}m ago`;\n if (diffHours < 24) return `${diffHours}h ago`;\n if (diffDays < 7) return `${diffDays}d ago`;\n return date.toLocaleDateString();\n}\n\n// ============================================================================\n// Event Log Row Component\n// ============================================================================\n\ninterface EventLogRowProps {\n log: EventLog;\n onRetry: () => void;\n retrying?: boolean;\n expanded?: boolean;\n onToggleExpand: () => void;\n}\n\nconst EventLogRow: React.FC<EventLogRowProps> = memo(function EventLogRow({\n log,\n onRetry,\n retrying,\n expanded,\n onToggleExpand,\n}) {\n const canRetry = log.status === 'FAILED';\n\n return (\n <>\n <tr>\n <td style={styles.td}>\n <button onClick={onToggleExpand} style={styles.expandButton}>\n {expanded ? '▼' : '▶'}\n </button>\n </td>\n <td style={styles.td}>\n <div style={styles.statusCell}>\n <span>{getEventStatusIcon(log.status)}</span>\n <span\n style={{\n ...styles.statusBadge,\n backgroundColor: `${getEventStatusColor(log.status)}20`,\n color: getEventStatusColor(log.status),\n }}\n >\n {getEventStatusLabel(log.status)}\n </span>\n </div>\n </td>\n <td style={styles.td}>\n <div style={styles.eventName}>{log.eventName}</div>\n {log.actionName && <div style={{ fontSize: '11px', color: '#9ca3af' }}>Action: {log.actionName}</div>}\n </td>\n <td style={styles.td}>\n <div style={styles.timeAgo}>{formatTimeAgo(log.createdAt)}</div>\n </td>\n <td style={styles.td}>\n {log.webhookUrl ? (\n <span style={{ fontSize: '12px', color: '#6b7280' }}>{new URL(log.webhookUrl).hostname}</span>\n ) : (\n <span style={{ fontSize: '12px', color: '#d1d5db' }}>—</span>\n )}\n </td>\n <td style={styles.td}>\n {canRetry && (\n <button onClick={onRetry} disabled={retrying} style={styles.retryButton}>\n {retrying ? '...' : '🔄 Retry'}\n </button>\n )}\n </td>\n </tr>\n {expanded && (\n <tr style={styles.detailRow}>\n <td colSpan={6} style={styles.td}>\n <div style={styles.detailContent as React.CSSProperties}>\n <strong>Payload:</strong>\n {'\\n'}\n {JSON.stringify(log.payload, null, 2)}\n {log.errorMessage && (\n <>\n {'\\n\\n'}\n <strong style={{ color: '#dc2626' }}>Error:</strong>\n {'\\n'}\n {log.errorMessage}\n </>\n )}\n {log.responseCode && (\n <>\n {'\\n\\n'}\n <strong>Response Code:</strong> {log.responseCode}\n </>\n )}\n {'\\n\\n'}\n <strong>Attempts:</strong> {log.attempts}\n </div>\n </td>\n </tr>\n )}\n </>\n );\n});\n\n// ============================================================================\n// Main Component\n// ============================================================================\n\nexport const EventLogViewer: React.FC<EventLogViewerProps> = memo(function EventLogViewer({\n dashboardId,\n widgetId,\n maxHeight = '400px',\n onRetrySuccess,\n}) {\n const [statusFilter, setStatusFilter] = useState<EventStatus | ''>('');\n const [expandedIds, setExpandedIds] = useState<Set<string>>(new Set());\n const [retryingId, setRetryingId] = useState<string | null>(null);\n\n const { logs, loading, totalCount, hasMore, loadMore, retryDelivery, refetch } = useEventLogs({\n dashboardId,\n widgetId,\n status: statusFilter || undefined,\n });\n\n const handleRetry = useCallback(\n async (log: EventLog) => {\n setRetryingId(log.id);\n const result = await retryDelivery(log.id);\n setRetryingId(null);\n if (result) {\n onRetrySuccess?.(result);\n }\n },\n [retryDelivery, onRetrySuccess]\n );\n\n const handleToggleExpand = useCallback((id: string) => {\n setExpandedIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) {\n next.delete(id);\n } else {\n next.add(id);\n }\n return next;\n });\n }, []);\n\n return (\n <div style={styles.container}>\n <div style={styles.header}>\n <div>\n <h3 style={styles.title}>Event History</h3>\n <span style={styles.totalCount}>{totalCount} events</span>\n </div>\n <div style={styles.headerActions}>\n <select\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value as EventStatus | '')}\n style={styles.filterSelect}\n >\n <option value=\"\">All Status</option>\n <option value=\"DELIVERED\">Delivered</option>\n <option value=\"FAILED\">Failed</option>\n <option value=\"PENDING\">Pending</option>\n <option value=\"PROCESSING\">Processing</option>\n <option value=\"RETRYING\">Retrying</option>\n <option value=\"IGNORED\">Ignored</option>\n </select>\n <button onClick={() => refetch()} style={styles.refreshButton}>\n 🔄 Refresh\n </button>\n </div>\n </div>\n\n {loading && logs.length === 0 ? (\n <div style={styles.emptyState}>Loading...</div>\n ) : logs.length === 0 ? (\n <div style={styles.emptyState}>\n <p>No events found</p>\n <p style={{ fontSize: '13px', marginTop: '8px' }}>Events will appear here when actions are triggered.</p>\n </div>\n ) : (\n <>\n <div style={{ ...styles.tableContainer, maxHeight, overflowY: 'auto' }}>\n <table style={styles.table}>\n <thead style={styles.tableHeader}>\n <tr>\n <th style={{ ...styles.th, width: '40px' }}></th>\n <th style={styles.th}>Status</th>\n <th style={styles.th}>Event</th>\n <th style={styles.th}>Time</th>\n <th style={styles.th}>Webhook</th>\n <th style={{ ...styles.th, width: '80px' }}>Action</th>\n </tr>\n </thead>\n <tbody>\n {logs.map((log) => (\n <EventLogRow\n key={log.id}\n log={log}\n onRetry={() => handleRetry(log)}\n retrying={retryingId === log.id}\n expanded={expandedIds.has(log.id)}\n onToggleExpand={() => handleToggleExpand(log.id)}\n />\n ))}\n </tbody>\n </table>\n </div>\n\n {hasMore && (\n <button onClick={loadMore} style={styles.loadMoreButton}>\n Load More\n </button>\n )}\n </>\n )}\n </div>\n );\n});\n\nexport default EventLogViewer;\n"],"mappings":"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"}
1
+ {"version":3,"file":"EventLogViewer.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/event-logs/EventLogViewer.tsx"],"sourcesContent":["/**\n * EventLogViewer Component (v2.0)\n *\n * Component for viewing event history and managing failed deliveries.\n * Shows event status, allows filtering, and supports retry functionality.\n */\n\nimport React, { memo, useState, useCallback } from 'react';\nimport {\n useEventLogs,\n getEventStatusColor,\n getEventStatusLabel,\n getEventStatusIcon,\n type EventStatus,\n type EventLog,\n} from '../../../hooks/useEventLogs';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface EventLogViewerProps {\n /** Dashboard ID to filter logs */\n dashboardId?: string;\n /** Widget ID to filter logs */\n widgetId?: string;\n /** Maximum height of the viewer */\n maxHeight?: string;\n /** Callback when retry is successful */\n onRetrySuccess?: (eventLog: EventLog) => void;\n}\n\n// ============================================================================\n// Styles\n// ============================================================================\n\nconst styles = {\n container: {\n padding: '16px',\n backgroundColor: 'var(--color-bg-surface)',\n borderRadius: '8px',\n } as React.CSSProperties,\n header: {\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n marginBottom: '16px',\n } as React.CSSProperties,\n title: {\n fontSize: '16px',\n fontWeight: 600,\n color: 'var(--color-text-primary)',\n margin: 0,\n } as React.CSSProperties,\n headerActions: {\n display: 'flex',\n gap: '8px',\n alignItems: 'center',\n } as React.CSSProperties,\n filterSelect: {\n padding: '6px 12px',\n fontSize: '13px',\n border: '1px solid var(--color-border)',\n borderRadius: '6px',\n backgroundColor: 'var(--color-bg-surface)',\n } as React.CSSProperties,\n refreshButton: {\n padding: '6px 12px',\n fontSize: '13px',\n backgroundColor: 'var(--color-bg-muted)',\n border: 'none',\n borderRadius: '6px',\n cursor: 'pointer',\n transition: 'background-color 0.15s ease',\n } as React.CSSProperties,\n table: {\n width: '100%',\n borderCollapse: 'collapse',\n fontSize: '13px',\n } as React.CSSProperties,\n tableHeader: {\n backgroundColor: 'var(--color-bg-sunken)',\n borderBottom: '1px solid var(--color-border)',\n } as React.CSSProperties,\n th: {\n padding: '10px 12px',\n textAlign: 'left',\n fontWeight: 600,\n color: 'var(--color-text-secondary)',\n } as React.CSSProperties,\n td: {\n padding: '10px 12px',\n borderBottom: '1px solid var(--color-border)',\n color: 'var(--color-text-secondary)',\n } as React.CSSProperties,\n statusCell: {\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n } as React.CSSProperties,\n statusBadge: {\n padding: '2px 8px',\n borderRadius: '12px',\n fontSize: '11px',\n fontWeight: 500,\n } as React.CSSProperties,\n eventName: {\n fontFamily: 'monospace',\n fontSize: '12px',\n color: 'var(--color-text-secondary)',\n } as React.CSSProperties,\n timeAgo: {\n fontSize: '12px',\n color: 'var(--color-text-muted)',\n } as React.CSSProperties,\n retryButton: {\n padding: '4px 8px',\n fontSize: '11px',\n backgroundColor: 'var(--color-action-primary-bg)',\n color: 'var(--color-action-primary-text)',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n transition: 'opacity 0.15s ease',\n } as React.CSSProperties,\n emptyState: {\n textAlign: 'center',\n padding: '32px',\n color: 'var(--color-text-muted)',\n } as React.CSSProperties,\n loadMoreButton: {\n width: '100%',\n padding: '10px',\n marginTop: '12px',\n backgroundColor: 'var(--color-bg-muted)',\n border: 'none',\n borderRadius: '6px',\n fontSize: '13px',\n color: 'var(--color-text-secondary)',\n cursor: 'pointer',\n transition: 'background-color 0.15s ease',\n } as React.CSSProperties,\n totalCount: {\n fontSize: '12px',\n color: 'var(--color-text-muted)',\n } as React.CSSProperties,\n tableContainer: {\n overflowX: 'auto',\n } as React.CSSProperties,\n detailRow: {\n backgroundColor: 'var(--color-bg-sunken)',\n } as React.CSSProperties,\n detailContent: {\n padding: '12px',\n fontSize: '12px',\n fontFamily: 'monospace',\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-all',\n color: 'var(--color-text-secondary)',\n } as React.CSSProperties,\n expandButton: {\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: '4px',\n fontSize: '14px',\n } as React.CSSProperties,\n};\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\nfunction formatTimeAgo(dateString: string): string {\n const date = new Date(dateString);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffMins = Math.floor(diffMs / 60000);\n const diffHours = Math.floor(diffMins / 60);\n const diffDays = Math.floor(diffHours / 24);\n\n if (diffMins < 1) return 'Just now';\n if (diffMins < 60) return `${diffMins}m ago`;\n if (diffHours < 24) return `${diffHours}h ago`;\n if (diffDays < 7) return `${diffDays}d ago`;\n return date.toLocaleDateString();\n}\n\n// ============================================================================\n// Event Log Row Component\n// ============================================================================\n\ninterface EventLogRowProps {\n log: EventLog;\n onRetry: () => void;\n retrying?: boolean;\n expanded?: boolean;\n onToggleExpand: () => void;\n}\n\nconst EventLogRow: React.FC<EventLogRowProps> = memo(function EventLogRow({\n log,\n onRetry,\n retrying,\n expanded,\n onToggleExpand,\n}) {\n const canRetry = log.status === 'FAILED';\n\n return (\n <>\n <tr>\n <td style={styles.td}>\n <button onClick={onToggleExpand} style={styles.expandButton}>\n {expanded ? '▼' : '▶'}\n </button>\n </td>\n <td style={styles.td}>\n <div style={styles.statusCell}>\n <span>{getEventStatusIcon(log.status)}</span>\n <span\n style={{\n ...styles.statusBadge,\n backgroundColor: `${getEventStatusColor(log.status)}20`,\n color: getEventStatusColor(log.status),\n }}\n >\n {getEventStatusLabel(log.status)}\n </span>\n </div>\n </td>\n <td style={styles.td}>\n <div style={styles.eventName}>{log.eventName}</div>\n {log.actionName && (\n <div style={{ fontSize: '11px', color: 'var(--color-text-placeholder)' }}>Action: {log.actionName}</div>\n )}\n </td>\n <td style={styles.td}>\n <div style={styles.timeAgo}>{formatTimeAgo(log.createdAt)}</div>\n </td>\n <td style={styles.td}>\n {log.webhookUrl ? (\n <span style={{ fontSize: '12px', color: 'var(--color-text-muted)' }}>\n {new URL(log.webhookUrl).hostname}\n </span>\n ) : (\n <span style={{ fontSize: '12px', color: 'var(--color-text-placeholder)' }}>—</span>\n )}\n </td>\n <td style={styles.td}>\n {canRetry && (\n <button onClick={onRetry} disabled={retrying} style={styles.retryButton}>\n {retrying ? '...' : '🔄 Retry'}\n </button>\n )}\n </td>\n </tr>\n {expanded && (\n <tr style={styles.detailRow}>\n <td colSpan={6} style={styles.td}>\n <div style={styles.detailContent as React.CSSProperties}>\n <strong>Payload:</strong>\n {'\\n'}\n {JSON.stringify(log.payload, null, 2)}\n {log.errorMessage && (\n <>\n {'\\n\\n'}\n <strong style={{ color: 'var(--color-status-error-text)' }}>Error:</strong>\n {'\\n'}\n {log.errorMessage}\n </>\n )}\n {log.responseCode && (\n <>\n {'\\n\\n'}\n <strong>Response Code:</strong> {log.responseCode}\n </>\n )}\n {'\\n\\n'}\n <strong>Attempts:</strong> {log.attempts}\n </div>\n </td>\n </tr>\n )}\n </>\n );\n});\n\n// ============================================================================\n// Main Component\n// ============================================================================\n\nexport const EventLogViewer: React.FC<EventLogViewerProps> = memo(function EventLogViewer({\n dashboardId,\n widgetId,\n maxHeight = '400px',\n onRetrySuccess,\n}) {\n const [statusFilter, setStatusFilter] = useState<EventStatus | ''>('');\n const [expandedIds, setExpandedIds] = useState<Set<string>>(new Set());\n const [retryingId, setRetryingId] = useState<string | null>(null);\n\n const { logs, loading, totalCount, hasMore, loadMore, retryDelivery, refetch } = useEventLogs({\n dashboardId,\n widgetId,\n status: statusFilter || undefined,\n });\n\n const handleRetry = useCallback(\n async (log: EventLog) => {\n setRetryingId(log.id);\n const result = await retryDelivery(log.id);\n setRetryingId(null);\n if (result) {\n onRetrySuccess?.(result);\n }\n },\n [retryDelivery, onRetrySuccess]\n );\n\n const handleToggleExpand = useCallback((id: string) => {\n setExpandedIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) {\n next.delete(id);\n } else {\n next.add(id);\n }\n return next;\n });\n }, []);\n\n return (\n <div style={styles.container}>\n <div style={styles.header}>\n <div>\n <h3 style={styles.title}>Event History</h3>\n <span style={styles.totalCount}>{totalCount} events</span>\n </div>\n <div style={styles.headerActions}>\n <select\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value as EventStatus | '')}\n style={styles.filterSelect}\n >\n <option value=\"\">All Status</option>\n <option value=\"DELIVERED\">Delivered</option>\n <option value=\"FAILED\">Failed</option>\n <option value=\"PENDING\">Pending</option>\n <option value=\"PROCESSING\">Processing</option>\n <option value=\"RETRYING\">Retrying</option>\n <option value=\"IGNORED\">Ignored</option>\n </select>\n <button onClick={() => refetch()} style={styles.refreshButton}>\n 🔄 Refresh\n </button>\n </div>\n </div>\n\n {loading && logs.length === 0 ? (\n <div style={styles.emptyState}>Loading...</div>\n ) : logs.length === 0 ? (\n <div style={styles.emptyState}>\n <p>No events found</p>\n <p style={{ fontSize: '13px', marginTop: '8px' }}>Events will appear here when actions are triggered.</p>\n </div>\n ) : (\n <>\n <div style={{ ...styles.tableContainer, maxHeight, overflowY: 'auto' }}>\n <table style={styles.table}>\n <thead style={styles.tableHeader}>\n <tr>\n <th style={{ ...styles.th, width: '40px' }}></th>\n <th style={styles.th}>Status</th>\n <th style={styles.th}>Event</th>\n <th style={styles.th}>Time</th>\n <th style={styles.th}>Webhook</th>\n <th style={{ ...styles.th, width: '80px' }}>Action</th>\n </tr>\n </thead>\n <tbody>\n {logs.map((log) => (\n <EventLogRow\n key={log.id}\n log={log}\n onRetry={() => handleRetry(log)}\n retrying={retryingId === log.id}\n expanded={expandedIds.has(log.id)}\n onToggleExpand={() => handleToggleExpand(log.id)}\n />\n ))}\n </tbody>\n </table>\n </div>\n\n {hasMore && (\n <button onClick={loadMore} style={styles.loadMoreButton}>\n Load More\n </button>\n )}\n </>\n )}\n </div>\n );\n});\n\nexport default EventLogViewer;\n"],"mappings":"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"}
@@ -67,27 +67,27 @@ var m = {
67
67
  display: "block",
68
68
  fontSize: "13px",
69
69
  fontWeight: 500,
70
- color: "#374151",
70
+ color: "var(--color-text-primary)",
71
71
  marginBottom: "6px"
72
72
  },
73
73
  required: {
74
- color: "#dc2626",
74
+ color: "var(--color-status-error-text)",
75
75
  marginLeft: "2px"
76
76
  },
77
77
  input: {
78
78
  width: "100%",
79
79
  padding: "8px 12px",
80
80
  fontSize: "14px",
81
- border: "1px solid #d1d5db",
81
+ border: "1px solid var(--color-border-default)",
82
82
  borderRadius: "6px",
83
- backgroundColor: "#ffffff",
83
+ backgroundColor: "var(--color-bg-surface)",
84
84
  transition: "border-color 0.15s, box-shadow 0.15s",
85
85
  outline: "none"
86
86
  },
87
- inputError: { borderColor: "#dc2626" },
87
+ inputError: { borderColor: "var(--color-status-error-border)" },
88
88
  inputFocus: {
89
- borderColor: "#6366f1",
90
- boxShadow: "0 0 0 3px rgba(99, 102, 241, 0.1)"
89
+ borderColor: "var(--color-border-focus)",
90
+ boxShadow: "var(--shadow-focus)"
91
91
  },
92
92
  textarea: {
93
93
  resize: "vertical",
@@ -113,12 +113,12 @@ var m = {
113
113
  },
114
114
  helpText: {
115
115
  fontSize: "12px",
116
- color: "#6b7280",
116
+ color: "var(--color-text-muted)",
117
117
  marginTop: "4px"
118
118
  },
119
119
  errorText: {
120
120
  fontSize: "12px",
121
- color: "#dc2626",
121
+ color: "var(--color-status-error-text)",
122
122
  marginTop: "4px",
123
123
  display: "flex",
124
124
  alignItems: "center",
@@ -129,8 +129,8 @@ var m = {
129
129
  justifyContent: "flex-end",
130
130
  gap: "12px",
131
131
  padding: "12px 16px",
132
- borderTop: "1px solid #e5e7eb",
133
- backgroundColor: "#f9fafb"
132
+ borderTop: "1px solid var(--color-border-subtle)",
133
+ backgroundColor: "var(--color-bg-subtle)"
134
134
  },
135
135
  button: {
136
136
  display: "inline-flex",
@@ -145,24 +145,24 @@ var m = {
145
145
  border: "none"
146
146
  },
147
147
  submitButton: {
148
- backgroundColor: "#6366f1",
149
- color: "#ffffff"
148
+ backgroundColor: "var(--color-action-primary-bg)",
149
+ color: "var(--color-text-inverse)"
150
150
  },
151
151
  resetButton: {
152
- backgroundColor: "#ffffff",
153
- color: "#374151",
154
- border: "1px solid #d1d5db"
152
+ backgroundColor: "var(--color-bg-surface)",
153
+ color: "var(--color-text-primary)",
154
+ border: "1px solid var(--color-border-default)"
155
155
  },
156
156
  successMessage: {
157
157
  display: "flex",
158
158
  alignItems: "center",
159
159
  gap: "8px",
160
160
  padding: "12px 16px",
161
- backgroundColor: "#ecfdf5",
162
- border: "1px solid #a7f3d0",
161
+ backgroundColor: "var(--color-status-success-bgSubtle)",
162
+ border: "1px solid var(--color-status-success-border)",
163
163
  borderRadius: "6px",
164
164
  marginBottom: "16px",
165
- color: "#065f46",
165
+ color: "var(--color-status-success-text)",
166
166
  fontSize: "14px"
167
167
  },
168
168
  emptyState: {
@@ -172,7 +172,7 @@ var m = {
172
172
  justifyContent: "center",
173
173
  height: "100%",
174
174
  padding: "32px",
175
- color: "#6b7280",
175
+ color: "var(--color-text-muted)",
176
176
  textAlign: "center"
177
177
  }
178
178
  }, h = e(function({ widget: e, data: h = {}, onDrilldown: g, onSubmit: _ }) {
@@ -1 +1 @@
1
- {"version":3,"file":"FormWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/form/FormWidget.tsx"],"sourcesContent":["/**\n * FormWidget Component\n *\n * Interactive form widget for data input with validation and submit actions.\n * v2.0 spec compliant widget type.\n */\n\nimport { type FC, memo, useState, useCallback, useMemo } from 'react';\nimport type {\n Widget,\n FormConfig as FormConfigType,\n FormFieldConfig,\n FormFieldType as FormFieldTypeAlias,\n FormFieldOption,\n FormValidationRule,\n} from '../../../types';\nimport { AlertCircle, CheckCircle, Send, RotateCcw, Settings, Loader2 } from 'lucide-react';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n// Re-export types from main types file\nexport type FieldType = FormFieldTypeAlias;\nexport type FormField = FormFieldConfig;\nexport type SelectOption = FormFieldOption;\nexport type ValidationRule = FormValidationRule;\nexport type FormConfig = FormConfigType;\n\nexport interface FormWidgetProps {\n widget: Widget;\n data?: Record<string, unknown>;\n /** Whether the widget is in edit mode */\n isEditMode?: boolean;\n /** Whether the widget is selected */\n isSelected?: boolean;\n /** Whether data is loading */\n isLoading?: boolean;\n /** Error message if any */\n error?: string | null;\n /** Callback when widget is clicked */\n onClick?: () => void;\n onDrilldown?: (selectedData: Record<string, unknown>) => void;\n onSubmit?: (formData: Record<string, unknown>) => void;\n}\n\ninterface FieldErrors {\n [fieldName: string]: string | null;\n}\n\n// ============================================================================\n// Validation\n// ============================================================================\n\nfunction validateField(value: unknown, field: FormField): string | null {\n const strValue = String(value ?? '');\n const isEmpty = value === null || value === undefined || strValue.trim() === '';\n\n // Check required\n if (field.required && isEmpty) {\n return `${field.label} is required`;\n }\n\n // Skip other validations if empty and not required\n if (isEmpty) return null;\n\n // Apply validation rules\n if (field.validation) {\n for (const rule of field.validation) {\n switch (rule.type) {\n case 'required':\n if (isEmpty) return rule.message;\n break;\n case 'minLength':\n if (strValue.length < Number(rule.value)) return rule.message;\n break;\n case 'maxLength':\n if (strValue.length > Number(rule.value)) return rule.message;\n break;\n case 'min':\n if (Number(value) < Number(rule.value)) return rule.message;\n break;\n case 'max':\n if (Number(value) > Number(rule.value)) return rule.message;\n break;\n case 'pattern':\n if (rule.value && !new RegExp(String(rule.value)).test(strValue)) {\n return rule.message;\n }\n break;\n case 'email':\n if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(strValue)) {\n return rule.message;\n }\n break;\n }\n }\n }\n\n // Type-specific validation\n if (field.type === 'email' && !field.validation?.some((r) => r.type === 'email')) {\n if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(strValue)) {\n return 'Please enter a valid email address';\n }\n }\n\n if (field.type === 'url') {\n try {\n new URL(strValue);\n } catch {\n return 'Please enter a valid URL';\n }\n }\n\n if (field.type === 'number') {\n if (isNaN(Number(value))) {\n return 'Please enter a valid number';\n }\n if (field.min !== undefined && Number(value) < Number(field.min)) {\n return `Value must be at least ${field.min}`;\n }\n if (field.max !== undefined && Number(value) > Number(field.max)) {\n return `Value must be at most ${field.max}`;\n }\n }\n\n return null;\n}\n\nfunction validateForm(values: Record<string, unknown>, fields: FormField[]): FieldErrors {\n const errors: FieldErrors = {};\n for (const field of fields) {\n const error = validateField(values[field.name], field);\n if (error) {\n errors[field.name] = error;\n }\n }\n return errors;\n}\n\n// ============================================================================\n// Styles\n// ============================================================================\n\nconst styles = {\n container: {\n display: 'flex',\n flexDirection: 'column' as const,\n height: '100%',\n overflow: 'hidden',\n },\n form: {\n flex: 1,\n overflow: 'auto',\n padding: '16px',\n },\n fieldWrapper: {\n marginBottom: '16px',\n },\n label: {\n display: 'block',\n fontSize: '13px',\n fontWeight: 500,\n color: '#374151',\n marginBottom: '6px',\n },\n required: {\n color: '#dc2626',\n marginLeft: '2px',\n },\n input: {\n width: '100%',\n padding: '8px 12px',\n fontSize: '14px',\n border: '1px solid #d1d5db',\n borderRadius: '6px',\n backgroundColor: '#ffffff',\n transition: 'border-color 0.15s, box-shadow 0.15s',\n outline: 'none',\n },\n inputError: {\n borderColor: '#dc2626',\n },\n inputFocus: {\n borderColor: '#6366f1',\n boxShadow: '0 0 0 3px rgba(99, 102, 241, 0.1)',\n },\n textarea: {\n resize: 'vertical' as const,\n minHeight: '80px',\n },\n select: {\n appearance: 'none' as const,\n backgroundImage: `url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e\")`,\n backgroundPosition: 'right 8px center',\n backgroundRepeat: 'no-repeat',\n backgroundSize: '20px',\n paddingRight: '36px',\n },\n checkbox: {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n },\n checkboxInput: {\n width: '16px',\n height: '16px',\n cursor: 'pointer',\n },\n helpText: {\n fontSize: '12px',\n color: '#6b7280',\n marginTop: '4px',\n },\n errorText: {\n fontSize: '12px',\n color: '#dc2626',\n marginTop: '4px',\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n },\n footer: {\n display: 'flex',\n justifyContent: 'flex-end',\n gap: '12px',\n padding: '12px 16px',\n borderTop: '1px solid #e5e7eb',\n backgroundColor: '#f9fafb',\n },\n button: {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '8px',\n padding: '8px 16px',\n fontSize: '14px',\n fontWeight: 500,\n borderRadius: '6px',\n cursor: 'pointer',\n transition: 'all 0.15s',\n border: 'none',\n },\n submitButton: {\n backgroundColor: '#6366f1',\n color: '#ffffff',\n },\n resetButton: {\n backgroundColor: '#ffffff',\n color: '#374151',\n border: '1px solid #d1d5db',\n },\n successMessage: {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '12px 16px',\n backgroundColor: '#ecfdf5',\n border: '1px solid #a7f3d0',\n borderRadius: '6px',\n marginBottom: '16px',\n color: '#065f46',\n fontSize: '14px',\n },\n emptyState: {\n display: 'flex',\n flexDirection: 'column' as const,\n alignItems: 'center',\n justifyContent: 'center',\n height: '100%',\n padding: '32px',\n color: '#6b7280',\n textAlign: 'center' as const,\n },\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const FormWidget: FC<FormWidgetProps> = memo(function FormWidget({ widget, data = {}, onDrilldown, onSubmit }) {\n const defaultConfig: FormConfig = {\n fields: [],\n layout: 'vertical',\n submitLabel: 'Submit',\n showReset: true,\n validateOnBlur: true,\n validateOnChange: false,\n };\n const config: FormConfig = widget.config\n ? { ...defaultConfig, ...(widget.config as Partial<FormConfig>) }\n : defaultConfig;\n\n // Initialize form values from default values or data\n const initialValues = useMemo(() => {\n const values: Record<string, unknown> = {};\n for (const field of config.fields) {\n values[field.name] = data[field.name] ?? field.defaultValue ?? (field.type === 'checkbox' ? false : '');\n }\n return values;\n }, [config.fields, data]);\n\n const [values, setValues] = useState<Record<string, unknown>>(initialValues);\n const [errors, setErrors] = useState<FieldErrors>({});\n const [touched, setTouched] = useState<Set<string>>(new Set());\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [submitSuccess, setSubmitSuccess] = useState(false);\n\n // Handle field change\n const handleChange = useCallback(\n (fieldName: string, value: unknown) => {\n setValues((prev) => ({ ...prev, [fieldName]: value }));\n setSubmitSuccess(false);\n\n if (config.validateOnChange) {\n const field = config.fields.find((f) => f.name === fieldName);\n if (field) {\n const error = validateField(value, field);\n setErrors((prev) => ({ ...prev, [fieldName]: error }));\n }\n }\n },\n [config.fields, config.validateOnChange]\n );\n\n // Handle field blur\n const handleBlur = useCallback(\n (fieldName: string) => {\n setTouched((prev) => new Set(prev).add(fieldName));\n\n if (config.validateOnBlur) {\n const field = config.fields.find((f) => f.name === fieldName);\n if (field) {\n const error = validateField(values[fieldName], field);\n setErrors((prev) => ({ ...prev, [fieldName]: error }));\n }\n }\n },\n [config.fields, config.validateOnBlur, values]\n );\n\n // Handle form submit\n const handleSubmit = useCallback(\n async (e: React.FormEvent) => {\n e.preventDefault();\n\n // Validate all fields\n const allErrors = validateForm(values, config.fields);\n setErrors(allErrors);\n setTouched(new Set(config.fields.map((f) => f.name)));\n\n // Check if there are errors\n const hasErrors = Object.values(allErrors).some((e) => e !== null);\n if (hasErrors) {\n return;\n }\n\n setIsSubmitting(true);\n\n try {\n // Emit form submit event via onDrilldown or onSubmit\n const formData = {\n ...values,\n _action: config.submitAction || 'form_submit',\n _widgetId: widget.id,\n _timestamp: new Date().toISOString(),\n };\n\n if (onSubmit) {\n await onSubmit(formData);\n }\n\n if (onDrilldown) {\n onDrilldown({\n type: 'form_submit',\n action: config.submitAction || 'form_submit',\n data: formData,\n });\n }\n\n setSubmitSuccess(true);\n } catch (error) {\n } finally {\n setIsSubmitting(false);\n }\n },\n [values, config.fields, config.submitAction, widget.id, onSubmit, onDrilldown]\n );\n\n // Handle form reset\n const handleReset = useCallback(() => {\n setValues(initialValues);\n setErrors({});\n setTouched(new Set());\n setSubmitSuccess(false);\n }, [initialValues]);\n\n // Render a field\n const renderField = useCallback(\n (field: FormField) => {\n const value = values[field.name];\n const error = touched.has(field.name) ? errors[field.name] : null;\n const hasError = Boolean(error);\n\n const inputStyle = {\n ...styles.input,\n ...(hasError ? styles.inputError : {}),\n };\n\n switch (field.type) {\n case 'textarea':\n return (\n <textarea\n id={field.name}\n name={field.name}\n value={String(value ?? '')}\n placeholder={field.placeholder}\n required={field.required}\n disabled={field.disabled || isSubmitting}\n readOnly={field.readonly}\n rows={field.rows || 4}\n style={{ ...inputStyle, ...styles.textarea }}\n onChange={(e) => handleChange(field.name, e.target.value)}\n onBlur={() => handleBlur(field.name)}\n />\n );\n\n case 'select':\n return (\n <select\n id={field.name}\n name={field.name}\n value={String(value ?? '')}\n required={field.required}\n disabled={field.disabled || isSubmitting}\n style={{ ...inputStyle, ...styles.select }}\n onChange={(e) => handleChange(field.name, e.target.value)}\n onBlur={() => handleBlur(field.name)}\n >\n <option value=\"\">{field.placeholder || `Select ${field.label}...`}</option>\n {field.options?.map((opt) => (\n <option key={opt.value} value={opt.value} disabled={opt.disabled}>\n {opt.label}\n </option>\n ))}\n </select>\n );\n\n case 'checkbox':\n return (\n <div style={styles.checkbox}>\n <input\n type=\"checkbox\"\n id={field.name}\n name={field.name}\n checked={Boolean(value)}\n disabled={field.disabled || isSubmitting}\n style={styles.checkboxInput}\n onChange={(e) => handleChange(field.name, e.target.checked)}\n onBlur={() => handleBlur(field.name)}\n />\n <label htmlFor={field.name} style={{ fontSize: '14px', cursor: 'pointer' }}>\n {field.label}\n </label>\n </div>\n );\n\n case 'radio':\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>\n {field.options?.map((opt) => (\n <div key={opt.value} style={styles.checkbox}>\n <input\n type=\"radio\"\n id={`${field.name}-${opt.value}`}\n name={field.name}\n value={opt.value}\n checked={value === opt.value}\n disabled={field.disabled || opt.disabled || isSubmitting}\n style={styles.checkboxInput}\n onChange={(e) => handleChange(field.name, e.target.value)}\n onBlur={() => handleBlur(field.name)}\n />\n <label htmlFor={`${field.name}-${opt.value}`} style={{ fontSize: '14px', cursor: 'pointer' }}>\n {opt.label}\n </label>\n </div>\n ))}\n </div>\n );\n\n case 'hidden':\n return <input type=\"hidden\" name={field.name} value={String(value ?? '')} />;\n\n default:\n return (\n <input\n type={field.type}\n id={field.name}\n name={field.name}\n value={String(value ?? '')}\n placeholder={field.placeholder}\n required={field.required}\n disabled={field.disabled || isSubmitting}\n readOnly={field.readonly}\n min={field.min}\n max={field.max}\n step={field.step}\n pattern={field.pattern}\n style={inputStyle}\n onChange={(e) =>\n handleChange(field.name, field.type === 'number' ? e.target.valueAsNumber : e.target.value)\n }\n onBlur={() => handleBlur(field.name)}\n />\n );\n }\n },\n [values, errors, touched, isSubmitting, handleChange, handleBlur]\n );\n\n // Empty state\n if (config.fields.length === 0) {\n return (\n <div style={styles.emptyState}>\n <Settings style={{ width: '48px', height: '48px', marginBottom: '16px', opacity: 0.5 }} />\n <p style={{ fontSize: '14px' }}>Configure Form Fields</p>\n <p style={{ fontSize: '12px', marginTop: '4px' }}>Add fields in widget settings to create your form</p>\n </div>\n );\n }\n\n // Grid layout styles\n const gridStyle =\n config.layout === 'grid'\n ? {\n display: 'grid',\n gridTemplateColumns: `repeat(${config.columns || 2}, 1fr)`,\n gap: '16px',\n }\n : {};\n\n return (\n <div style={styles.container}>\n <form onSubmit={handleSubmit} style={{ ...styles.form, ...gridStyle }}>\n {/* Success message */}\n {submitSuccess && config.successMessage && (\n <div style={{ ...styles.successMessage, gridColumn: '1 / -1' }}>\n <CheckCircle style={{ width: '18px', height: '18px' }} />\n {config.successMessage}\n </div>\n )}\n\n {/* Form fields */}\n {config.fields.map((field) => {\n if (field.type === 'hidden') {\n return renderField(field);\n }\n\n const error = touched.has(field.name) ? errors[field.name] : null;\n\n return (\n <div key={field.name} style={styles.fieldWrapper}>\n {field.type !== 'checkbox' && (\n <label htmlFor={field.name} style={styles.label}>\n {field.label}\n {field.required && <span style={styles.required}>*</span>}\n </label>\n )}\n\n {renderField(field)}\n\n {field.helpText && !error && <p style={styles.helpText}>{field.helpText}</p>}\n\n {error && (\n <p style={styles.errorText}>\n <AlertCircle style={{ width: '14px', height: '14px' }} />\n {error}\n </p>\n )}\n </div>\n );\n })}\n </form>\n\n {/* Footer with buttons */}\n <div style={styles.footer}>\n {config.showReset !== false && (\n <button\n type=\"button\"\n onClick={handleReset}\n disabled={isSubmitting}\n style={{\n ...styles.button,\n ...styles.resetButton,\n opacity: isSubmitting ? 0.6 : 1,\n }}\n >\n <RotateCcw style={{ width: '16px', height: '16px' }} />\n {config.resetLabel || 'Reset'}\n </button>\n )}\n\n <button\n type=\"submit\"\n onClick={handleSubmit}\n disabled={isSubmitting}\n style={{\n ...styles.button,\n ...styles.submitButton,\n opacity: isSubmitting ? 0.6 : 1,\n }}\n >\n {isSubmitting ? (\n <Loader2 style={{ width: '16px', height: '16px', animation: 'spin 1s linear infinite' }} />\n ) : (\n <Send style={{ width: '16px', height: '16px' }} />\n )}\n {config.submitLabel || 'Submit'}\n </button>\n </div>\n </div>\n );\n});\n\nexport default FormWidget;\n"],"mappings":"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"}
1
+ {"version":3,"file":"FormWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/form/FormWidget.tsx"],"sourcesContent":["/**\n * FormWidget Component\n *\n * Interactive form widget for data input with validation and submit actions.\n * v2.0 spec compliant widget type.\n */\n\nimport { type FC, memo, useState, useCallback, useMemo } from 'react';\nimport type {\n Widget,\n FormConfig as FormConfigType,\n FormFieldConfig,\n FormFieldType as FormFieldTypeAlias,\n FormFieldOption,\n FormValidationRule,\n} from '../../../types';\nimport { AlertCircle, CheckCircle, Send, RotateCcw, Settings, Loader2 } from 'lucide-react';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n// Re-export types from main types file\nexport type FieldType = FormFieldTypeAlias;\nexport type FormField = FormFieldConfig;\nexport type SelectOption = FormFieldOption;\nexport type ValidationRule = FormValidationRule;\nexport type FormConfig = FormConfigType;\n\nexport interface FormWidgetProps {\n widget: Widget;\n data?: Record<string, unknown>;\n /** Whether the widget is in edit mode */\n isEditMode?: boolean;\n /** Whether the widget is selected */\n isSelected?: boolean;\n /** Whether data is loading */\n isLoading?: boolean;\n /** Error message if any */\n error?: string | null;\n /** Callback when widget is clicked */\n onClick?: () => void;\n onDrilldown?: (selectedData: Record<string, unknown>) => void;\n onSubmit?: (formData: Record<string, unknown>) => void;\n}\n\ninterface FieldErrors {\n [fieldName: string]: string | null;\n}\n\n// ============================================================================\n// Validation\n// ============================================================================\n\nfunction validateField(value: unknown, field: FormField): string | null {\n const strValue = String(value ?? '');\n const isEmpty = value === null || value === undefined || strValue.trim() === '';\n\n // Check required\n if (field.required && isEmpty) {\n return `${field.label} is required`;\n }\n\n // Skip other validations if empty and not required\n if (isEmpty) return null;\n\n // Apply validation rules\n if (field.validation) {\n for (const rule of field.validation) {\n switch (rule.type) {\n case 'required':\n if (isEmpty) return rule.message;\n break;\n case 'minLength':\n if (strValue.length < Number(rule.value)) return rule.message;\n break;\n case 'maxLength':\n if (strValue.length > Number(rule.value)) return rule.message;\n break;\n case 'min':\n if (Number(value) < Number(rule.value)) return rule.message;\n break;\n case 'max':\n if (Number(value) > Number(rule.value)) return rule.message;\n break;\n case 'pattern':\n if (rule.value && !new RegExp(String(rule.value)).test(strValue)) {\n return rule.message;\n }\n break;\n case 'email':\n if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(strValue)) {\n return rule.message;\n }\n break;\n }\n }\n }\n\n // Type-specific validation\n if (field.type === 'email' && !field.validation?.some((r) => r.type === 'email')) {\n if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(strValue)) {\n return 'Please enter a valid email address';\n }\n }\n\n if (field.type === 'url') {\n try {\n new URL(strValue);\n } catch {\n return 'Please enter a valid URL';\n }\n }\n\n if (field.type === 'number') {\n if (isNaN(Number(value))) {\n return 'Please enter a valid number';\n }\n if (field.min !== undefined && Number(value) < Number(field.min)) {\n return `Value must be at least ${field.min}`;\n }\n if (field.max !== undefined && Number(value) > Number(field.max)) {\n return `Value must be at most ${field.max}`;\n }\n }\n\n return null;\n}\n\nfunction validateForm(values: Record<string, unknown>, fields: FormField[]): FieldErrors {\n const errors: FieldErrors = {};\n for (const field of fields) {\n const error = validateField(values[field.name], field);\n if (error) {\n errors[field.name] = error;\n }\n }\n return errors;\n}\n\n// ============================================================================\n// Styles\n// ============================================================================\n\nconst styles = {\n container: {\n display: 'flex',\n flexDirection: 'column' as const,\n height: '100%',\n overflow: 'hidden',\n },\n form: {\n flex: 1,\n overflow: 'auto',\n padding: '16px',\n },\n fieldWrapper: {\n marginBottom: '16px',\n },\n label: {\n display: 'block',\n fontSize: '13px',\n fontWeight: 500,\n color: 'var(--color-text-primary)',\n marginBottom: '6px',\n },\n required: {\n color: 'var(--color-status-error-text)',\n marginLeft: '2px',\n },\n input: {\n width: '100%',\n padding: '8px 12px',\n fontSize: '14px',\n border: '1px solid var(--color-border-default)',\n borderRadius: '6px',\n backgroundColor: 'var(--color-bg-surface)',\n transition: 'border-color 0.15s, box-shadow 0.15s',\n outline: 'none',\n },\n inputError: {\n borderColor: 'var(--color-status-error-border)',\n },\n inputFocus: {\n borderColor: 'var(--color-border-focus)',\n boxShadow: 'var(--shadow-focus)',\n },\n textarea: {\n resize: 'vertical' as const,\n minHeight: '80px',\n },\n select: {\n appearance: 'none' as const,\n backgroundImage: `url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e\")`,\n backgroundPosition: 'right 8px center',\n backgroundRepeat: 'no-repeat',\n backgroundSize: '20px',\n paddingRight: '36px',\n },\n checkbox: {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n },\n checkboxInput: {\n width: '16px',\n height: '16px',\n cursor: 'pointer',\n },\n helpText: {\n fontSize: '12px',\n color: 'var(--color-text-muted)',\n marginTop: '4px',\n },\n errorText: {\n fontSize: '12px',\n color: 'var(--color-status-error-text)',\n marginTop: '4px',\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n },\n footer: {\n display: 'flex',\n justifyContent: 'flex-end',\n gap: '12px',\n padding: '12px 16px',\n borderTop: '1px solid var(--color-border-subtle)',\n backgroundColor: 'var(--color-bg-subtle)',\n },\n button: {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '8px',\n padding: '8px 16px',\n fontSize: '14px',\n fontWeight: 500,\n borderRadius: '6px',\n cursor: 'pointer',\n transition: 'all 0.15s',\n border: 'none',\n },\n submitButton: {\n backgroundColor: 'var(--color-action-primary-bg)',\n color: 'var(--color-text-inverse)',\n },\n resetButton: {\n backgroundColor: 'var(--color-bg-surface)',\n color: 'var(--color-text-primary)',\n border: '1px solid var(--color-border-default)',\n },\n successMessage: {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '12px 16px',\n backgroundColor: 'var(--color-status-success-bgSubtle)',\n border: '1px solid var(--color-status-success-border)',\n borderRadius: '6px',\n marginBottom: '16px',\n color: 'var(--color-status-success-text)',\n fontSize: '14px',\n },\n emptyState: {\n display: 'flex',\n flexDirection: 'column' as const,\n alignItems: 'center',\n justifyContent: 'center',\n height: '100%',\n padding: '32px',\n color: 'var(--color-text-muted)',\n textAlign: 'center' as const,\n },\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const FormWidget: FC<FormWidgetProps> = memo(function FormWidget({ widget, data = {}, onDrilldown, onSubmit }) {\n const defaultConfig: FormConfig = {\n fields: [],\n layout: 'vertical',\n submitLabel: 'Submit',\n showReset: true,\n validateOnBlur: true,\n validateOnChange: false,\n };\n const config: FormConfig = widget.config\n ? { ...defaultConfig, ...(widget.config as Partial<FormConfig>) }\n : defaultConfig;\n\n // Initialize form values from default values or data\n const initialValues = useMemo(() => {\n const values: Record<string, unknown> = {};\n for (const field of config.fields) {\n values[field.name] = data[field.name] ?? field.defaultValue ?? (field.type === 'checkbox' ? false : '');\n }\n return values;\n }, [config.fields, data]);\n\n const [values, setValues] = useState<Record<string, unknown>>(initialValues);\n const [errors, setErrors] = useState<FieldErrors>({});\n const [touched, setTouched] = useState<Set<string>>(new Set());\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [submitSuccess, setSubmitSuccess] = useState(false);\n\n // Handle field change\n const handleChange = useCallback(\n (fieldName: string, value: unknown) => {\n setValues((prev) => ({ ...prev, [fieldName]: value }));\n setSubmitSuccess(false);\n\n if (config.validateOnChange) {\n const field = config.fields.find((f) => f.name === fieldName);\n if (field) {\n const error = validateField(value, field);\n setErrors((prev) => ({ ...prev, [fieldName]: error }));\n }\n }\n },\n [config.fields, config.validateOnChange]\n );\n\n // Handle field blur\n const handleBlur = useCallback(\n (fieldName: string) => {\n setTouched((prev) => new Set(prev).add(fieldName));\n\n if (config.validateOnBlur) {\n const field = config.fields.find((f) => f.name === fieldName);\n if (field) {\n const error = validateField(values[fieldName], field);\n setErrors((prev) => ({ ...prev, [fieldName]: error }));\n }\n }\n },\n [config.fields, config.validateOnBlur, values]\n );\n\n // Handle form submit\n const handleSubmit = useCallback(\n async (e: React.FormEvent) => {\n e.preventDefault();\n\n // Validate all fields\n const allErrors = validateForm(values, config.fields);\n setErrors(allErrors);\n setTouched(new Set(config.fields.map((f) => f.name)));\n\n // Check if there are errors\n const hasErrors = Object.values(allErrors).some((e) => e !== null);\n if (hasErrors) {\n return;\n }\n\n setIsSubmitting(true);\n\n try {\n // Emit form submit event via onDrilldown or onSubmit\n const formData = {\n ...values,\n _action: config.submitAction || 'form_submit',\n _widgetId: widget.id,\n _timestamp: new Date().toISOString(),\n };\n\n if (onSubmit) {\n await onSubmit(formData);\n }\n\n if (onDrilldown) {\n onDrilldown({\n type: 'form_submit',\n action: config.submitAction || 'form_submit',\n data: formData,\n });\n }\n\n setSubmitSuccess(true);\n } catch (error) {\n } finally {\n setIsSubmitting(false);\n }\n },\n [values, config.fields, config.submitAction, widget.id, onSubmit, onDrilldown]\n );\n\n // Handle form reset\n const handleReset = useCallback(() => {\n setValues(initialValues);\n setErrors({});\n setTouched(new Set());\n setSubmitSuccess(false);\n }, [initialValues]);\n\n // Render a field\n const renderField = useCallback(\n (field: FormField) => {\n const value = values[field.name];\n const error = touched.has(field.name) ? errors[field.name] : null;\n const hasError = Boolean(error);\n\n const inputStyle = {\n ...styles.input,\n ...(hasError ? styles.inputError : {}),\n };\n\n switch (field.type) {\n case 'textarea':\n return (\n <textarea\n id={field.name}\n name={field.name}\n value={String(value ?? '')}\n placeholder={field.placeholder}\n required={field.required}\n disabled={field.disabled || isSubmitting}\n readOnly={field.readonly}\n rows={field.rows || 4}\n style={{ ...inputStyle, ...styles.textarea }}\n onChange={(e) => handleChange(field.name, e.target.value)}\n onBlur={() => handleBlur(field.name)}\n />\n );\n\n case 'select':\n return (\n <select\n id={field.name}\n name={field.name}\n value={String(value ?? '')}\n required={field.required}\n disabled={field.disabled || isSubmitting}\n style={{ ...inputStyle, ...styles.select }}\n onChange={(e) => handleChange(field.name, e.target.value)}\n onBlur={() => handleBlur(field.name)}\n >\n <option value=\"\">{field.placeholder || `Select ${field.label}...`}</option>\n {field.options?.map((opt) => (\n <option key={opt.value} value={opt.value} disabled={opt.disabled}>\n {opt.label}\n </option>\n ))}\n </select>\n );\n\n case 'checkbox':\n return (\n <div style={styles.checkbox}>\n <input\n type=\"checkbox\"\n id={field.name}\n name={field.name}\n checked={Boolean(value)}\n disabled={field.disabled || isSubmitting}\n style={styles.checkboxInput}\n onChange={(e) => handleChange(field.name, e.target.checked)}\n onBlur={() => handleBlur(field.name)}\n />\n <label htmlFor={field.name} style={{ fontSize: '14px', cursor: 'pointer' }}>\n {field.label}\n </label>\n </div>\n );\n\n case 'radio':\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>\n {field.options?.map((opt) => (\n <div key={opt.value} style={styles.checkbox}>\n <input\n type=\"radio\"\n id={`${field.name}-${opt.value}`}\n name={field.name}\n value={opt.value}\n checked={value === opt.value}\n disabled={field.disabled || opt.disabled || isSubmitting}\n style={styles.checkboxInput}\n onChange={(e) => handleChange(field.name, e.target.value)}\n onBlur={() => handleBlur(field.name)}\n />\n <label htmlFor={`${field.name}-${opt.value}`} style={{ fontSize: '14px', cursor: 'pointer' }}>\n {opt.label}\n </label>\n </div>\n ))}\n </div>\n );\n\n case 'hidden':\n return <input type=\"hidden\" name={field.name} value={String(value ?? '')} />;\n\n default:\n return (\n <input\n type={field.type}\n id={field.name}\n name={field.name}\n value={String(value ?? '')}\n placeholder={field.placeholder}\n required={field.required}\n disabled={field.disabled || isSubmitting}\n readOnly={field.readonly}\n min={field.min}\n max={field.max}\n step={field.step}\n pattern={field.pattern}\n style={inputStyle}\n onChange={(e) =>\n handleChange(field.name, field.type === 'number' ? e.target.valueAsNumber : e.target.value)\n }\n onBlur={() => handleBlur(field.name)}\n />\n );\n }\n },\n [values, errors, touched, isSubmitting, handleChange, handleBlur]\n );\n\n // Empty state\n if (config.fields.length === 0) {\n return (\n <div style={styles.emptyState}>\n <Settings style={{ width: '48px', height: '48px', marginBottom: '16px', opacity: 0.5 }} />\n <p style={{ fontSize: '14px' }}>Configure Form Fields</p>\n <p style={{ fontSize: '12px', marginTop: '4px' }}>Add fields in widget settings to create your form</p>\n </div>\n );\n }\n\n // Grid layout styles\n const gridStyle =\n config.layout === 'grid'\n ? {\n display: 'grid',\n gridTemplateColumns: `repeat(${config.columns || 2}, 1fr)`,\n gap: '16px',\n }\n : {};\n\n return (\n <div style={styles.container}>\n <form onSubmit={handleSubmit} style={{ ...styles.form, ...gridStyle }}>\n {/* Success message */}\n {submitSuccess && config.successMessage && (\n <div style={{ ...styles.successMessage, gridColumn: '1 / -1' }}>\n <CheckCircle style={{ width: '18px', height: '18px' }} />\n {config.successMessage}\n </div>\n )}\n\n {/* Form fields */}\n {config.fields.map((field) => {\n if (field.type === 'hidden') {\n return renderField(field);\n }\n\n const error = touched.has(field.name) ? errors[field.name] : null;\n\n return (\n <div key={field.name} style={styles.fieldWrapper}>\n {field.type !== 'checkbox' && (\n <label htmlFor={field.name} style={styles.label}>\n {field.label}\n {field.required && <span style={styles.required}>*</span>}\n </label>\n )}\n\n {renderField(field)}\n\n {field.helpText && !error && <p style={styles.helpText}>{field.helpText}</p>}\n\n {error && (\n <p style={styles.errorText}>\n <AlertCircle style={{ width: '14px', height: '14px' }} />\n {error}\n </p>\n )}\n </div>\n );\n })}\n </form>\n\n {/* Footer with buttons */}\n <div style={styles.footer}>\n {config.showReset !== false && (\n <button\n type=\"button\"\n onClick={handleReset}\n disabled={isSubmitting}\n style={{\n ...styles.button,\n ...styles.resetButton,\n opacity: isSubmitting ? 0.6 : 1,\n }}\n >\n <RotateCcw style={{ width: '16px', height: '16px' }} />\n {config.resetLabel || 'Reset'}\n </button>\n )}\n\n <button\n type=\"submit\"\n onClick={handleSubmit}\n disabled={isSubmitting}\n style={{\n ...styles.button,\n ...styles.submitButton,\n opacity: isSubmitting ? 0.6 : 1,\n }}\n >\n {isSubmitting ? (\n <Loader2 style={{ width: '16px', height: '16px', animation: 'spin 1s linear infinite' }} />\n ) : (\n <Send style={{ width: '16px', height: '16px' }} />\n )}\n {config.submitLabel || 'Submit'}\n </button>\n </div>\n </div>\n );\n});\n\nexport default FormWidget;\n"],"mappings":"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"}
@@ -27,7 +27,7 @@ var a = e(function({ widget: e, data: a, onClick: o }) {
27
27
  children: [
28
28
  /* @__PURE__ */ n("div", {
29
29
  className: "w-2 h-2 rounded-full",
30
- style: { backgroundColor: e.color || "#6b7280" }
30
+ style: { backgroundColor: e.color || "var(--color-text-muted)" }
31
31
  }),
32
32
  /* @__PURE__ */ n("span", {
33
33
  className: "text-xs font-medium text-text-primary truncate",
@@ -1 +1 @@
1
- {"version":3,"file":"KanbanWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/kanban/KanbanWidget.tsx"],"sourcesContent":["/**\n * KanbanWidget Component\n *\n * Simple kanban board view with columns and tasks.\n */\n\nimport { type FC, memo, useMemo } from 'react';\nimport type { Widget } from '../../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface KanbanWidgetProps {\n widget: Widget;\n data?: KanbanData;\n onClick?: (task: KanbanTask) => void;\n}\n\nexport interface KanbanColumn {\n id: string;\n title: string;\n color?: string;\n}\n\nexport interface KanbanTask {\n id: string;\n title: string;\n column: string;\n priority?: 'high' | 'medium' | 'low';\n assignee?: string;\n labels?: string[];\n dueDate?: string;\n}\n\nexport interface KanbanData {\n columns?: KanbanColumn[];\n tasks?: KanbanTask[];\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction getPriorityColor(priority?: string): string {\n switch (priority) {\n case 'high':\n return 'bg-state-error/20 text-state-error';\n case 'medium':\n return 'bg-state-warning/20 text-state-warning';\n case 'low':\n return 'bg-state-success/20 text-state-success';\n default:\n return 'bg-bg-muted text-text-secondary';\n }\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const KanbanWidget: FC<KanbanWidgetProps> = memo(function KanbanWidget({ widget: _widget, data, onClick }) {\n const columns = useMemo(() => data?.columns || [], [data?.columns]);\n const tasks = useMemo(() => data?.tasks || [], [data?.tasks]);\n\n // Group tasks by column\n const tasksByColumn = useMemo(() => {\n const grouped: Record<string, KanbanTask[]> = {};\n columns.forEach((col) => {\n grouped[col.id] = tasks.filter((t) => t.column === col.id);\n });\n return grouped;\n }, [columns, tasks]);\n\n if (!columns.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 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2\"\n />\n </svg>\n <p>No board data</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex h-full p-2 gap-2 overflow-x-auto\">\n {columns.map((column) => {\n const columnTasks = tasksByColumn[column.id] || [];\n\n return (\n <div key={column.id} className=\"flex-shrink-0 w-48 flex flex-col bg-bg-muted/50 rounded-lg\">\n {/* Column Header */}\n <div className=\"flex items-center gap-2 p-2 border-b border-border-default\">\n <div className=\"w-2 h-2 rounded-full\" style={{ backgroundColor: column.color || '#6b7280' }} />\n <span className=\"text-xs font-medium text-text-primary truncate\">{column.title}</span>\n <span className=\"ml-auto text-xs text-text-tertiary\">{columnTasks.length}</span>\n </div>\n\n {/* Tasks */}\n <div className=\"flex-1 p-2 space-y-2 overflow-y-auto\">\n {columnTasks.map((task) => (\n <div\n key={task.id}\n className={`\n p-2 bg-bg-surface rounded border border-border-default\n ${onClick ? 'cursor-pointer hover:border-action-primary-bg' : ''}\n transition-colors\n `}\n onClick={() => onClick?.(task)}\n >\n <p className=\"text-xs font-medium text-text-primary line-clamp-2\">{task.title}</p>\n\n <div className=\"flex items-center gap-1 mt-2 flex-wrap\">\n {task.priority && (\n <span className={`px-1.5 py-0.5 text-[10px] rounded ${getPriorityColor(task.priority)}`}>\n {task.priority}\n </span>\n )}\n {task.assignee && (\n <span className=\"px-1.5 py-0.5 text-[10px] rounded bg-action-primary-bg/10 text-action-primary-text\">\n {task.assignee}\n </span>\n )}\n </div>\n </div>\n ))}\n\n {columnTasks.length === 0 && <p className=\"text-[10px] text-text-tertiary text-center py-4\">No tasks</p>}\n </div>\n </div>\n );\n })}\n </div>\n );\n});\n\nexport default KanbanWidget;\n"],"mappings":";;;AA4CA,SAAS,EAAiB,GAA2B;AACnD,SAAQ,GAAR;EACE,KAAK,OACH,QAAO;EACT,KAAK,SACH,QAAO;EACT,KAAK,MACH,QAAO;EACT,QACE,QAAO;;;AAQb,IAAa,IAAsC,EAAK,SAAsB,EAAE,QAAQ,GAAS,SAAM,cAAW;CAChH,IAAM,IAAU,QAAc,GAAM,WAAW,EAAE,EAAE,CAAC,GAAM,QAAQ,CAAC,EAC7D,IAAQ,QAAc,GAAM,SAAS,EAAE,EAAE,CAAC,GAAM,MAAM,CAAC,EAGvD,IAAgB,QAAc;EAClC,IAAM,IAAwC,EAAE;AAIhD,SAHA,EAAQ,SAAS,MAAQ;AACvB,KAAQ,EAAI,MAAM,EAAM,QAAQ,MAAM,EAAE,WAAW,EAAI,GAAG;IAC1D,EACK;IACN,CAAC,GAAS,EAAM,CAAC;AAyBpB,QAvBK,EAAQ,SAwBX,kBAAC,OAAD;EAAK,WAAU;YACZ,EAAQ,KAAK,MAAW;GACvB,IAAM,IAAc,EAAc,EAAO,OAAO,EAAE;AAElD,UACE,kBAAC,OAAD;IAAqB,WAAU;cAA/B,CAEE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD;OAAK,WAAU;OAAuB,OAAO,EAAE,iBAAiB,EAAO,SAAS,WAAW;OAAI,CAAA;MAC/F,kBAAC,QAAD;OAAM,WAAU;iBAAkD,EAAO;OAAa,CAAA;MACtF,kBAAC,QAAD;OAAM,WAAU;iBAAsC,EAAY;OAAc,CAAA;MAC5E;QAGN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,EAAY,KAAK,MAChB,kBAAC,OAAD;MAEE,WAAW;;wBAEL,IAAU,kDAAkD,GAAG;;;MAGrE,eAAe,IAAU,EAAK;gBAPhC,CASE,kBAAC,KAAD;OAAG,WAAU;iBAAsD,EAAK;OAAU,CAAA,EAElF,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACG,EAAK,YACJ,kBAAC,QAAD;QAAM,WAAW,qCAAqC,EAAiB,EAAK,SAAS;kBAClF,EAAK;QACD,CAAA,EAER,EAAK,YACJ,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAK;QACD,CAAA,CAEL;SACF;QAtBC,EAAK,GAsBN,CACN,EAED,EAAY,WAAW,KAAK,kBAAC,KAAD;MAAG,WAAU;gBAAkD;MAAY,CAAA,CACpG;OACF;MAvCI,EAAO,GAuCX;IAER;EACE,CAAA,GArEJ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IACE,WAAU;IACV,MAAK;IACL,QAAO;IACP,SAAQ;cAER,kBAAC,QAAD;KACE,eAAc;KACd,gBAAe;KACf,aAAa;KACb,GAAE;KACF,CAAA;IACE,CAAA,EACN,kBAAC,KAAD,EAAA,UAAG,iBAAiB,CAAA,CAChB;;EACF,CAAA;EAsDV"}
1
+ {"version":3,"file":"KanbanWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/kanban/KanbanWidget.tsx"],"sourcesContent":["/**\n * KanbanWidget Component\n *\n * Simple kanban board view with columns and tasks.\n */\n\nimport { type FC, memo, useMemo } from 'react';\nimport type { Widget } from '../../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface KanbanWidgetProps {\n widget: Widget;\n data?: KanbanData;\n onClick?: (task: KanbanTask) => void;\n}\n\nexport interface KanbanColumn {\n id: string;\n title: string;\n color?: string;\n}\n\nexport interface KanbanTask {\n id: string;\n title: string;\n column: string;\n priority?: 'high' | 'medium' | 'low';\n assignee?: string;\n labels?: string[];\n dueDate?: string;\n}\n\nexport interface KanbanData {\n columns?: KanbanColumn[];\n tasks?: KanbanTask[];\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction getPriorityColor(priority?: string): string {\n switch (priority) {\n case 'high':\n return 'bg-state-error/20 text-state-error';\n case 'medium':\n return 'bg-state-warning/20 text-state-warning';\n case 'low':\n return 'bg-state-success/20 text-state-success';\n default:\n return 'bg-bg-muted text-text-secondary';\n }\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const KanbanWidget: FC<KanbanWidgetProps> = memo(function KanbanWidget({ widget: _widget, data, onClick }) {\n const columns = useMemo(() => data?.columns || [], [data?.columns]);\n const tasks = useMemo(() => data?.tasks || [], [data?.tasks]);\n\n // Group tasks by column\n const tasksByColumn = useMemo(() => {\n const grouped: Record<string, KanbanTask[]> = {};\n columns.forEach((col) => {\n grouped[col.id] = tasks.filter((t) => t.column === col.id);\n });\n return grouped;\n }, [columns, tasks]);\n\n if (!columns.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 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2\"\n />\n </svg>\n <p>No board data</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex h-full p-2 gap-2 overflow-x-auto\">\n {columns.map((column) => {\n const columnTasks = tasksByColumn[column.id] || [];\n\n return (\n <div key={column.id} className=\"flex-shrink-0 w-48 flex flex-col bg-bg-muted/50 rounded-lg\">\n {/* Column Header */}\n <div className=\"flex items-center gap-2 p-2 border-b border-border-default\">\n <div\n className=\"w-2 h-2 rounded-full\"\n style={{ backgroundColor: column.color || 'var(--color-text-muted)' }}\n />\n <span className=\"text-xs font-medium text-text-primary truncate\">{column.title}</span>\n <span className=\"ml-auto text-xs text-text-tertiary\">{columnTasks.length}</span>\n </div>\n\n {/* Tasks */}\n <div className=\"flex-1 p-2 space-y-2 overflow-y-auto\">\n {columnTasks.map((task) => (\n <div\n key={task.id}\n className={`\n p-2 bg-bg-surface rounded border border-border-default\n ${onClick ? 'cursor-pointer hover:border-action-primary-bg' : ''}\n transition-colors\n `}\n onClick={() => onClick?.(task)}\n >\n <p className=\"text-xs font-medium text-text-primary line-clamp-2\">{task.title}</p>\n\n <div className=\"flex items-center gap-1 mt-2 flex-wrap\">\n {task.priority && (\n <span className={`px-1.5 py-0.5 text-[10px] rounded ${getPriorityColor(task.priority)}`}>\n {task.priority}\n </span>\n )}\n {task.assignee && (\n <span className=\"px-1.5 py-0.5 text-[10px] rounded bg-action-primary-bg/10 text-action-primary-text\">\n {task.assignee}\n </span>\n )}\n </div>\n </div>\n ))}\n\n {columnTasks.length === 0 && <p className=\"text-[10px] text-text-tertiary text-center py-4\">No tasks</p>}\n </div>\n </div>\n );\n })}\n </div>\n );\n});\n\nexport default KanbanWidget;\n"],"mappings":";;;AA4CA,SAAS,EAAiB,GAA2B;AACnD,SAAQ,GAAR;EACE,KAAK,OACH,QAAO;EACT,KAAK,SACH,QAAO;EACT,KAAK,MACH,QAAO;EACT,QACE,QAAO;;;AAQb,IAAa,IAAsC,EAAK,SAAsB,EAAE,QAAQ,GAAS,SAAM,cAAW;CAChH,IAAM,IAAU,QAAc,GAAM,WAAW,EAAE,EAAE,CAAC,GAAM,QAAQ,CAAC,EAC7D,IAAQ,QAAc,GAAM,SAAS,EAAE,EAAE,CAAC,GAAM,MAAM,CAAC,EAGvD,IAAgB,QAAc;EAClC,IAAM,IAAwC,EAAE;AAIhD,SAHA,EAAQ,SAAS,MAAQ;AACvB,KAAQ,EAAI,MAAM,EAAM,QAAQ,MAAM,EAAE,WAAW,EAAI,GAAG;IAC1D,EACK;IACN,CAAC,GAAS,EAAM,CAAC;AAyBpB,QAvBK,EAAQ,SAwBX,kBAAC,OAAD;EAAK,WAAU;YACZ,EAAQ,KAAK,MAAW;GACvB,IAAM,IAAc,EAAc,EAAO,OAAO,EAAE;AAElD,UACE,kBAAC,OAAD;IAAqB,WAAU;cAA/B,CAEE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD;OACE,WAAU;OACV,OAAO,EAAE,iBAAiB,EAAO,SAAS,2BAA2B;OACrE,CAAA;MACF,kBAAC,QAAD;OAAM,WAAU;iBAAkD,EAAO;OAAa,CAAA;MACtF,kBAAC,QAAD;OAAM,WAAU;iBAAsC,EAAY;OAAc,CAAA;MAC5E;QAGN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,EAAY,KAAK,MAChB,kBAAC,OAAD;MAEE,WAAW;;wBAEL,IAAU,kDAAkD,GAAG;;;MAGrE,eAAe,IAAU,EAAK;gBAPhC,CASE,kBAAC,KAAD;OAAG,WAAU;iBAAsD,EAAK;OAAU,CAAA,EAElF,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACG,EAAK,YACJ,kBAAC,QAAD;QAAM,WAAW,qCAAqC,EAAiB,EAAK,SAAS;kBAClF,EAAK;QACD,CAAA,EAER,EAAK,YACJ,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAK;QACD,CAAA,CAEL;SACF;QAtBC,EAAK,GAsBN,CACN,EAED,EAAY,WAAW,KAAK,kBAAC,KAAD;MAAG,WAAU;gBAAkD;MAAY,CAAA,CACpG;OACF;MA1CI,EAAO,GA0CX;IAER;EACE,CAAA,GAxEJ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IACE,WAAU;IACV,MAAK;IACL,QAAO;IACP,SAAQ;cAER,kBAAC,QAAD;KACE,eAAc;KACd,gBAAe;KACf,aAAa;KACb,GAAE;KACF,CAAA;IACE,CAAA,EACN,kBAAC,KAAD,EAAA,UAAG,iBAAiB,CAAA,CAChB;;EACF,CAAA;EAyDV"}
@@ -43,7 +43,7 @@ var i = e(function({ widget: e, data: i, onClick: a, onDrilldown: o }) {
43
43
  children: [
44
44
  /* @__PURE__ */ n("div", {
45
45
  className: "w-2 h-2 rounded-full",
46
- style: { backgroundColor: e.color || "#3b82f6" }
46
+ style: { backgroundColor: e.color || "var(--color-chart-1)" }
47
47
  }),
48
48
  /* @__PURE__ */ n("span", {
49
49
  className: "text-xs text-text-primary truncate max-w-[80px]",
@@ -71,7 +71,7 @@ var i = e(function({ widget: e, data: i, onClick: a, onDrilldown: o }) {
71
71
  className: "flex items-center gap-2",
72
72
  children: [/* @__PURE__ */ n("div", {
73
73
  className: "w-2 h-2 rounded-full flex-shrink-0",
74
- style: { backgroundColor: e.color || "#3b82f6" }
74
+ style: { backgroundColor: e.color || "var(--color-chart-1)" }
75
75
  }), /* @__PURE__ */ n("span", {
76
76
  className: "text-xs text-text-primary",
77
77
  children: e.name