@burdenoff/microfe-bigconsole 2026.812.1 → 2026.812.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/dist/bigconsole/components/widgets/PropertiesPanel.js +480 -473
  2. package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
  3. package/dist/bigconsole/components/widgets/WidgetRegistry.js +4 -4
  4. package/dist/bigconsole/components/widgets/WidgetRegistry.js.map +1 -1
  5. package/dist/bigconsole/components/widgets/gauge/CircularGauge.js +36 -32
  6. package/dist/bigconsole/components/widgets/gauge/CircularGauge.js.map +1 -1
  7. package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js +60 -50
  8. package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js.map +1 -1
  9. package/dist/bigconsole/components/widgets/gauge/GaugeWidget.js +63 -34
  10. package/dist/bigconsole/components/widgets/gauge/GaugeWidget.js.map +1 -1
  11. package/dist/bigconsole/components/widgets/gauge/LinearGauge.js +46 -45
  12. package/dist/bigconsole/components/widgets/gauge/LinearGauge.js.map +1 -1
  13. package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js +152 -89
  14. package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js.map +1 -1
  15. package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js +5 -1
  16. package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js.map +1 -1
  17. package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js +112 -89
  18. package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js.map +1 -1
  19. package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js +21 -13
  20. package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js.map +1 -1
  21. package/dist/bigconsole/components/widgets/metric-card/index.js +4 -4
  22. package/dist/bigconsole/components/widgets/progress/ProgressWidget.js +129 -114
  23. package/dist/bigconsole/components/widgets/progress/ProgressWidget.js.map +1 -1
  24. package/dist/bigconsole/components/widgets/utils/targetProgress.js +13 -0
  25. package/dist/bigconsole/components/widgets/utils/targetProgress.js.map +1 -0
  26. package/package.json +1 -1
@@ -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 /**\n * Default responsive position (v1.0 spec). `xl` is optional and falls back\n * to `lg` when not set so existing widget defaults remain valid.\n */\n defaultResponsive: { xs: number; sm: number; md: number; lg: number; xl?: 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 /**\n * Whether the widget honors rule-based conditional formatting\n * (`config.conditionalRules`). Drives which options the config UI shows.\n */\n supportsConditionalFormat?: boolean;\n /**\n * Whether the widget supports reference / threshold lines & bands\n * (`config.referenceLines`).\n */\n supportsThresholds?: boolean;\n /** Whether the widget supports a combo / dual-axis layout (`config.dualAxis`). */\n supportsDualAxis?: boolean;\n /** Whether the widget supports a totals/aggregate footer (`config.showTotals`). */\n supportsTotals?: 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 supportsConditionalFormat: 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 supportsConditionalFormat: 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 supportsConditionalFormat: true,\n supportsThresholds: true,\n supportsDualAxis: true,\n tags: ['chart', 'graph', 'visualization', 'line', 'bar', 'area', 'pie', 'combo', 'dual-axis'],\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 // ChartWidget dispatches on `chartType` and falls back to 'line' when it is\n // absent, so a palette-created funnel must seed it explicitly.\n chartType: 'funnel',\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 supportsConditionalFormat: true,\n supportsTotals: 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: true,\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 // Cohort / Retention (1 type)\n // ============================================================================\n\n retention: {\n type: 'retention',\n name: 'Retention / Cohort',\n description: 'Cohort-by-period retention grid with decay shading',\n icon: 'Grid3x3',\n category: 'Data',\n component: null,\n defaultConfig: {\n cohortField: 'cohort',\n periodField: 'period',\n valueField: 'value',\n periodType: 'month',\n showPercentages: true,\n showAverages: true,\n showLegend: true,\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: false,\n supportsAutoRefresh: true,\n tags: ['retention', 'cohort', 'grid', 'churn', 'saas'],\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":";AAwFA,IAAa,IAA2D;CAKtE,qBAAqB;EACnB,MAAM;EACN,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;EACV,WAAW;EACX,eAAe;GACb,aAAa,EAAE;GACf,gBAAgB;GAChB,QAAQ;GACR,QAAQ;GACT;EACD,aAAa;GAAE,OAAO;GAAG,QAAQ;GAAG;EACpC,mBAAmB;GAAE,IAAI;GAAI,IAAI;GAAG,IAAI;GAAG,IAAI;GAAG;EAClD,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,SAAS;GAAE,OAAO;GAAI,QAAQ;GAAG;EACjC,qBAAqB;EACrB,mBAAmB;EACnB,qBAAqB;EACrB,2BAA2B;EAC3B,MAAM;GAAC;GAAO;GAAc;GAAW;GAAQ;EAChD;CAED,aAAa;EACX,MAAM;EACN,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;EACV,WAAW;EACX,eAAe;GACb,QAAQ;GACR,eAAe;GACf,WAAW;GACX,eAAe;GAChB;EACD,aAAa;GAAE,OAAO;GAAG,QAAQ;GAAG;EACpC,mBAAmB;GAAE,IAAI;GAAI,IAAI;GAAG,IAAI;GAAG,IAAI;GAAG;EAClD,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,qBAAqB;EACrB,mBAAmB;EACnB,qBAAqB;EACrB,2BAA2B;EAC3B,MAAM;GAAC;GAAO;GAAU;GAAU;GAAQ;EAC3C;CAED,OAAO;EACL,MAAM;EACN,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;EACV,WAAW;EACX,eAAe;GACb,WAAW;GACX,YAAY;GACZ,gBAAgB;GAChB,UAAU;GACV,aAAa;GACd;EACD,aAAa;GAAE,OAAO;GAAG,QAAQ;GAAG;EACpC,mBAAmB;GAAE,IAAI;GAAI,IAAI;GAAI,IAAI;GAAG,IAAI;GAAG;EACnD,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,SAAS;GAAE,OAAO;GAAI,QAAQ;GAAG;EACjC,qBAAqB;EACrB,mBAAmB;EACnB,qBAAqB;EACrB,2BAA2B;EAC3B,oBAAoB;EACpB,kBAAkB;EAClB,MAAM;GAAC;GAAS;GAAS;GAAiB;GAAQ;GAAO;GAAQ;GAAO;GAAS;GAAY;EAC9F;CAED,cAAc;EACZ,MAAM;EACN,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;EACV,WAAW;EACX,eAAe;GAGb,WAAW;GACX,YAAY;GACZ,YAAY;GACZ,iBAAiB;GACjB,aAAa;GACd;EACD,aAAa;GAAE,OAAO;GAAG,QAAQ;GAAG;EACpC,mBAAmB;GAAE,IAAI;GAAI,IAAI;GAAG,IAAI;GAAG,IAAI;GAAG;EAClD,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAI;EACjC,qBAAqB;EACrB,mBAAmB;EACnB,qBAAqB;EACrB,MAAM;GAAC;GAAU;GAAc;GAAU;GAAW;EACrD;CAED,OAAO;EACL,MAAM;EACN,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;EACV,WAAW;EACX,eAAe;GACb,UAAU;GACV,UAAU;GACV,YAAY;GACZ,cAAc;GACd,SAAS,EAAE;GACZ;EACD,aAAa;GAAE,OAAO;GAAG,QAAQ;GAAG;EACpC,mBAAmB;GAAE,IAAI;GAAI,IAAI;GAAI,IAAI;GAAG,IAAI;GAAG;EACnD,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,SAAS;GAAE,OAAO;GAAI,QAAQ;GAAI;EAClC,qBAAqB;EACrB,mBAAmB;EACnB,qBAAqB;EACrB,2BAA2B;EAC3B,gBAAgB;EAChB,MAAM;GAAC;GAAS;GAAQ;GAAQ;GAAO;EACxC;CAED,aAAa;EACX,MAAM;EACN,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;EACV,WAAW;EACX,eAAe;GACb,MAAM,EAAE;GACR,SAAS,EAAE;GACX,QAAQ,EAAE;GACV,aAAa;GACb,YAAY;GACb;EACD,aAAa;GAAE,OAAO;GAAI,QAAQ;GAAG;EACrC,mBAAmB;GAAE,IAAI;GAAI,IAAI;GAAI,IAAI;GAAI,IAAI;GAAI;EACrD,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,SAAS;GAAE,OAAO;GAAI,QAAQ;GAAI;EAClC,qBAAqB;EACrB,mBAAmB;EACnB,qBAAqB;EACrB,MAAM;GAAC;GAAS;GAAS;GAAY;GAAc;EACpD;CAMD,OAAO;EACL,MAAM;EACN,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;EACV,WAAW;EACX,eAAe;GACb,SAAS;GACT,KAAK;GACL,KAAK;GACL,WAAW;GACX,YAAY;GACZ,YAAY;IACV;KAAE,OAAO;KAAI,OAAO;KAAO;IAC3B;KAAE,OAAO;KAAI,OAAO;KAAU;IAC9B;KAAE,OAAO;KAAK,OAAO;KAAS;IAC/B;GACF;EACD,aAAa;GAAE,OAAO;GAAG,QAAQ;GAAG;EACpC,mBAAmB;GAAE,IAAI;GAAG,IAAI;GAAG,IAAI;GAAG,IAAI;GAAG;EACjD,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,qBAAqB;EACrB,mBAAmB;EACnB,qBAAqB;EACrB,MAAM;GAAC;GAAS;GAAS;GAAQ;GAAY;EAC9C;CAED,UAAU;EACR,MAAM;EACN,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;EACV,WAAW;EACX,eAAe;GACb,gBAAgB;GAChB,WAAW;GACX,QAAQ;GACR,YAAY,EAAE;GACf;EACD,aAAa;GAAE,OAAO;GAAG,QAAQ;GAAG;EACpC,mBAAmB;GAAE,IAAI;GAAI,IAAI;GAAG,IAAI;GAAG,IAAI;GAAG;EAClD,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,SAAS;GAAE,OAAO;GAAI,QAAQ;GAAG;EACjC,qBAAqB;EACrB,mBAAmB;EACnB,qBAAqB;EACrB,MAAM;GAAC;GAAY;GAAO;GAAQ;GAAa;EAChD;CAMD,MAAM;EACJ,MAAM;EACN,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;EACV,WAAW;EACX,eAAe;GACb,cAAc;GACd,aAAa;GACb,YAAY;GACZ,UAAU;GACV,eAAe;GAChB;EACD,aAAa;GAAE,OAAO;GAAG,QAAQ;GAAG;EACpC,mBAAmB;GAAE,IAAI;GAAI,IAAI;GAAG,IAAI;GAAG,IAAI;GAAG;EAClD,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAI;EACjC,qBAAqB;EACrB,mBAAmB;EACnB,qBAAqB;EACrB,MAAM;GAAC;GAAQ;GAAS;GAAS;EAClC;CAED,MAAM;EACJ,MAAM;EACN,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;EACV,WAAW;EACX,eAAe;GACb,QAAQ,EAAE;GACV,cAAc;GACd,QAAQ;GACR,YAAY;GACb;EACD,aAAa;GAAE,OAAO;GAAG,QAAQ;GAAG;EACpC,mBAAmB;GAAE,IAAI;GAAI,IAAI;GAAI,IAAI;GAAG,IAAI;GAAG;EACnD,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,SAAS;GAAE,OAAO;GAAI,QAAQ;GAAI;EAClC,qBAAqB;EACrB,mBAAmB;EACnB,qBAAqB;EACrB,MAAM;GAAC;GAAQ;GAAS;GAAU;GAAS;EAC5C;CAMD,MAAM;EACJ,MAAM;EACN,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;EACV,WAAW;EACX,eAAe;GACb,SAAS;GACT,QAAQ;GACR,WAAW;GACZ;EACD,aAAa;GAAE,OAAO;GAAG,QAAQ;GAAG;EACpC,mBAAmB;GAAE,IAAI;GAAI,IAAI;GAAG,IAAI;GAAG,IAAI;GAAG;EAClD,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,SAAS;GAAE,OAAO;GAAI,QAAQ;GAAI;EAClC,qBAAqB;EACrB,mBAAmB;EACnB,qBAAqB;EACrB,MAAM;GAAC;GAAQ;GAAY;GAAW;GAAY;EACnD;CAED,QAAQ;EACN,MAAM;EACN,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;EACV,WAAW;EACX,eAAe;GACb,KAAK;GACL,SAAS;GACT,iBAAiB;GAClB;EACD,aAAa;GAAE,OAAO;GAAG,QAAQ;GAAG;EACpC,mBAAmB;GAAE,IAAI;GAAI,IAAI;GAAI,IAAI;GAAG,IAAI;GAAG;EACnD,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,SAAS;GAAE,OAAO;GAAI,QAAQ;GAAI;EAClC,qBAAqB;EACrB,mBAAmB;EACnB,qBAAqB;EACrB,MAAM;GAAC;GAAU;GAAS;GAAY;GAAM;EAC7C;CAMD,KAAK;EACH,MAAM;EACN,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;EACV,WAAW;EACX,eAAe;GACb,UAAU;GACV,QAAQ;IAAE,KAAK;IAAG,KAAK;IAAG;GAC1B,MAAM;GACN,aAAa;GACb,aAAa;GACd;EACD,aAAa;GAAE,OAAO;GAAG,QAAQ;GAAG;EACpC,mBAAmB;GAAE,IAAI;GAAI,IAAI;GAAI,IAAI;GAAG,IAAI;GAAG;EACnD,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,SAAS;GAAE,OAAO;GAAI,QAAQ;GAAI;EAClC,qBAAqB;EACrB,mBAAmB;EACnB,qBAAqB;EACrB,MAAM;GAAC;GAAO;GAAO;GAAY;GAAU;EAC5C;CAED,SAAS;EACP,MAAM;EACN,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;EACV,WAAW;EACX,eAAe;GACb,YAAY;GACZ,YAAY;GACZ,YAAY;GAIZ,YAAY,EAAE;GACd,aAAa;GACb,YAAY;GACb;EACD,aAAa;GAAE,OAAO;GAAG,QAAQ;GAAG;EACpC,mBAAmB;GAAE,IAAI;GAAI,IAAI;GAAI,IAAI;GAAG,IAAI;GAAG;EACnD,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,SAAS;GAAE,OAAO;GAAI,QAAQ;GAAI;EAClC,qBAAqB;EACrB,mBAAmB;EACnB,qBAAqB;EACrB,MAAM;GAAC;GAAW;GAAQ;GAAW;GAAQ;EAC9C;CAED,UAAU;EACR,MAAM;EACN,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;EACV,WAAW;EACX,eAAe;GACb,MAAM;GACN,iBAAiB;GACjB,gBAAgB;GAChB,YAAY;GACb;EACD,aAAa;GAAE,OAAO;GAAG,QAAQ;GAAG;EACpC,mBAAmB;GAAE,IAAI;GAAI,IAAI;GAAI,IAAI;GAAG,IAAI;GAAG;EACnD,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,SAAS;GAAE,OAAO;GAAI,QAAQ;GAAI;EAClC,qBAAqB;EACrB,mBAAmB;EACnB,qBAAqB;EACrB,MAAM;GAAC;GAAY;GAAU;GAAY;GAAQ;EAClD;CAED,QAAQ;EACN,MAAM;EACN,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;EACV,WAAW;EACX,eAAe;GACb,SAAS,EAAE;GACX,gBAAgB;GAChB,sBAAsB;GACtB,aAAa;GACb,eAAe;GAChB;EACD,aAAa;GAAE,OAAO;GAAI,QAAQ;GAAG;EACrC,mBAAmB;GAAE,IAAI;GAAI,IAAI;GAAI,IAAI;GAAI,IAAI;GAAI;EACrD,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,SAAS;GAAE,OAAO;GAAI,QAAQ;GAAI;EAClC,qBAAqB;EACrB,mBAAmB;EACnB,qBAAqB;EACrB,MAAM;GAAC;GAAU;GAAS;GAAS;GAAW;EAC/C;CAED,UAAU;EACR,MAAM;EACN,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;EACV,WAAW;EACX,eAAe;GACb,gBAAgB;GAChB,cAAc;GACd,YAAY;GACZ,YAAY;GACZ,WAAW;GACZ;EACD,aAAa;GAAE,OAAO;GAAI,QAAQ;GAAG;EACrC,mBAAmB;GAAE,IAAI;GAAI,IAAI;GAAI,IAAI;GAAI,IAAI;GAAI;EACrD,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,SAAS;GAAE,OAAO;GAAI,QAAQ;GAAI;EAClC,qBAAqB;EACrB,mBAAmB;EACnB,qBAAqB;EACrB,MAAM;GAAC;GAAY;GAAS;GAAW;GAAW;EACnD;CAMD,WAAW;EACT,MAAM;EACN,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;EACV,WAAW;EACX,eAAe;GACb,aAAa;GACb,aAAa;GACb,YAAY;GACZ,YAAY;GACZ,iBAAiB;GACjB,cAAc;GACd,YAAY;GACb;EACD,aAAa;GAAE,OAAO;GAAG,QAAQ;GAAG;EACpC,mBAAmB;GAAE,IAAI;GAAI,IAAI;GAAI,IAAI;GAAG,IAAI;GAAG;EACnD,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,SAAS;GAAE,OAAO;GAAI,QAAQ;GAAI;EAClC,qBAAqB;EACrB,mBAAmB;EACnB,qBAAqB;EACrB,MAAM;GAAC;GAAa;GAAU;GAAQ;GAAS;GAAO;EACvD;CAMD,QAAQ;EACN,MAAM;EACN,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;EACV,WAAW;EACX,eAAe;GACb,aAAa;GACb,OAAO,EAAE;GACV;EACD,aAAa;GAAE,OAAO;GAAG,QAAQ;GAAG;EACpC,mBAAmB;GAAE,IAAI;GAAI,IAAI;GAAG,IAAI;GAAG,IAAI;GAAG;EAClD,SAAS;GAAE,OAAO;GAAG,QAAQ;GAAG;EAChC,SAAS;GAAE,OAAO;GAAI,QAAQ;GAAI;EAClC,qBAAqB;EACrB,mBAAmB;EACnB,qBAAqB;EACrB,MAAM;GAAC;GAAU;GAAU;GAAY;EACxC;CACF,EASK,IAA8C;CAClD,MAAM;CACN,MAAM;CACN,aAAa;CACb,MAAM;CACN,UAAU;CACV,WAAW;CACX,eAAe,EAAE;CACjB,aAAa;EAAE,OAAO;EAAG,QAAQ;EAAG;CACpC,mBAAmB;EAAE,IAAI;EAAI,IAAI;EAAG,IAAI;EAAG,IAAI;EAAG;CAClD,SAAS;EAAE,OAAO;EAAG,QAAQ;EAAG;CAChC,SAAS;EAAE,OAAO;EAAI,QAAQ;EAAI;CAClC,qBAAqB;CACrB,mBAAmB;CACnB,qBAAqB;CACrB,MAAM,CAAC,UAAU;CAClB;AAMD,SAAgB,EAAoB,GAA6C;AAE/E,KAAI,EAAmB,GACrB,QAAO,EAAmB;CAI5B,IAAM,IAAY,EAAK,aAAa;AAMpC,QALI,EAAmB,KACd,EAAmB,KAIrB;EAAE,GAAG;EAAiC;EAAoB;;AAMnE,SAAgB,IAA8C;AAC5D,QAAO,OAAO,OAAO,EAAmB;;AAM1C,SAAgB,EAAqB,GAA8C;AACjF,QAAO,OAAO,OAAO,EAAmB,CAAC,QAAQ,MAAQ,EAAI,aAAa,EAAS;;AAoBrF,IAAa,IAAyD;CACpE,KAAK;CACL,eAAe;CACf,MAAM;CACN,SAAS;CACT,UAAU;CACV,QAAQ;CACR,WAAW;CACZ;AAKD,SAAgB,IAIZ;AAGF,QAFqC;EAAC;EAAO;EAAiB;EAAQ;EAAW;EAAY;EAAU;EAAY,CAEjG,KAAK,OAAc;EACnC;EACA,OAAO,EAAuB;EAC9B,SAAS,EAAqB,EAAS;EACxC,EAAE;;AA0BL,SAAgB,EAAa,GAAkC;AAO7D,QANI,EAAO,eAAe,cACjB,aAAa,EAAO,cAAc,gBAEvC,EAAO,aAAa,cACf,aAAa,EAAO,SAEtB,EAAO"}
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 /**\n * Default responsive position (v1.0 spec). `xl` is optional and falls back\n * to `lg` when not set so existing widget defaults remain valid.\n */\n defaultResponsive: { xs: number; sm: number; md: number; lg: number; xl?: 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 /**\n * Whether the widget honors rule-based conditional formatting\n * (`config.conditionalRules`). Drives which options the config UI shows.\n */\n supportsConditionalFormat?: boolean;\n /**\n * Whether the widget supports reference / threshold lines & bands\n * (`config.referenceLines`).\n */\n supportsThresholds?: boolean;\n /** Whether the widget supports a combo / dual-axis layout (`config.dualAxis`). */\n supportsDualAxis?: boolean;\n /** Whether the widget supports a totals/aggregate footer (`config.showTotals`). */\n supportsTotals?: 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 supportsConditionalFormat: 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 // 'auto' defers the numeric style to the payload's `isCurrency`, so a\n // parser emitting the documented MetricCardData contract renders as\n // currency without the user having to re-pick it in the Style tab.\n format: 'auto',\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 supportsConditionalFormat: 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 supportsConditionalFormat: true,\n supportsThresholds: true,\n supportsDualAxis: true,\n tags: ['chart', 'graph', 'visualization', 'line', 'bar', 'area', 'pie', 'combo', 'dual-axis'],\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 // ChartWidget dispatches on `chartType` and falls back to 'line' when it is\n // absent, so a palette-created funnel must seed it explicitly.\n chartType: 'funnel',\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 supportsConditionalFormat: true,\n supportsTotals: 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 // Semantic threshold vocabulary — matches what the Gauge inspector\n // writes (GaugeConfig.tsx) and what GaugeWidget maps onto fe-libs\n // `--color-status-*` tokens. Raw colour names are not permitted in UI.\n thresholds: [\n { value: 33, color: 'error' },\n { value: 66, color: 'warning' },\n { value: 100, color: 'success' },\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: true,\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 // Cohort / Retention (1 type)\n // ============================================================================\n\n retention: {\n type: 'retention',\n name: 'Retention / Cohort',\n description: 'Cohort-by-period retention grid with decay shading',\n icon: 'Grid3x3',\n category: 'Data',\n component: null,\n defaultConfig: {\n cohortField: 'cohort',\n periodField: 'period',\n valueField: 'value',\n periodType: 'month',\n showPercentages: true,\n showAverages: true,\n showLegend: true,\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: false,\n supportsAutoRefresh: true,\n tags: ['retention', 'cohort', 'grid', 'churn', 'saas'],\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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"}
@@ -2,76 +2,80 @@ import { memo as e, useMemo as t } from "react";
2
2
  import { jsx as n, jsxs as r } from "react/jsx-runtime";
3
3
  //#region src/bigconsole/components/widgets/gauge/CircularGauge.tsx
4
4
  function i(e, t) {
5
+ let n = t - e;
6
+ return Number.isFinite(n) && n > 0 ? n : 1;
7
+ }
8
+ function a(e, t) {
5
9
  if (!t?.length) return "var(--color-action-primary-bg)";
6
10
  let n = [...t].sort((e, t) => e.value - t.value);
7
11
  for (let t of n) if (e <= t.value) return t.color;
8
12
  return n[n.length - 1].color;
9
13
  }
10
- var a = e(function({ value: e, min: a = 0, max: o = 100, size: s = 120, strokeWidth: c = 12, thresholds: l, unit: u, showValue: d = !0, formatValue: f = (e) => e.toFixed(0) }) {
11
- let p = t(() => {
12
- let t = (s - c) / 2, n = t * Math.PI * 2, r = -225;
14
+ var o = e(function({ value: e, min: o = 0, max: s = 100, size: c = 120, strokeWidth: l = 12, thresholds: u, unit: d, showValue: f = !0, formatValue: p = (e) => e.toFixed(0) }) {
15
+ let m = t(() => {
16
+ let t = (c - l) / 2, n = t * Math.PI * 2, r = -225;
13
17
  45 - r;
14
- let i = (Math.max(a, Math.min(o, e)) - a) / (o - a);
18
+ let a = (Math.max(o, Math.min(s, e)) - o) / i(o, s);
15
19
  return {
16
20
  radius: t,
17
21
  circumference: n,
18
- arcLength: i * 270 / 360 * n,
22
+ arcLength: a * 270 / 360 * n,
19
23
  backgroundArcLength: 270 / 360 * n,
20
24
  startAngle: r,
21
- percentage: i
25
+ percentage: a
22
26
  };
23
27
  }, [
24
- s,
25
28
  c,
29
+ l,
26
30
  e,
27
- a,
28
- o
29
- ]), m = i(e, l);
31
+ o,
32
+ s
33
+ ]), h = a(e, u);
30
34
  return /* @__PURE__ */ r("div", {
31
35
  className: "relative inline-flex items-center justify-center",
32
36
  style: {
33
- width: s,
34
- height: s
37
+ width: c,
38
+ height: c
35
39
  },
36
40
  children: [/* @__PURE__ */ r("svg", {
37
- width: s,
38
- height: s,
39
- viewBox: `0 0 ${s} ${s}`,
41
+ width: c,
42
+ height: c,
43
+ viewBox: `0 0 ${c} ${c}`,
40
44
  className: "transform -rotate-135",
41
45
  children: [/* @__PURE__ */ n("circle", {
42
- cx: s / 2,
43
- cy: s / 2,
44
- r: p.radius,
46
+ cx: c / 2,
47
+ cy: c / 2,
48
+ r: m.radius,
45
49
  fill: "none",
46
50
  stroke: "var(--color-border-default)",
47
- strokeWidth: c,
51
+ strokeWidth: l,
48
52
  strokeLinecap: "round",
49
- strokeDasharray: `${p.backgroundArcLength} ${p.circumference}`
53
+ strokeDasharray: `${m.backgroundArcLength} ${m.circumference}`
50
54
  }), /* @__PURE__ */ n("circle", {
51
- cx: s / 2,
52
- cy: s / 2,
53
- r: p.radius,
55
+ cx: c / 2,
56
+ cy: c / 2,
57
+ r: m.radius,
54
58
  fill: "none",
55
- stroke: m,
56
- strokeWidth: c,
59
+ stroke: h,
60
+ strokeWidth: l,
57
61
  strokeLinecap: "round",
58
- strokeDasharray: `${p.arcLength} ${p.circumference}`,
62
+ strokeDasharray: `${m.arcLength} ${m.circumference}`,
59
63
  className: "transition-all duration-500 ease-out"
60
64
  })]
61
- }), d && /* @__PURE__ */ r("div", {
65
+ }), f && /* @__PURE__ */ r("div", {
62
66
  className: "absolute inset-0 flex flex-col items-center justify-center",
63
67
  children: [/* @__PURE__ */ n("span", {
64
68
  className: "text-2xl font-bold text-text-primary",
65
- style: { color: m },
66
- children: f(e)
67
- }), u && /* @__PURE__ */ n("span", {
69
+ style: { color: h },
70
+ children: p(e)
71
+ }), d && /* @__PURE__ */ n("span", {
68
72
  className: "text-xs text-text-secondary",
69
- children: u
73
+ children: d
70
74
  })]
71
75
  })]
72
76
  });
73
77
  });
74
78
  //#endregion
75
- export { a as default };
79
+ export { o as default, i as gaugeSpan };
76
80
 
77
81
  //# sourceMappingURL=CircularGauge.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CircularGauge.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/gauge/CircularGauge.tsx"],"sourcesContent":["/**\n * CircularGauge Component\n *\n * Circular gauge visualization with arc and value display.\n */\n\nimport { type FC, memo, useMemo } from 'react';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ThresholdConfig {\n /** Threshold value */\n value: number;\n /** Color for values up to this threshold */\n color: string;\n}\n\nexport interface CircularGaugeProps {\n /** Current value */\n value: number;\n /** Minimum value */\n min?: number;\n /** Maximum value */\n max?: number;\n /** Size of the gauge */\n size?: number;\n /** Stroke width of the arc */\n strokeWidth?: number;\n /** Thresholds for color zones */\n thresholds?: ThresholdConfig[];\n /** Unit label */\n unit?: string;\n /** Whether to show the value */\n showValue?: boolean;\n /** Value format function */\n formatValue?: (value: number) => string;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction getColorForValue(value: number, thresholds?: ThresholdConfig[]): string {\n if (!thresholds?.length) {\n return 'var(--color-action-primary-bg)';\n }\n\n // Sort thresholds by value\n const sorted = [...thresholds].sort((a, b) => a.value - b.value);\n\n for (const threshold of sorted) {\n if (value <= threshold.value) {\n return threshold.color;\n }\n }\n\n // Return last threshold color if above all\n return sorted[sorted.length - 1].color;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const CircularGauge: FC<CircularGaugeProps> = memo(function CircularGauge({\n value,\n min = 0,\n max = 100,\n size = 120,\n strokeWidth = 12,\n thresholds,\n unit,\n showValue = true,\n formatValue = (v: number) => v.toFixed(0),\n}) {\n // Calculate arc geometry\n const geometry = useMemo(() => {\n const radius = (size - strokeWidth) / 2;\n const circumference = radius * Math.PI * 2;\n const startAngle = -225; // Start from bottom-left\n const endAngle = 45; // End at bottom-right\n const totalAngle = endAngle - startAngle; // 270 degrees\n\n // Clamp value to range\n const clampedValue = Math.max(min, Math.min(max, value));\n const percentage = (clampedValue - min) / (max - min);\n const angle = percentage * totalAngle;\n\n // Calculate arc path\n const arcLength = (angle / 360) * circumference;\n const backgroundArcLength = (totalAngle / 360) * circumference;\n\n return {\n radius,\n circumference,\n arcLength,\n backgroundArcLength,\n startAngle,\n percentage,\n };\n }, [size, strokeWidth, value, min, max]);\n\n const color = getColorForValue(value, thresholds);\n\n return (\n <div className=\"relative inline-flex items-center justify-center\" style={{ width: size, height: size }}>\n <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} className=\"transform -rotate-135\">\n {/* Background arc */}\n <circle\n cx={size / 2}\n cy={size / 2}\n r={geometry.radius}\n fill=\"none\"\n stroke=\"var(--color-border-default)\"\n strokeWidth={strokeWidth}\n strokeLinecap=\"round\"\n strokeDasharray={`${geometry.backgroundArcLength} ${geometry.circumference}`}\n />\n\n {/* Value arc */}\n <circle\n cx={size / 2}\n cy={size / 2}\n r={geometry.radius}\n fill=\"none\"\n stroke={color}\n strokeWidth={strokeWidth}\n strokeLinecap=\"round\"\n strokeDasharray={`${geometry.arcLength} ${geometry.circumference}`}\n className=\"transition-all duration-500 ease-out\"\n />\n </svg>\n\n {/* Center content */}\n {showValue && (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center\">\n <span className=\"text-2xl font-bold text-text-primary\" style={{ color }}>\n {formatValue(value)}\n </span>\n {unit && <span className=\"text-xs text-text-secondary\">{unit}</span>}\n </div>\n )}\n </div>\n );\n});\n\nexport default CircularGauge;\n"],"mappings":";;;AA4CA,SAAS,EAAiB,GAAe,GAAwC;AAC/E,KAAI,CAAC,GAAY,OACf,QAAO;CAIT,IAAM,IAAS,CAAC,GAAG,EAAW,CAAC,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM;AAEhE,MAAK,IAAM,KAAa,EACtB,KAAI,KAAS,EAAU,MACrB,QAAO,EAAU;AAKrB,QAAO,EAAO,EAAO,SAAS,GAAG;;AAOnC,IAAa,IAAwC,EAAK,SAAuB,EAC/E,UACA,SAAM,GACN,SAAM,KACN,UAAO,KACP,iBAAc,IACd,eACA,SACA,eAAY,IACZ,kBAAe,MAAc,EAAE,QAAQ,EAAE,IACxC;CAED,IAAM,IAAW,QAAc;EAC7B,IAAM,KAAU,IAAO,KAAe,GAChC,IAAgB,IAAS,KAAK,KAAK,GACnC,IAAa;AACF,OACa;EAJ9B,IAQM,KADe,KAAK,IAAI,GAAK,KAAK,IAAI,GAAK,EAAM,CAAC,GACrB,MAAQ,IAAM;AAOjD,SAAO;GACL;GACA;GACA,WATY,IAAa,MAGA,MAAO;GAOhC,qBAN2B,MAAa,MAAO;GAO/C;GACA;GACD;IACA;EAAC;EAAM;EAAa;EAAO;EAAK;EAAI,CAAC,EAElC,IAAQ,EAAiB,GAAO,EAAW;AAEjD,QACE,kBAAC,OAAD;EAAK,WAAU;EAAmD,OAAO;GAAE,OAAO;GAAM,QAAQ;GAAM;YAAtG,CACE,kBAAC,OAAD;GAAK,OAAO;GAAM,QAAQ;GAAM,SAAS,OAAO,EAAK,GAAG;GAAQ,WAAU;aAA1E,CAEE,kBAAC,UAAD;IACE,IAAI,IAAO;IACX,IAAI,IAAO;IACX,GAAG,EAAS;IACZ,MAAK;IACL,QAAO;IACM;IACb,eAAc;IACd,iBAAiB,GAAG,EAAS,oBAAoB,GAAG,EAAS;IAC7D,CAAA,EAGF,kBAAC,UAAD;IACE,IAAI,IAAO;IACX,IAAI,IAAO;IACX,GAAG,EAAS;IACZ,MAAK;IACL,QAAQ;IACK;IACb,eAAc;IACd,iBAAiB,GAAG,EAAS,UAAU,GAAG,EAAS;IACnD,WAAU;IACV,CAAA,CACE;MAGL,KACC,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,QAAD;IAAM,WAAU;IAAuC,OAAO,EAAE,UAAO;cACpE,EAAY,EAAM;IACd,CAAA,EACN,KAAQ,kBAAC,QAAD;IAAM,WAAU;cAA+B;IAAY,CAAA,CAChE;KAEJ;;EAER"}
1
+ {"version":3,"file":"CircularGauge.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/gauge/CircularGauge.tsx"],"sourcesContent":["/**\n * CircularGauge Component\n *\n * Circular gauge visualization with arc and value display.\n */\n\nimport { type FC, memo, useMemo } from 'react';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ThresholdConfig {\n /** Threshold value */\n value: number;\n /** Color for values up to this threshold */\n color: string;\n}\n\nexport interface CircularGaugeProps {\n /** Current value */\n value: number;\n /** Minimum value */\n min?: number;\n /** Maximum value */\n max?: number;\n /** Size of the gauge */\n size?: number;\n /** Stroke width of the arc */\n strokeWidth?: number;\n /** Thresholds for color zones */\n thresholds?: ThresholdConfig[];\n /** Unit label */\n unit?: string;\n /** Whether to show the value */\n showValue?: boolean;\n /** Value format function */\n formatValue?: (value: number) => string;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Width of the gauge range.\n *\n * A degenerate range (`min === max`, or an inverted one) makes every ratio\n * `NaN`/`Infinity`, which React emits as `stroke-dasharray=\"NaN …\"` or\n * `width: NaN%` — both invalid, so the browser drops the declaration and the\n * gauge renders unpredictably. Falling back to 1 makes the gauge read at its\n * minimum instead. Mirrors the `max - min || 1` guard already used by\n * HeatmapWidget, SparklineChart and MapWidget.\n */\nexport function gaugeSpan(min: number, max: number): number {\n const span = max - min;\n return Number.isFinite(span) && span > 0 ? span : 1;\n}\n\nfunction getColorForValue(value: number, thresholds?: ThresholdConfig[]): string {\n if (!thresholds?.length) {\n return 'var(--color-action-primary-bg)';\n }\n\n // Sort thresholds by value\n const sorted = [...thresholds].sort((a, b) => a.value - b.value);\n\n for (const threshold of sorted) {\n if (value <= threshold.value) {\n return threshold.color;\n }\n }\n\n // Return last threshold color if above all\n return sorted[sorted.length - 1].color;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const CircularGauge: FC<CircularGaugeProps> = memo(function CircularGauge({\n value,\n min = 0,\n max = 100,\n size = 120,\n strokeWidth = 12,\n thresholds,\n unit,\n showValue = true,\n formatValue = (v: number) => v.toFixed(0),\n}) {\n // Calculate arc geometry\n const geometry = useMemo(() => {\n const radius = (size - strokeWidth) / 2;\n const circumference = radius * Math.PI * 2;\n const startAngle = -225; // Start from bottom-left\n const endAngle = 45; // End at bottom-right\n const totalAngle = endAngle - startAngle; // 270 degrees\n\n // Clamp value to range\n const clampedValue = Math.max(min, Math.min(max, value));\n const percentage = (clampedValue - min) / gaugeSpan(min, max);\n const angle = percentage * totalAngle;\n\n // Calculate arc path\n const arcLength = (angle / 360) * circumference;\n const backgroundArcLength = (totalAngle / 360) * circumference;\n\n return {\n radius,\n circumference,\n arcLength,\n backgroundArcLength,\n startAngle,\n percentage,\n };\n }, [size, strokeWidth, value, min, max]);\n\n const color = getColorForValue(value, thresholds);\n\n return (\n <div className=\"relative inline-flex items-center justify-center\" style={{ width: size, height: size }}>\n <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} className=\"transform -rotate-135\">\n {/* Background arc */}\n <circle\n cx={size / 2}\n cy={size / 2}\n r={geometry.radius}\n fill=\"none\"\n stroke=\"var(--color-border-default)\"\n strokeWidth={strokeWidth}\n strokeLinecap=\"round\"\n strokeDasharray={`${geometry.backgroundArcLength} ${geometry.circumference}`}\n />\n\n {/* Value arc */}\n <circle\n cx={size / 2}\n cy={size / 2}\n r={geometry.radius}\n fill=\"none\"\n stroke={color}\n strokeWidth={strokeWidth}\n strokeLinecap=\"round\"\n strokeDasharray={`${geometry.arcLength} ${geometry.circumference}`}\n className=\"transition-all duration-500 ease-out\"\n />\n </svg>\n\n {/* Center content */}\n {showValue && (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center\">\n <span className=\"text-2xl font-bold text-text-primary\" style={{ color }}>\n {formatValue(value)}\n </span>\n {unit && <span className=\"text-xs text-text-secondary\">{unit}</span>}\n </div>\n )}\n </div>\n );\n});\n\nexport default CircularGauge;\n"],"mappings":";;;AAsDA,SAAgB,EAAU,GAAa,GAAqB;CAC1D,IAAM,IAAO,IAAM;AACnB,QAAO,OAAO,SAAS,EAAK,IAAI,IAAO,IAAI,IAAO;;AAGpD,SAAS,EAAiB,GAAe,GAAwC;AAC/E,KAAI,CAAC,GAAY,OACf,QAAO;CAIT,IAAM,IAAS,CAAC,GAAG,EAAW,CAAC,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM;AAEhE,MAAK,IAAM,KAAa,EACtB,KAAI,KAAS,EAAU,MACrB,QAAO,EAAU;AAKrB,QAAO,EAAO,EAAO,SAAS,GAAG;;AAOnC,IAAa,IAAwC,EAAK,SAAuB,EAC/E,UACA,SAAM,GACN,SAAM,KACN,UAAO,KACP,iBAAc,IACd,eACA,SACA,eAAY,IACZ,kBAAe,MAAc,EAAE,QAAQ,EAAE,IACxC;CAED,IAAM,IAAW,QAAc;EAC7B,IAAM,KAAU,IAAO,KAAe,GAChC,IAAgB,IAAS,KAAK,KAAK,GACnC,IAAa;AACF,OACa;EAJ9B,IAQM,KADe,KAAK,IAAI,GAAK,KAAK,IAAI,GAAK,EAAM,CAAC,GACrB,KAAO,EAAU,GAAK,EAAI;AAO7D,SAAO;GACL;GACA;GACA,WATY,IAAa,MAGA,MAAO;GAOhC,qBAN2B,MAAa,MAAO;GAO/C;GACA;GACD;IACA;EAAC;EAAM;EAAa;EAAO;EAAK;EAAI,CAAC,EAElC,IAAQ,EAAiB,GAAO,EAAW;AAEjD,QACE,kBAAC,OAAD;EAAK,WAAU;EAAmD,OAAO;GAAE,OAAO;GAAM,QAAQ;GAAM;YAAtG,CACE,kBAAC,OAAD;GAAK,OAAO;GAAM,QAAQ;GAAM,SAAS,OAAO,EAAK,GAAG;GAAQ,WAAU;aAA1E,CAEE,kBAAC,UAAD;IACE,IAAI,IAAO;IACX,IAAI,IAAO;IACX,GAAG,EAAS;IACZ,MAAK;IACL,QAAO;IACM;IACb,eAAc;IACd,iBAAiB,GAAG,EAAS,oBAAoB,GAAG,EAAS;IAC7D,CAAA,EAGF,kBAAC,UAAD;IACE,IAAI,IAAO;IACX,IAAI,IAAO;IACX,GAAG,EAAS;IACZ,MAAK;IACL,QAAQ;IACK;IACb,eAAc;IACd,iBAAiB,GAAG,EAAS,UAAU,GAAG,EAAS;IACnD,WAAU;IACV,CAAA,CACE;MAGL,KACC,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,QAAD;IAAM,WAAU;IAAuC,OAAO,EAAE,UAAO;cACpE,EAAY,EAAM;IACd,CAAA,EACN,KAAQ,kBAAC,QAAD;IAAM,WAAU;cAA+B;IAAY,CAAA,CAChE;KAEJ;;EAER"}
@@ -2,91 +2,119 @@ import { memo as e, useCallback as t } from "react";
2
2
  import { useI18n as n } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
3
3
  import { jsx as r, jsxs as i } from "react/jsx-runtime";
4
4
  //#region src/bigconsole/components/widgets/gauge/GaugeConfig.tsx
5
- var a = e(function({ config: e, onChange: a }) {
6
- let { t: o } = n(), s = t((t, n) => {
7
- a({
5
+ var a = [
6
+ {
7
+ value: 33,
8
+ color: "error"
9
+ },
10
+ {
11
+ value: 66,
12
+ color: "warning"
13
+ },
14
+ {
15
+ value: 100,
16
+ color: "success"
17
+ }
18
+ ], o = e(function({ config: e, onChange: o }) {
19
+ let { t: s } = n(), c = t((t, n) => {
20
+ o({
8
21
  ...e,
9
22
  [t]: n
10
23
  });
11
- }, [e, a]);
24
+ }, [e, o]), l = t((t, n) => {
25
+ let r = [];
26
+ for (let n = 0; n <= t; n++) r[n] = e.thresholds?.[n] ?? a[n] ?? {
27
+ value: 100,
28
+ color: "success"
29
+ };
30
+ r[t] = {
31
+ ...r[t],
32
+ value: Number(n)
33
+ };
34
+ for (let n = t + 1; n < (e.thresholds?.length ?? 0); n++) r[n] = e.thresholds?.[n] ?? {
35
+ value: 100,
36
+ color: "success"
37
+ };
38
+ c("thresholds", r);
39
+ }, [e.thresholds, c]);
12
40
  return /* @__PURE__ */ i("div", {
13
41
  className: "min-w-0 space-y-form-gap",
14
42
  children: [
15
43
  /* @__PURE__ */ i("div", { children: [/* @__PURE__ */ r("label", {
16
44
  className: "block text-sm font-medium text-text-primary mb-1",
17
- children: o("bigconsole.widget.config.gauge.gaugeType", "Gauge Type")
45
+ children: s("bigconsole.widget.config.gauge.gaugeType", "Gauge Type")
18
46
  }), /* @__PURE__ */ i("select", {
19
47
  value: e.variant || "circular",
20
- onChange: (e) => s("variant", e.target.value),
48
+ onChange: (e) => c("variant", e.target.value),
21
49
  className: "\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n ",
22
50
  children: [/* @__PURE__ */ r("option", {
23
51
  value: "circular",
24
- children: o("bigconsole.widget.config.gauge.variant.circular", "Circular")
52
+ children: s("bigconsole.widget.config.gauge.variant.circular", "Circular")
25
53
  }), /* @__PURE__ */ r("option", {
26
54
  value: "linear",
27
- children: o("bigconsole.widget.config.gauge.variant.linear", "Linear")
55
+ children: s("bigconsole.widget.config.gauge.variant.linear", "Linear")
28
56
  })]
29
57
  })] }),
30
58
  /* @__PURE__ */ i("div", {
31
59
  className: "grid grid-cols-1 gap-3 sm:grid-cols-2",
32
60
  children: [/* @__PURE__ */ i("div", { children: [/* @__PURE__ */ r("label", {
33
61
  className: "block text-sm font-medium text-text-primary mb-1",
34
- children: o("bigconsole.widget.config.gauge.minimum", "Minimum")
62
+ children: s("bigconsole.widget.config.gauge.minimum", "Minimum")
35
63
  }), /* @__PURE__ */ r("input", {
36
64
  type: "number",
37
65
  value: e.min ?? 0,
38
- onChange: (e) => s("min", Number(e.target.value)),
66
+ onChange: (e) => c("min", Number(e.target.value)),
39
67
  className: "\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n "
40
68
  })] }), /* @__PURE__ */ i("div", { children: [/* @__PURE__ */ r("label", {
41
69
  className: "block text-sm font-medium text-text-primary mb-1",
42
- children: o("bigconsole.widget.config.gauge.maximum", "Maximum")
70
+ children: s("bigconsole.widget.config.gauge.maximum", "Maximum")
43
71
  }), /* @__PURE__ */ r("input", {
44
72
  type: "number",
45
73
  value: e.max ?? 100,
46
- onChange: (e) => s("max", Number(e.target.value)),
74
+ onChange: (e) => c("max", Number(e.target.value)),
47
75
  className: "\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n "
48
76
  })] })]
49
77
  }),
50
78
  /* @__PURE__ */ i("div", { children: [/* @__PURE__ */ r("label", {
51
79
  className: "block text-sm font-medium text-text-primary mb-1",
52
- children: o("bigconsole.widget.config.gauge.unitLabel", "Unit Label")
80
+ children: s("bigconsole.widget.config.gauge.unitLabel", "Unit Label")
53
81
  }), /* @__PURE__ */ r("input", {
54
82
  type: "text",
55
83
  value: e.unit || "",
56
- onChange: (e) => s("unit", e.target.value),
57
- placeholder: o("bigconsole.widget.config.gauge.unitPlaceholder", "e.g., %, ms, users"),
84
+ onChange: (e) => c("unit", e.target.value),
85
+ placeholder: s("bigconsole.widget.config.gauge.unitPlaceholder", "e.g., %, ms, users"),
58
86
  className: "\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n "
59
87
  })] }),
60
88
  /* @__PURE__ */ i("div", { children: [/* @__PURE__ */ r("label", {
61
89
  className: "block text-sm font-medium text-text-primary mb-1",
62
- children: o("bigconsole.widget.config.gauge.valueFormat", "Value Format")
90
+ children: s("bigconsole.widget.config.gauge.valueFormat", "Value Format")
63
91
  }), /* @__PURE__ */ i("select", {
64
92
  value: e.format || "number",
65
- onChange: (e) => s("format", e.target.value),
93
+ onChange: (e) => c("format", e.target.value),
66
94
  className: "\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n ",
67
95
  children: [
68
96
  /* @__PURE__ */ r("option", {
69
97
  value: "number",
70
- children: o("bigconsole.widget.config.gauge.format.number", "Number")
98
+ children: s("bigconsole.widget.config.gauge.format.number", "Number")
71
99
  }),
72
100
  /* @__PURE__ */ r("option", {
73
101
  value: "percentage",
74
- children: o("bigconsole.widget.config.gauge.format.percentage", "Percentage")
102
+ children: s("bigconsole.widget.config.gauge.format.percentage", "Percentage")
75
103
  }),
76
104
  /* @__PURE__ */ r("option", {
77
105
  value: "currency",
78
- children: o("bigconsole.widget.config.gauge.format.currency", "Currency")
106
+ children: s("bigconsole.widget.config.gauge.format.currency", "Currency")
79
107
  })
80
108
  ]
81
109
  })] }),
82
110
  /* @__PURE__ */ i("div", { children: [
83
111
  /* @__PURE__ */ r("label", {
84
112
  className: "block text-sm font-medium text-text-primary mb-2",
85
- children: o("bigconsole.widget.config.gauge.colorThresholds", "Color Thresholds")
113
+ children: s("bigconsole.widget.config.gauge.colorThresholds", "Color Thresholds")
86
114
  }),
87
115
  /* @__PURE__ */ r("p", {
88
116
  className: "text-xs text-text-secondary mb-3",
89
- children: o("bigconsole.widget.config.gauge.colorThresholdsHelp", "Define color zones based on value ranges. Values up to each threshold will use that color.")
117
+ children: s("bigconsole.widget.config.gauge.colorThresholdsHelp", "Define color zones based on value ranges. Values up to each threshold will use that color.")
90
118
  }),
91
119
  /* @__PURE__ */ i("div", {
92
120
  className: "space-y-2",
@@ -97,18 +125,12 @@ var a = e(function({ config: e, onChange: a }) {
97
125
  /* @__PURE__ */ r("div", { className: "w-4 h-4 rounded bg-status-error-bg" }),
98
126
  /* @__PURE__ */ r("span", {
99
127
  className: "text-sm text-text-primary flex-1",
100
- children: o("bigconsole.widget.config.gauge.threshold.danger", "Danger (Red)")
128
+ children: s("bigconsole.widget.config.gauge.threshold.danger", "Danger (Red)")
101
129
  }),
102
130
  /* @__PURE__ */ r("input", {
103
131
  type: "number",
104
132
  value: e.thresholds?.[0]?.value ?? 33,
105
- onChange: (t) => {
106
- let n = [...e.thresholds || []];
107
- n[0] = {
108
- value: Number(t.target.value),
109
- color: "error"
110
- }, s("thresholds", n);
111
- },
133
+ onChange: (e) => l(0, e.target.value),
112
134
  className: "\n w-20 px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n "
113
135
  })
114
136
  ]
@@ -119,18 +141,12 @@ var a = e(function({ config: e, onChange: a }) {
119
141
  /* @__PURE__ */ r("div", { className: "w-4 h-4 rounded bg-status-warning-bg" }),
120
142
  /* @__PURE__ */ r("span", {
121
143
  className: "text-sm text-text-primary flex-1",
122
- children: o("bigconsole.widget.config.gauge.threshold.warning", "Warning (Yellow)")
144
+ children: s("bigconsole.widget.config.gauge.threshold.warning", "Warning (Yellow)")
123
145
  }),
124
146
  /* @__PURE__ */ r("input", {
125
147
  type: "number",
126
148
  value: e.thresholds?.[1]?.value ?? 66,
127
- onChange: (t) => {
128
- let n = [...e.thresholds || []];
129
- n[1] = {
130
- value: Number(t.target.value),
131
- color: "warning"
132
- }, s("thresholds", n);
133
- },
149
+ onChange: (e) => l(1, e.target.value),
134
150
  className: "\n w-20 px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n "
135
151
  })
136
152
  ]
@@ -141,18 +157,12 @@ var a = e(function({ config: e, onChange: a }) {
141
157
  /* @__PURE__ */ r("div", { className: "w-4 h-4 rounded bg-status-success-bg" }),
142
158
  /* @__PURE__ */ r("span", {
143
159
  className: "text-sm text-text-primary flex-1",
144
- children: o("bigconsole.widget.config.gauge.threshold.good", "Good (Green)")
160
+ children: s("bigconsole.widget.config.gauge.threshold.good", "Good (Green)")
145
161
  }),
146
162
  /* @__PURE__ */ r("input", {
147
163
  type: "number",
148
164
  value: e.thresholds?.[2]?.value ?? 100,
149
- onChange: (t) => {
150
- let n = [...e.thresholds || []];
151
- n[2] = {
152
- value: Number(t.target.value),
153
- color: "success"
154
- }, s("thresholds", n);
155
- },
165
+ onChange: (e) => l(2, e.target.value),
156
166
  className: "\n w-20 px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n "
157
167
  })
158
168
  ]
@@ -174,16 +184,16 @@ var a = e(function({ config: e, onChange: a }) {
174
184
  children: [/* @__PURE__ */ r("input", {
175
185
  type: "checkbox",
176
186
  checked: e.showZones === !0,
177
- onChange: (e) => s("showZones", e.target.checked),
187
+ onChange: (e) => c("showZones", e.target.checked),
178
188
  className: "\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n "
179
189
  }), /* @__PURE__ */ r("span", {
180
190
  className: "text-sm text-text-primary",
181
- children: o("bigconsole.widget.config.gauge.showZones", "Show color zones in background")
191
+ children: s("bigconsole.widget.config.gauge.showZones", "Show color zones in background")
182
192
  })]
183
193
  }),
184
194
  e.variant !== "linear" && /* @__PURE__ */ r("p", {
185
195
  className: "text-xs text-text-secondary",
186
- children: o("bigconsole.widget.config.gauge.noCircularOptions", "No display options for the circular gauge.")
196
+ children: s("bigconsole.widget.config.gauge.noCircularOptions", "No display options for the circular gauge.")
187
197
  })
188
198
  ]
189
199
  })
@@ -191,6 +201,6 @@ var a = e(function({ config: e, onChange: a }) {
191
201
  });
192
202
  });
193
203
  //#endregion
194
- export { a as default };
204
+ export { o as default };
195
205
 
196
206
  //# sourceMappingURL=GaugeConfig.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"GaugeConfig.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/gauge/GaugeConfig.tsx"],"sourcesContent":["/**\n * GaugeConfig Component\n *\n * Configuration panel for Gauge widgets.\n */\n\nimport { type FC, memo, useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport type { GaugeConfig as ConfigType } from '../../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface GaugeConfigProps {\n /** Current configuration */\n config: ConfigType;\n /** Callback when config changes */\n onChange: (config: ConfigType) => void;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const GaugeConfig: FC<GaugeConfigProps> = memo(function GaugeConfig({ config, onChange }) {\n const { t } = useI18n();\n const handleChange = useCallback(\n <K extends keyof ConfigType>(key: K, value: ConfigType[K]) => {\n onChange({ ...config, [key]: value });\n },\n [config, onChange]\n );\n\n return (\n <div className=\"min-w-0 space-y-form-gap\">\n {/* Variant */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {t('bigconsole.widget.config.gauge.gaugeType', 'Gauge Type')}\n </label>\n <select\n value={config.variant || 'circular'}\n onChange={(e) => handleChange('variant', e.target.value as ConfigType['variant'])}\n className=\"\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value=\"circular\">{t('bigconsole.widget.config.gauge.variant.circular', 'Circular')}</option>\n <option value=\"linear\">{t('bigconsole.widget.config.gauge.variant.linear', 'Linear')}</option>\n </select>\n </div>\n\n {/* Min/Max Range */}\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {t('bigconsole.widget.config.gauge.minimum', 'Minimum')}\n </label>\n <input\n type=\"number\"\n value={config.min ?? 0}\n onChange={(e) => handleChange('min', Number(e.target.value))}\n className=\"\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {t('bigconsole.widget.config.gauge.maximum', 'Maximum')}\n </label>\n <input\n type=\"number\"\n value={config.max ?? 100}\n onChange={(e) => handleChange('max', Number(e.target.value))}\n className=\"\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n </div>\n </div>\n\n {/* Unit */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {t('bigconsole.widget.config.gauge.unitLabel', 'Unit Label')}\n </label>\n <input\n type=\"text\"\n value={config.unit || ''}\n onChange={(e) => handleChange('unit', e.target.value)}\n placeholder={t('bigconsole.widget.config.gauge.unitPlaceholder', 'e.g., %, ms, users')}\n className=\"\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n </div>\n\n {/* Format */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {t('bigconsole.widget.config.gauge.valueFormat', 'Value Format')}\n </label>\n <select\n value={config.format || 'number'}\n onChange={(e) => handleChange('format', e.target.value as ConfigType['format'])}\n className=\"\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value=\"number\">{t('bigconsole.widget.config.gauge.format.number', 'Number')}</option>\n <option value=\"percentage\">{t('bigconsole.widget.config.gauge.format.percentage', 'Percentage')}</option>\n <option value=\"currency\">{t('bigconsole.widget.config.gauge.format.currency', 'Currency')}</option>\n </select>\n </div>\n\n {/* Thresholds Section */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-2\">\n {t('bigconsole.widget.config.gauge.colorThresholds', 'Color Thresholds')}\n </label>\n <p className=\"text-xs text-text-secondary mb-3\">\n {t(\n 'bigconsole.widget.config.gauge.colorThresholdsHelp',\n 'Define color zones based on value ranges. Values up to each threshold will use that color.'\n )}\n </p>\n\n <div className=\"space-y-2\">\n {/* Red zone */}\n <div className=\"flex items-center gap-2\">\n <div className=\"w-4 h-4 rounded bg-status-error-bg\" />\n <span className=\"text-sm text-text-primary flex-1\">\n {t('bigconsole.widget.config.gauge.threshold.danger', 'Danger (Red)')}\n </span>\n <input\n type=\"number\"\n value={config.thresholds?.[0]?.value ?? 33}\n onChange={(e) => {\n const thresholds = [...(config.thresholds || [])];\n thresholds[0] = {\n value: Number(e.target.value),\n color: 'error',\n };\n handleChange('thresholds', thresholds);\n }}\n className=\"\n w-20 px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n </div>\n\n {/* Yellow zone */}\n <div className=\"flex items-center gap-2\">\n <div className=\"w-4 h-4 rounded bg-status-warning-bg\" />\n <span className=\"text-sm text-text-primary flex-1\">\n {t('bigconsole.widget.config.gauge.threshold.warning', 'Warning (Yellow)')}\n </span>\n <input\n type=\"number\"\n value={config.thresholds?.[1]?.value ?? 66}\n onChange={(e) => {\n const thresholds = [...(config.thresholds || [])];\n thresholds[1] = {\n value: Number(e.target.value),\n color: 'warning',\n };\n handleChange('thresholds', thresholds);\n }}\n className=\"\n w-20 px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n </div>\n\n {/* Green zone */}\n <div className=\"flex items-center gap-2\">\n <div className=\"w-4 h-4 rounded bg-status-success-bg\" />\n <span className=\"text-sm text-text-primary flex-1\">\n {t('bigconsole.widget.config.gauge.threshold.good', 'Good (Green)')}\n </span>\n <input\n type=\"number\"\n value={config.thresholds?.[2]?.value ?? 100}\n onChange={(e) => {\n const thresholds = [...(config.thresholds || [])];\n thresholds[2] = {\n value: Number(e.target.value),\n color: 'success',\n };\n handleChange('thresholds', thresholds);\n }}\n className=\"\n w-20 px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n </div>\n </div>\n </div>\n\n {/* Show zones (for linear gauge) */}\n <div\n role=\"group\"\n aria-label=\"Display options\"\n className=\"space-y-3 border-t border-[var(--color-border-subtle)] pt-form-gap\"\n >\n {/* Toggles are a different KIND of control from the field stack above, so they\n get their own labelled group instead of being visually identical to it\n (BOFF-5636). */}\n <p className=\"text-xs font-bold uppercase tracking-wider text-text-secondary\">Display options</p>\n {config.variant === 'linear' && (\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showZones === true}\n onChange={(e) => handleChange('showZones', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">\n {t('bigconsole.widget.config.gauge.showZones', 'Show color zones in background')}\n </span>\n </label>\n )}\n {config.variant !== 'linear' && (\n <p className=\"text-xs text-text-secondary\">\n {t('bigconsole.widget.config.gauge.noCircularOptions', 'No display options for the circular gauge.')}\n </p>\n )}\n </div>\n </div>\n );\n});\n\nexport default GaugeConfig;\n"],"mappings":"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"}
1
+ {"version":3,"file":"GaugeConfig.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/gauge/GaugeConfig.tsx"],"sourcesContent":["/**\n * GaugeConfig Component\n *\n * Configuration panel for Gauge widgets.\n */\n\nimport { type FC, memo, useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport type { GaugeConfig as ConfigType, GaugeThreshold } from '../../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface GaugeConfigProps {\n /** Current configuration */\n config: ConfigType;\n /** Callback when config changes */\n onChange: (config: ConfigType) => void;\n}\n\n/** Semantic fallbacks for bands a config has not defined yet. */\nconst DEFAULT_THRESHOLD_BANDS: readonly GaugeThreshold[] = [\n { value: 33, color: 'error' },\n { value: 66, color: 'warning' },\n { value: 100, color: 'success' },\n];\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const GaugeConfig: FC<GaugeConfigProps> = memo(function GaugeConfig({ config, onChange }) {\n const { t } = useI18n();\n const handleChange = useCallback(\n <K extends keyof ConfigType>(key: K, value: ConfigType[K]) => {\n onChange({ ...config, [key]: value });\n },\n [config, onChange]\n );\n\n /**\n * Update one threshold band's value without disturbing the rest of the entry.\n *\n * Writing a whole new `{value, color}` by index used to discard whatever\n * colour the band already carried — including the hex the backend widget\n * catalog seeds — so editing one band left a mixed hex/semantic array and\n * silently repainted that band. It also dropped the optional `label`.\n *\n * Writing by bare index into a shorter array would leave holes (`[ , , {…}]`),\n * which the widget then maps over as `undefined`; seed any missing lower\n * bands with their semantic default instead.\n */\n const handleThresholdValueChange = useCallback(\n (index: number, rawValue: string) => {\n const next: GaugeThreshold[] = [];\n for (let i = 0; i <= index; i++) {\n next[i] = config.thresholds?.[i] ?? DEFAULT_THRESHOLD_BANDS[i] ?? { value: 100, color: 'success' };\n }\n // Preserve everything except the edited value (colour, label, …).\n next[index] = { ...next[index], value: Number(rawValue) };\n // Keep any bands beyond the edited one untouched.\n for (let i = index + 1; i < (config.thresholds?.length ?? 0); i++) {\n next[i] = config.thresholds?.[i] ?? { value: 100, color: 'success' };\n }\n handleChange('thresholds', next);\n },\n [config.thresholds, handleChange]\n );\n\n return (\n <div className=\"min-w-0 space-y-form-gap\">\n {/* Variant */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {t('bigconsole.widget.config.gauge.gaugeType', 'Gauge Type')}\n </label>\n <select\n value={config.variant || 'circular'}\n onChange={(e) => handleChange('variant', e.target.value as ConfigType['variant'])}\n className=\"\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value=\"circular\">{t('bigconsole.widget.config.gauge.variant.circular', 'Circular')}</option>\n <option value=\"linear\">{t('bigconsole.widget.config.gauge.variant.linear', 'Linear')}</option>\n </select>\n </div>\n\n {/* Min/Max Range */}\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {t('bigconsole.widget.config.gauge.minimum', 'Minimum')}\n </label>\n <input\n type=\"number\"\n value={config.min ?? 0}\n onChange={(e) => handleChange('min', Number(e.target.value))}\n className=\"\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {t('bigconsole.widget.config.gauge.maximum', 'Maximum')}\n </label>\n <input\n type=\"number\"\n value={config.max ?? 100}\n onChange={(e) => handleChange('max', Number(e.target.value))}\n className=\"\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n </div>\n </div>\n\n {/* Unit */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {t('bigconsole.widget.config.gauge.unitLabel', 'Unit Label')}\n </label>\n <input\n type=\"text\"\n value={config.unit || ''}\n onChange={(e) => handleChange('unit', e.target.value)}\n placeholder={t('bigconsole.widget.config.gauge.unitPlaceholder', 'e.g., %, ms, users')}\n className=\"\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n </div>\n\n {/* Format */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {t('bigconsole.widget.config.gauge.valueFormat', 'Value Format')}\n </label>\n <select\n value={config.format || 'number'}\n onChange={(e) => handleChange('format', e.target.value as ConfigType['format'])}\n className=\"\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value=\"number\">{t('bigconsole.widget.config.gauge.format.number', 'Number')}</option>\n <option value=\"percentage\">{t('bigconsole.widget.config.gauge.format.percentage', 'Percentage')}</option>\n <option value=\"currency\">{t('bigconsole.widget.config.gauge.format.currency', 'Currency')}</option>\n </select>\n </div>\n\n {/* Thresholds Section */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-2\">\n {t('bigconsole.widget.config.gauge.colorThresholds', 'Color Thresholds')}\n </label>\n <p className=\"text-xs text-text-secondary mb-3\">\n {t(\n 'bigconsole.widget.config.gauge.colorThresholdsHelp',\n 'Define color zones based on value ranges. Values up to each threshold will use that color.'\n )}\n </p>\n\n <div className=\"space-y-2\">\n {/* Red zone */}\n <div className=\"flex items-center gap-2\">\n <div className=\"w-4 h-4 rounded bg-status-error-bg\" />\n <span className=\"text-sm text-text-primary flex-1\">\n {t('bigconsole.widget.config.gauge.threshold.danger', 'Danger (Red)')}\n </span>\n <input\n type=\"number\"\n value={config.thresholds?.[0]?.value ?? 33}\n onChange={(e) => handleThresholdValueChange(0, e.target.value)}\n className=\"\n w-20 px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n </div>\n\n {/* Yellow zone */}\n <div className=\"flex items-center gap-2\">\n <div className=\"w-4 h-4 rounded bg-status-warning-bg\" />\n <span className=\"text-sm text-text-primary flex-1\">\n {t('bigconsole.widget.config.gauge.threshold.warning', 'Warning (Yellow)')}\n </span>\n <input\n type=\"number\"\n value={config.thresholds?.[1]?.value ?? 66}\n onChange={(e) => handleThresholdValueChange(1, e.target.value)}\n className=\"\n w-20 px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n </div>\n\n {/* Green zone */}\n <div className=\"flex items-center gap-2\">\n <div className=\"w-4 h-4 rounded bg-status-success-bg\" />\n <span className=\"text-sm text-text-primary flex-1\">\n {t('bigconsole.widget.config.gauge.threshold.good', 'Good (Green)')}\n </span>\n <input\n type=\"number\"\n value={config.thresholds?.[2]?.value ?? 100}\n onChange={(e) => handleThresholdValueChange(2, e.target.value)}\n className=\"\n w-20 px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n </div>\n </div>\n </div>\n\n {/* Show zones (for linear gauge) */}\n <div\n role=\"group\"\n aria-label=\"Display options\"\n className=\"space-y-3 border-t border-[var(--color-border-subtle)] pt-form-gap\"\n >\n {/* Toggles are a different KIND of control from the field stack above, so they\n get their own labelled group instead of being visually identical to it\n (BOFF-5636). */}\n <p className=\"text-xs font-bold uppercase tracking-wider text-text-secondary\">Display options</p>\n {config.variant === 'linear' && (\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showZones === true}\n onChange={(e) => handleChange('showZones', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">\n {t('bigconsole.widget.config.gauge.showZones', 'Show color zones in background')}\n </span>\n </label>\n )}\n {config.variant !== 'linear' && (\n <p className=\"text-xs text-text-secondary\">\n {t('bigconsole.widget.config.gauge.noCircularOptions', 'No display options for the circular gauge.')}\n </p>\n )}\n </div>\n </div>\n );\n});\n\nexport default GaugeConfig;\n"],"mappings":"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"}