@burdenoff/microfe-bigconsole 2026.613.2 → 2026.613.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bigconsole/components/dashboard/DashboardCanvas.js +142 -135
- package/dist/bigconsole/components/dashboard/DashboardCanvas.js.map +1 -1
- package/dist/bigconsole/components/dashboard/WidgetPalette.js +124 -120
- package/dist/bigconsole/components/dashboard/WidgetPalette.js.map +1 -1
- package/dist/bigconsole/components/widgets/PropertiesPanel.js +9 -9
- package/dist/bigconsole/components/widgets/WidgetRegistry.js +10 -7
- package/dist/bigconsole/components/widgets/WidgetRegistry.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetTypeSelector.js +32 -27
- package/dist/bigconsole/components/widgets/WidgetTypeSelector.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetWrapper.js +9 -9
- package/dist/bigconsole/components/widgets/WidgetWrapper.js.map +1 -1
- package/dist/bigconsole/hooks/index.js +1 -0
- package/dist/bigconsole/hooks/useWidgetCatalog.js +82 -0
- package/dist/bigconsole/hooks/useWidgetCatalog.js.map +1 -0
- package/dist/bigconsole/pages/DashboardBuilderPage.js +172 -163
- package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
- package/dist/generated/wspace-operations.js +17 -17
- package/dist/generated/wspace-operations.js.map +1 -1
- 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 /** Tags for search/filter */\n tags: string[];\n}\n\n// ============================================================================\n// Widget Definitions\n// ============================================================================\n\nexport const WIDGET_DEFINITIONS: Record<WidgetType, WidgetDefinition> = {\n // ============================================================================\n // Core Visualization (6 types)\n // ============================================================================\n\n kpi_card_comparison: {\n type: 'kpi_card_comparison',\n name: 'KPI Card Comparison',\n description: 'Compare multiple KPIs side by side with trends',\n icon: 'LayoutDashboard',\n category: 'KPI',\n component: null,\n defaultConfig: {\n comparisons: [],\n showSparklines: true,\n layout: 'horizontal',\n format: 'number',\n },\n defaultSize: { width: 6, height: 3 },\n defaultResponsive: { xs: 12, sm: 6, md: 6, lg: 4 },\n minSize: { width: 4, height: 2 },\n maxSize: { width: 12, height: 6 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['kpi', 'comparison', 'metrics', 'multi'],\n },\n\n metric_card: {\n type: 'metric_card',\n name: 'Metric Card',\n description: 'Display a single KPI value with trend indicator',\n icon: 'TrendingUp',\n category: 'KPI',\n component: null,\n defaultConfig: {\n format: 'number',\n decimalPlaces: 0,\n showTrend: true,\n showSparkline: false,\n },\n defaultSize: { width: 3, height: 2 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 3 },\n minSize: { width: 2, height: 2 },\n maxSize: { width: 6, height: 4 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['kpi', 'metric', 'number', 'trend'],\n },\n\n chart: {\n type: 'chart',\n name: 'Chart',\n description: 'Multi-type chart (Line, Bar, Area, Pie)',\n icon: 'BarChart3',\n category: 'Visualization',\n component: null,\n defaultConfig: {\n chartType: 'line',\n showLegend: true,\n legendPosition: 'bottom',\n showGrid: true,\n showTooltip: true,\n },\n defaultSize: { width: 6, height: 4 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 3, height: 3 },\n maxSize: { width: 12, height: 8 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['chart', 'graph', 'visualization', 'line', 'bar', 'area', 'pie'],\n },\n\n funnel_chart: {\n type: 'funnel_chart',\n name: 'Funnel Chart',\n description: 'Visualize conversion or drop-off stages',\n icon: 'Filter',\n category: 'Visualization',\n component: null,\n defaultConfig: {\n showLabels: true,\n showValues: true,\n showPercentages: true,\n orientation: 'vertical',\n },\n defaultSize: { width: 4, height: 5 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 3, height: 4 },\n maxSize: { width: 8, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['funnel', 'conversion', 'stages', 'pipeline'],\n },\n\n table: {\n type: 'table',\n name: 'Data Table',\n description: 'Display data in sortable, filterable rows and columns',\n icon: 'Table',\n category: 'Data',\n component: null,\n defaultConfig: {\n pageSize: 10,\n sortable: true,\n filterable: true,\n stickyHeader: true,\n columns: [],\n },\n defaultSize: { width: 8, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 8, lg: 8 },\n minSize: { width: 4, height: 3 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['table', 'data', 'grid', 'rows'],\n },\n\n pivot_table: {\n type: 'pivot_table',\n name: 'Pivot Table',\n description: 'Interactive pivot table for data analysis',\n icon: 'Grid3x3',\n category: 'Data',\n component: null,\n defaultConfig: {\n rows: [],\n columns: [],\n values: [],\n aggregation: 'sum',\n showTotals: true,\n },\n defaultSize: { width: 10, height: 6 },\n defaultResponsive: { xs: 12, sm: 12, md: 12, lg: 10 },\n minSize: { width: 6, height: 4 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['pivot', 'table', 'analysis', 'aggregation'],\n },\n\n // ============================================================================\n // Indicators (2 types)\n // ============================================================================\n\n gauge: {\n type: 'gauge',\n name: 'Gauge',\n description: 'Display a value within a range',\n icon: 'Gauge',\n category: 'KPI',\n component: null,\n defaultConfig: {\n variant: 'circular',\n min: 0,\n max: 100,\n showValue: true,\n showLabels: true,\n thresholds: [\n { value: 33, color: 'red' },\n { value: 66, color: 'yellow' },\n { value: 100, color: 'green' },\n ],\n },\n defaultSize: { width: 3, height: 3 },\n defaultResponsive: { xs: 6, sm: 4, md: 3, lg: 3 },\n minSize: { width: 2, height: 2 },\n maxSize: { width: 6, height: 6 },\n supportsDataBinding: true,\n supportsDrilldown: false,\n supportsAutoRefresh: true,\n tags: ['gauge', 'meter', 'dial', 'indicator'],\n },\n\n progress: {\n type: 'progress',\n name: 'Progress Bar',\n description: 'Show progress towards a goal with milestones',\n icon: 'Activity',\n category: 'KPI',\n component: null,\n defaultConfig: {\n showPercentage: true,\n showValue: false,\n target: null,\n milestones: [],\n },\n defaultSize: { width: 4, height: 2 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 3, height: 2 },\n maxSize: { width: 12, height: 3 },\n supportsDataBinding: true,\n supportsDrilldown: false,\n supportsAutoRefresh: true,\n tags: ['progress', 'bar', 'goal', 'completion'],\n },\n\n // ============================================================================\n // Data Display (2 types)\n // ============================================================================\n\n list: {\n type: 'list',\n name: 'List',\n description: 'Display items in a scrollable list',\n icon: 'List',\n category: 'Data',\n component: null,\n defaultConfig: {\n showMetadata: true,\n showActions: false,\n showBadges: true,\n maxItems: 10,\n itemClickable: true,\n },\n defaultSize: { width: 4, height: 5 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 3, height: 3 },\n maxSize: { width: 8, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['list', 'items', 'scroll'],\n },\n\n form: {\n type: 'form',\n name: 'Form',\n description: 'Interactive form widget for data input',\n icon: 'FileText',\n category: 'Data',\n component: null,\n defaultConfig: {\n fields: [],\n submitAction: null,\n layout: 'vertical',\n showLabels: true,\n },\n defaultSize: { width: 6, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 4, height: 3 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: false,\n supportsAutoRefresh: false,\n tags: ['form', 'input', 'submit', 'fields'],\n },\n\n // ============================================================================\n // Content (2 types)\n // ============================================================================\n\n text: {\n type: 'text',\n name: 'Text',\n description: 'Rich text or markdown content widget',\n icon: 'Type',\n category: 'Content',\n component: null,\n defaultConfig: {\n content: '',\n format: 'markdown',\n alignment: 'left',\n },\n defaultSize: { width: 4, height: 3 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 2, height: 1 },\n maxSize: { width: 12, height: 12 },\n supportsDataBinding: false,\n supportsDrilldown: false,\n supportsAutoRefresh: false,\n tags: ['text', 'markdown', 'content', 'rich text'],\n },\n\n iframe: {\n type: 'iframe',\n name: 'Iframe',\n description: 'Embed external content via iframe',\n icon: 'ExternalLink',\n category: 'Content',\n component: null,\n defaultConfig: {\n url: '',\n sandbox: 'allow-scripts allow-same-origin',\n allowFullscreen: false,\n },\n defaultSize: { width: 6, height: 4 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 3, height: 2 },\n maxSize: { width: 12, height: 12 },\n supportsDataBinding: false,\n supportsDrilldown: false,\n supportsAutoRefresh: false,\n tags: ['iframe', 'embed', 'external', 'web'],\n },\n\n // ============================================================================\n // Spatial & Temporal (5 types)\n // ============================================================================\n\n map: {\n type: 'map',\n name: 'Map',\n description: 'Geographic map visualization with markers',\n icon: 'MapPin',\n category: 'Visualization',\n component: null,\n defaultConfig: {\n provider: 'mapbox',\n center: { lat: 0, lng: 0 },\n zoom: 2,\n showMarkers: true,\n showRegions: false,\n },\n defaultSize: { width: 6, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 4, height: 3 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['map', 'geo', 'location', 'markers'],\n },\n\n heatmap: {\n type: 'heatmap',\n name: 'Heatmap',\n description: 'Display values in a color-coded grid',\n icon: 'Grid3x3',\n category: 'Visualization',\n component: null,\n defaultConfig: {\n xAxisField: '',\n yAxisField: '',\n valueField: '',\n // HeatmapWidget renders intensity from `colorScheme` (token-based Tailwind\n // classes), not `colorScale`; keep the scale empty rather than seeding it\n // with CSS var() strings that a data array can never resolve.\n colorScale: [],\n colorScheme: 'blue',\n showValues: true,\n },\n defaultSize: { width: 6, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 4, height: 4 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['heatmap', 'grid', 'density', 'color'],\n },\n\n calendar: {\n type: 'calendar',\n name: 'Calendar',\n description: 'Calendar view for events and schedules',\n icon: 'Calendar',\n category: 'Temporal',\n component: null,\n defaultConfig: {\n view: 'month',\n showWeekNumbers: false,\n firstDayOfWeek: 0,\n eventField: '',\n },\n defaultSize: { width: 8, height: 6 },\n defaultResponsive: { xs: 12, sm: 12, md: 8, lg: 8 },\n minSize: { width: 6, height: 4 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['calendar', 'events', 'schedule', 'dates'],\n },\n\n kanban: {\n type: 'kanban',\n name: 'Kanban Board',\n description: 'Kanban board for task and workflow management',\n icon: 'Columns',\n category: 'Data',\n component: null,\n defaultConfig: {\n columns: [],\n cardTitleField: '',\n cardDescriptionField: '',\n columnField: '',\n allowDragDrop: true,\n },\n defaultSize: { width: 12, height: 6 },\n defaultResponsive: { xs: 12, sm: 12, md: 12, lg: 12 },\n minSize: { width: 8, height: 4 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['kanban', 'board', 'tasks', 'workflow'],\n },\n\n timeline: {\n type: 'timeline',\n name: 'Timeline',\n description: 'Timeline or Gantt chart for project scheduling',\n icon: 'GitBranch',\n category: 'Temporal',\n component: null,\n defaultConfig: {\n startDateField: '',\n endDateField: '',\n titleField: '',\n groupField: '',\n showToday: true,\n },\n defaultSize: { width: 12, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 12, lg: 12 },\n minSize: { width: 8, height: 3 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['timeline', 'gantt', 'project', 'schedule'],\n },\n\n // ============================================================================\n // Extensibility (1 type)\n // ============================================================================\n\n custom: {\n type: 'custom',\n name: 'Custom Widget',\n description: 'Custom widget with user-defined rendering',\n icon: 'Puzzle',\n category: 'Custom',\n component: null,\n defaultConfig: {\n componentId: '',\n props: {},\n },\n defaultSize: { width: 4, height: 4 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 2, height: 2 },\n maxSize: { width: 12, height: 12 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['custom', 'plugin', 'extension'],\n },\n};\n\n// ============================================================================\n// Registry Functions\n// ============================================================================\n\n/**\n * Default widget definition for unknown types\n */\nconst DEFAULT_WIDGET_DEFINITION: WidgetDefinition = {\n type: 'custom' as WidgetType,\n name: 'Unknown Widget',\n description: 'Unknown widget type',\n icon: 'Puzzle',\n category: 'Custom',\n component: null,\n defaultConfig: {},\n defaultSize: { width: 4, height: 4 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 2, height: 2 },\n maxSize: { width: 12, height: 12 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['unknown'],\n};\n\n/**\n * Get widget definition by type\n * Handles both lowercase (frontend) and uppercase (backend) types\n */\nexport function getWidgetDefinition(type: WidgetType | string): WidgetDefinition {\n // Try exact match first\n if (WIDGET_DEFINITIONS[type as WidgetType]) {\n return WIDGET_DEFINITIONS[type as WidgetType];\n }\n\n // Try lowercase version (backend returns uppercase for some types)\n const lowerType = type.toLowerCase() as WidgetType;\n if (WIDGET_DEFINITIONS[lowerType]) {\n return WIDGET_DEFINITIONS[lowerType];\n }\n\n // Return default definition for unknown types\n return { ...DEFAULT_WIDGET_DEFINITION, type: type as WidgetType };\n}\n\n/**\n * Get all widget definitions\n */\nexport function getAllWidgetDefinitions(): WidgetDefinition[] {\n return Object.values(WIDGET_DEFINITIONS);\n}\n\n/**\n * Get widget definitions by category\n */\nexport function getWidgetsByCategory(category: WidgetCategory): WidgetDefinition[] {\n return Object.values(WIDGET_DEFINITIONS).filter((def) => def.category === category);\n}\n\n/**\n * Search widget definitions by query\n */\nexport function searchWidgets(query: string): WidgetDefinition[] {\n const lowerQuery = query.toLowerCase();\n return Object.values(WIDGET_DEFINITIONS).filter(\n (def) =>\n def.name.toLowerCase().includes(lowerQuery) ||\n def.description.toLowerCase().includes(lowerQuery) ||\n def.tags.some((tag) => tag.includes(lowerQuery))\n );\n}\n\n/**\n * Canonical mapping from widget category to human-readable label.\n * Shared across WidgetTypeSelector, WidgetPalette, and other UI.\n */\nexport const WIDGET_CATEGORY_LABELS: Record<WidgetCategory, string> = {\n KPI: 'Metrics & KPIs',\n Visualization: 'Charts & Visualization',\n Data: 'Data Display',\n Content: 'Content',\n Temporal: 'Temporal & Scheduling',\n Custom: 'Custom',\n Installed: 'Installed from Store',\n};\n\n/**\n * Get widget categories with their definitions\n */\nexport function getWidgetCategories(): {\n category: WidgetCategory;\n label: string;\n widgets: WidgetDefinition[];\n}[] {\n const categories: WidgetCategory[] = ['KPI', 'Visualization', 'Data', 'Content', 'Temporal', 'Custom', 'Installed'];\n\n return categories.map((category) => ({\n category,\n label: WIDGET_CATEGORY_LABELS[category],\n widgets: getWidgetsByCategory(category),\n }));\n}\n\n/**\n * Validate widget size constraints\n */\nexport function validateWidgetSize(\n type: WidgetType,\n width: number,\n height: number\n): { valid: boolean; width: number; height: number } {\n const def = WIDGET_DEFINITIONS[type];\n\n const clampedWidth = Math.min(Math.max(width, def.minSize.width), def.maxSize.width);\n const clampedHeight = Math.min(Math.max(height, def.minSize.height), def.maxSize.height);\n\n return {\n valid: width === clampedWidth && height === clampedHeight,\n width: clampedWidth,\n height: clampedHeight,\n };\n}\n\n/**\n * Get a stable key for a widget definition (handles installed widgets with componentId)\n */\nexport function getWidgetKey(widget: WidgetDefinition): string {\n if (widget.defaultConfig?.componentId) {\n return `installed-${widget.defaultConfig.componentId}`;\n }\n if (widget.category === 'Installed') {\n return `installed-${widget.name}`;\n }\n return widget.type;\n}\n\nexport default WIDGET_DEFINITIONS;\n"],"mappings":"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"}
|
|
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 /** Tags for search/filter */\n tags: string[];\n}\n\n// ============================================================================\n// Widget Definitions\n// ============================================================================\n\nexport const WIDGET_DEFINITIONS: Record<WidgetType, WidgetDefinition> = {\n // ============================================================================\n // Core Visualization (6 types)\n // ============================================================================\n\n kpi_card_comparison: {\n type: 'kpi_card_comparison',\n name: 'KPI Card Comparison',\n description: 'Compare multiple KPIs side by side with trends',\n icon: 'LayoutDashboard',\n category: 'KPI',\n component: null,\n defaultConfig: {\n comparisons: [],\n showSparklines: true,\n layout: 'horizontal',\n format: 'number',\n },\n defaultSize: { width: 6, height: 3 },\n defaultResponsive: { xs: 12, sm: 6, md: 6, lg: 4 },\n minSize: { width: 4, height: 2 },\n maxSize: { width: 12, height: 6 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['kpi', 'comparison', 'metrics', 'multi'],\n },\n\n metric_card: {\n type: 'metric_card',\n name: 'Metric Card',\n description: 'Display a single KPI value with trend indicator',\n icon: 'TrendingUp',\n category: 'KPI',\n component: null,\n defaultConfig: {\n format: 'number',\n decimalPlaces: 0,\n showTrend: true,\n showSparkline: false,\n },\n defaultSize: { width: 3, height: 2 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 3 },\n minSize: { width: 2, height: 2 },\n maxSize: { width: 6, height: 4 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['kpi', 'metric', 'number', 'trend'],\n },\n\n chart: {\n type: 'chart',\n name: 'Chart',\n description: 'Multi-type chart (Line, Bar, Area, Pie)',\n icon: 'BarChart3',\n category: 'Visualization',\n component: null,\n defaultConfig: {\n chartType: 'line',\n showLegend: true,\n legendPosition: 'bottom',\n showGrid: true,\n showTooltip: true,\n },\n defaultSize: { width: 6, height: 4 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 3, height: 3 },\n maxSize: { width: 12, height: 8 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['chart', 'graph', 'visualization', 'line', 'bar', 'area', 'pie'],\n },\n\n funnel_chart: {\n type: 'funnel_chart',\n name: 'Funnel Chart',\n description: 'Visualize conversion or drop-off stages',\n icon: 'Filter',\n category: 'Visualization',\n component: null,\n defaultConfig: {\n showLabels: true,\n showValues: true,\n showPercentages: true,\n orientation: 'vertical',\n },\n defaultSize: { width: 4, height: 5 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 3, height: 4 },\n maxSize: { width: 8, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['funnel', 'conversion', 'stages', 'pipeline'],\n },\n\n table: {\n type: 'table',\n name: 'Data Table',\n description: 'Display data in sortable, filterable rows and columns',\n icon: 'Table',\n category: 'Data',\n component: null,\n defaultConfig: {\n pageSize: 10,\n sortable: true,\n filterable: true,\n stickyHeader: true,\n columns: [],\n },\n defaultSize: { width: 8, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 8, lg: 8 },\n minSize: { width: 4, height: 3 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['table', 'data', 'grid', 'rows'],\n },\n\n pivot_table: {\n type: 'pivot_table',\n name: 'Pivot Table',\n description: 'Interactive pivot table for data analysis',\n icon: 'Grid3x3',\n category: 'Data',\n component: null,\n defaultConfig: {\n rows: [],\n columns: [],\n values: [],\n aggregation: 'sum',\n showTotals: true,\n },\n defaultSize: { width: 10, height: 6 },\n defaultResponsive: { xs: 12, sm: 12, md: 12, lg: 10 },\n minSize: { width: 6, height: 4 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['pivot', 'table', 'analysis', 'aggregation'],\n },\n\n // ============================================================================\n // Indicators (2 types)\n // ============================================================================\n\n gauge: {\n type: 'gauge',\n name: 'Gauge',\n description: 'Display a value within a range',\n icon: 'Gauge',\n category: 'KPI',\n component: null,\n defaultConfig: {\n variant: 'circular',\n min: 0,\n max: 100,\n showValue: true,\n showLabels: true,\n thresholds: [\n { value: 33, color: 'red' },\n { value: 66, color: 'yellow' },\n { value: 100, color: 'green' },\n ],\n },\n defaultSize: { width: 3, height: 3 },\n defaultResponsive: { xs: 6, sm: 4, md: 3, lg: 3 },\n minSize: { width: 2, height: 2 },\n maxSize: { width: 6, height: 6 },\n supportsDataBinding: true,\n supportsDrilldown: false,\n supportsAutoRefresh: true,\n tags: ['gauge', 'meter', 'dial', 'indicator'],\n },\n\n progress: {\n type: 'progress',\n name: 'Progress Bar',\n description: 'Show progress towards a goal with milestones',\n icon: 'Activity',\n category: 'KPI',\n component: null,\n defaultConfig: {\n showPercentage: true,\n showValue: false,\n target: null,\n milestones: [],\n },\n defaultSize: { width: 4, height: 2 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 3, height: 2 },\n maxSize: { width: 12, height: 3 },\n supportsDataBinding: true,\n supportsDrilldown: false,\n supportsAutoRefresh: true,\n tags: ['progress', 'bar', 'goal', 'completion'],\n },\n\n // ============================================================================\n // Data Display (2 types)\n // ============================================================================\n\n list: {\n type: 'list',\n name: 'List',\n description: 'Display items in a scrollable list',\n icon: 'List',\n category: 'Data',\n component: null,\n defaultConfig: {\n showMetadata: true,\n showActions: false,\n showBadges: true,\n maxItems: 10,\n itemClickable: true,\n },\n defaultSize: { width: 4, height: 5 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 3, height: 3 },\n maxSize: { width: 8, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['list', 'items', 'scroll'],\n },\n\n form: {\n type: 'form',\n name: 'Form',\n description: 'Interactive form widget for data input',\n icon: 'FileText',\n category: 'Data',\n component: null,\n defaultConfig: {\n fields: [],\n submitAction: null,\n layout: 'vertical',\n showLabels: true,\n },\n defaultSize: { width: 6, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 4, height: 3 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: false,\n supportsAutoRefresh: false,\n tags: ['form', 'input', 'submit', 'fields'],\n },\n\n // ============================================================================\n // Content (2 types)\n // ============================================================================\n\n text: {\n type: 'text',\n name: 'Text',\n description: 'Rich text or markdown content widget',\n icon: 'Type',\n category: 'Content',\n component: null,\n defaultConfig: {\n content: '',\n format: 'markdown',\n alignment: 'left',\n },\n defaultSize: { width: 4, height: 3 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 2, height: 1 },\n maxSize: { width: 12, height: 12 },\n supportsDataBinding: false,\n supportsDrilldown: false,\n supportsAutoRefresh: false,\n tags: ['text', 'markdown', 'content', 'rich text'],\n },\n\n iframe: {\n type: 'iframe',\n name: 'Iframe',\n description: 'Embed external content via iframe',\n icon: 'ExternalLink',\n category: 'Content',\n component: null,\n defaultConfig: {\n url: '',\n sandbox: 'allow-scripts allow-same-origin',\n allowFullscreen: false,\n },\n defaultSize: { width: 6, height: 4 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 3, height: 2 },\n maxSize: { width: 12, height: 12 },\n supportsDataBinding: false,\n supportsDrilldown: false,\n supportsAutoRefresh: false,\n tags: ['iframe', 'embed', 'external', 'web'],\n },\n\n // ============================================================================\n // Spatial & Temporal (5 types)\n // ============================================================================\n\n map: {\n type: 'map',\n name: 'Map',\n description: 'Geographic map visualization with markers',\n icon: 'MapPin',\n category: 'Visualization',\n component: null,\n defaultConfig: {\n provider: 'mapbox',\n center: { lat: 0, lng: 0 },\n zoom: 2,\n showMarkers: true,\n showRegions: false,\n },\n defaultSize: { width: 6, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 4, height: 3 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['map', 'geo', 'location', 'markers'],\n },\n\n heatmap: {\n type: 'heatmap',\n name: 'Heatmap',\n description: 'Display values in a color-coded grid',\n icon: 'Grid3x3',\n category: 'Visualization',\n component: null,\n defaultConfig: {\n xAxisField: '',\n yAxisField: '',\n valueField: '',\n // HeatmapWidget renders intensity from `colorScheme` (token-based Tailwind\n // classes), not `colorScale`; keep the scale empty rather than seeding it\n // with CSS var() strings that a data array can never resolve.\n colorScale: [],\n colorScheme: 'blue',\n showValues: true,\n },\n defaultSize: { width: 6, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 4, height: 4 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['heatmap', 'grid', 'density', 'color'],\n },\n\n calendar: {\n type: 'calendar',\n name: 'Calendar',\n description: 'Calendar view for events and schedules',\n icon: 'Calendar',\n category: 'Temporal',\n component: null,\n defaultConfig: {\n view: 'month',\n showWeekNumbers: false,\n firstDayOfWeek: 0,\n eventField: '',\n },\n defaultSize: { width: 8, height: 6 },\n defaultResponsive: { xs: 12, sm: 12, md: 8, lg: 8 },\n minSize: { width: 6, height: 4 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['calendar', 'events', 'schedule', 'dates'],\n },\n\n kanban: {\n type: 'kanban',\n name: 'Kanban Board',\n description: 'Kanban board for task and workflow management',\n icon: 'Columns',\n category: 'Data',\n component: null,\n defaultConfig: {\n columns: [],\n cardTitleField: '',\n cardDescriptionField: '',\n columnField: '',\n allowDragDrop: true,\n },\n defaultSize: { width: 12, height: 6 },\n defaultResponsive: { xs: 12, sm: 12, md: 12, lg: 12 },\n minSize: { width: 8, height: 4 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['kanban', 'board', 'tasks', 'workflow'],\n },\n\n timeline: {\n type: 'timeline',\n name: 'Timeline',\n description: 'Timeline or Gantt chart for project scheduling',\n icon: 'GitBranch',\n category: 'Temporal',\n component: null,\n defaultConfig: {\n startDateField: '',\n endDateField: '',\n titleField: '',\n groupField: '',\n showToday: true,\n },\n defaultSize: { width: 12, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 12, lg: 12 },\n minSize: { width: 8, height: 3 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['timeline', 'gantt', 'project', 'schedule'],\n },\n\n // ============================================================================\n // Extensibility (1 type)\n // ============================================================================\n\n custom: {\n type: 'custom',\n name: 'Custom Widget',\n description: 'Custom widget with user-defined rendering',\n icon: 'Puzzle',\n category: 'Custom',\n component: null,\n defaultConfig: {\n componentId: '',\n props: {},\n },\n defaultSize: { width: 4, height: 4 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 2, height: 2 },\n maxSize: { width: 12, height: 12 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['custom', 'plugin', 'extension'],\n },\n};\n\n// ============================================================================\n// Registry Functions\n// ============================================================================\n\n/**\n * Default widget definition for unknown types\n */\nconst DEFAULT_WIDGET_DEFINITION: WidgetDefinition = {\n type: 'custom' as WidgetType,\n name: 'Unknown Widget',\n description: 'Unknown widget type',\n icon: 'Puzzle',\n category: 'Custom',\n component: null,\n defaultConfig: {},\n defaultSize: { width: 4, height: 4 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 2, height: 2 },\n maxSize: { width: 12, height: 12 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['unknown'],\n};\n\n/**\n * Get widget definition by type\n * Handles both lowercase (frontend) and uppercase (backend) types\n */\nexport function getWidgetDefinition(type: WidgetType | string): WidgetDefinition {\n // Try exact match first\n if (WIDGET_DEFINITIONS[type as WidgetType]) {\n return WIDGET_DEFINITIONS[type as WidgetType];\n }\n\n // Try lowercase version (backend returns uppercase for some types)\n const lowerType = type.toLowerCase() as WidgetType;\n if (WIDGET_DEFINITIONS[lowerType]) {\n return WIDGET_DEFINITIONS[lowerType];\n }\n\n // Return default definition for unknown types\n return { ...DEFAULT_WIDGET_DEFINITION, type: type as WidgetType };\n}\n\n/**\n * Get all widget definitions\n */\nexport function getAllWidgetDefinitions(): WidgetDefinition[] {\n return Object.values(WIDGET_DEFINITIONS);\n}\n\n/**\n * Get widget definitions by category\n */\nexport function getWidgetsByCategory(category: WidgetCategory): WidgetDefinition[] {\n return Object.values(WIDGET_DEFINITIONS).filter((def) => def.category === category);\n}\n\n/**\n * Search widget definitions by query\n */\nexport function searchWidgets(query: string): WidgetDefinition[] {\n const lowerQuery = query.toLowerCase();\n return Object.values(WIDGET_DEFINITIONS).filter(\n (def) =>\n def.name.toLowerCase().includes(lowerQuery) ||\n def.description.toLowerCase().includes(lowerQuery) ||\n def.tags.some((tag) => tag.includes(lowerQuery))\n );\n}\n\n/**\n * Canonical mapping from widget category to human-readable label.\n * Shared across WidgetTypeSelector, WidgetPalette, and other UI.\n */\nexport const WIDGET_CATEGORY_LABELS: Record<WidgetCategory, string> = {\n KPI: 'Metrics & KPIs',\n Visualization: 'Charts & Visualization',\n Data: 'Data Display',\n Content: 'Content',\n Temporal: 'Temporal & Scheduling',\n Custom: 'Custom',\n Installed: 'Installed from Store',\n};\n\n/**\n * Get widget categories with their definitions\n */\nexport function getWidgetCategories(): {\n category: WidgetCategory;\n label: string;\n widgets: WidgetDefinition[];\n}[] {\n const categories: WidgetCategory[] = ['KPI', 'Visualization', 'Data', 'Content', 'Temporal', 'Custom', 'Installed'];\n\n return categories.map((category) => ({\n category,\n label: WIDGET_CATEGORY_LABELS[category],\n widgets: getWidgetsByCategory(category),\n }));\n}\n\n/**\n * Validate widget size constraints\n */\nexport function validateWidgetSize(\n type: WidgetType,\n width: number,\n height: number\n): { valid: boolean; width: number; height: number } {\n const def = WIDGET_DEFINITIONS[type];\n\n const clampedWidth = Math.min(Math.max(width, def.minSize.width), def.maxSize.width);\n const clampedHeight = Math.min(Math.max(height, def.minSize.height), def.maxSize.height);\n\n return {\n valid: width === clampedWidth && height === clampedHeight,\n width: clampedWidth,\n height: clampedHeight,\n };\n}\n\n/**\n * Get a stable key for a widget definition (handles installed widgets with componentId)\n */\nexport function getWidgetKey(widget: WidgetDefinition): string {\n if (widget.defaultConfig?.componentId) {\n return `installed-${widget.defaultConfig.componentId}`;\n }\n if (widget.category === 'Installed') {\n return `installed-${widget.name}`;\n }\n return widget.type;\n}\n\nexport default WIDGET_DEFINITIONS;\n"],"mappings":";AA0EA,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,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,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,MAAM;GAAC;GAAS;GAAS;GAAiB;GAAQ;GAAO;GAAQ;GAAM;EACxE;CAED,cAAc;EACZ,MAAM;EACN,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;EACV,WAAW;EACX,eAAe;GACb,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,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,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,4 +1,4 @@
|
|
|
1
|
-
import { WIDGET_CATEGORY_LABELS as e,
|
|
1
|
+
import { WIDGET_CATEGORY_LABELS as e, getAllWidgetDefinitions as t, getWidgetKey as n } from "./WidgetRegistry.js";
|
|
2
2
|
import { memo as r, useCallback as i, useMemo as a, useState as o } from "react";
|
|
3
3
|
import { Activity as s, BarChart3 as c, Calendar as l, Code as u, Columns as d, CreditCard as f, ExternalLink as p, FileText as m, Filter as h, Gauge as g, GitBranch as _, Grid3x3 as v, Layers as y, LayoutDashboard as b, List as x, MapPin as S, MessageSquare as C, Puzzle as w, Search as T, Table as E, TrendingUp as D, Type as O } from "lucide-react";
|
|
4
4
|
import { jsx as k, jsxs as A } from "react/jsx-runtime";
|
|
@@ -76,30 +76,35 @@ var P = [
|
|
|
76
76
|
"Temporal",
|
|
77
77
|
"Custom",
|
|
78
78
|
"Installed"
|
|
79
|
-
], L = r(function({ selectedType: r, onSelect: s, categories: c, onRendererSelect: l, selectedRenderer: u, installedWidgets: d = [] }) {
|
|
80
|
-
let [
|
|
81
|
-
let e =
|
|
82
|
-
for (let
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
79
|
+
], L = r(function({ selectedType: r, onSelect: s, categories: c, onRendererSelect: l, selectedRenderer: u, installedWidgets: d = [], definitions: f }) {
|
|
80
|
+
let [p, m] = o(""), [h, g] = o(u || "ALL"), _ = a(() => {
|
|
81
|
+
let e = f ?? t(), n = {};
|
|
82
|
+
for (let t of e) (n[t.category] ??= []).push(t);
|
|
83
|
+
return n;
|
|
84
|
+
}, [f]), v = a(() => {
|
|
85
|
+
let e = c || I, t = {}, n = F[h];
|
|
86
|
+
for (let r of e) {
|
|
87
|
+
let e = r === "Installed" ? d : _[r] ?? [];
|
|
88
|
+
if (p.trim()) {
|
|
89
|
+
let t = p.toLowerCase();
|
|
86
90
|
e = e.filter((e) => e.name.toLowerCase().includes(t) || e.description.toLowerCase().includes(t));
|
|
87
91
|
}
|
|
88
|
-
|
|
92
|
+
n !== "all" && (e = e.filter((e) => n.includes(e.type))), e.length > 0 && (t[r] = e);
|
|
89
93
|
}
|
|
90
94
|
return t;
|
|
91
95
|
}, [
|
|
92
|
-
|
|
96
|
+
p,
|
|
93
97
|
c,
|
|
94
|
-
|
|
95
|
-
d
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
h,
|
|
99
|
+
d,
|
|
100
|
+
_
|
|
101
|
+
]), y = i((e) => {
|
|
102
|
+
g(e), l && e !== "ALL" && l(e);
|
|
103
|
+
}, [l]), b = i((e, t) => {
|
|
104
|
+
s(e, t), h !== "ALL" && l && l(h);
|
|
100
105
|
}, [
|
|
101
106
|
s,
|
|
102
|
-
|
|
107
|
+
h,
|
|
103
108
|
l
|
|
104
109
|
]);
|
|
105
110
|
return /* @__PURE__ */ A("div", {
|
|
@@ -125,10 +130,10 @@ var P = [
|
|
|
125
130
|
borderRadius: "6px"
|
|
126
131
|
},
|
|
127
132
|
children: P.map((e) => {
|
|
128
|
-
let t = e.icon, n =
|
|
133
|
+
let t = e.icon, n = h === e.id;
|
|
129
134
|
return /* @__PURE__ */ A("button", {
|
|
130
135
|
type: "button",
|
|
131
|
-
onClick: () =>
|
|
136
|
+
onClick: () => y(e.id),
|
|
132
137
|
style: {
|
|
133
138
|
flex: 1,
|
|
134
139
|
display: "flex",
|
|
@@ -172,8 +177,8 @@ var P = [
|
|
|
172
177
|
} }), /* @__PURE__ */ k(j, {
|
|
173
178
|
type: "text",
|
|
174
179
|
placeholder: "Search widgets...",
|
|
175
|
-
value:
|
|
176
|
-
onChange: (e) =>
|
|
180
|
+
value: p,
|
|
181
|
+
onChange: (e) => m(e.target.value),
|
|
177
182
|
style: {
|
|
178
183
|
paddingLeft: "32px",
|
|
179
184
|
height: "32px",
|
|
@@ -191,7 +196,7 @@ var P = [
|
|
|
191
196
|
maxHeight: "350px",
|
|
192
197
|
minHeight: "200px"
|
|
193
198
|
},
|
|
194
|
-
children: [Object.entries(
|
|
199
|
+
children: [Object.entries(v).map(([t, i]) => /* @__PURE__ */ A("div", {
|
|
195
200
|
style: { marginBottom: "16px" },
|
|
196
201
|
children: [/* @__PURE__ */ k("h3", {
|
|
197
202
|
style: {
|
|
@@ -203,7 +208,7 @@ var P = [
|
|
|
203
208
|
marginBottom: "8px",
|
|
204
209
|
paddingLeft: "4px"
|
|
205
210
|
},
|
|
206
|
-
children:
|
|
211
|
+
children: t === "search" ? `Search Results (${i.length})` : e[t]
|
|
207
212
|
}), /* @__PURE__ */ k("div", {
|
|
208
213
|
style: {
|
|
209
214
|
display: "grid",
|
|
@@ -211,9 +216,9 @@ var P = [
|
|
|
211
216
|
gap: "8px"
|
|
212
217
|
},
|
|
213
218
|
children: i.map((e) => {
|
|
214
|
-
let
|
|
219
|
+
let t = N(e.icon), i = n(e), a = e.category !== "Installed" && r === e.type;
|
|
215
220
|
return /* @__PURE__ */ A("div", {
|
|
216
|
-
onClick: () =>
|
|
221
|
+
onClick: () => b(e.type, e),
|
|
217
222
|
style: {
|
|
218
223
|
display: "flex",
|
|
219
224
|
alignItems: "center",
|
|
@@ -244,7 +249,7 @@ var P = [
|
|
|
244
249
|
backgroundColor: a ? "var(--color-action-primary-bg)" : "var(--color-bg-muted)",
|
|
245
250
|
color: a ? "var(--color-action-primary-text)" : "var(--color-text-secondary)"
|
|
246
251
|
},
|
|
247
|
-
children: /* @__PURE__ */ k(
|
|
252
|
+
children: /* @__PURE__ */ k(t, { style: {
|
|
248
253
|
width: "16px",
|
|
249
254
|
height: "16px"
|
|
250
255
|
} })
|
|
@@ -262,7 +267,7 @@ var P = [
|
|
|
262
267
|
}, i);
|
|
263
268
|
})
|
|
264
269
|
})]
|
|
265
|
-
},
|
|
270
|
+
}, t)), Object.keys(v).length === 0 && /* @__PURE__ */ A("div", {
|
|
266
271
|
style: {
|
|
267
272
|
display: "flex",
|
|
268
273
|
flexDirection: "column",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WidgetTypeSelector.js","names":[],"sources":["../../../../src/bigconsole/components/widgets/WidgetTypeSelector.tsx"],"sourcesContent":["/**\n * WidgetTypeSelector Component\n *\n * Grid of available widget types for selection.\n * v2.0: Added renderer filter tabs for filtering by renderer type.\n * Uses fe-libs shared components for consistent styling.\n */\n\nimport { type FC, memo, useState, useMemo, useCallback } from 'react';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport type { WidgetType, WidgetCategory, RendererType } from '../../types';\nimport { getWidgetsByCategory, getWidgetKey, WIDGET_CATEGORY_LABELS, type WidgetDefinition } from './WidgetRegistry';\nimport {\n TrendingUp,\n BarChart3,\n Filter,\n Table,\n Grid3x3,\n Gauge,\n Activity,\n List,\n FileText,\n Type,\n ExternalLink,\n MapPin,\n Calendar,\n Columns,\n GitBranch,\n Puzzle,\n LayoutDashboard,\n Search,\n Layers,\n CreditCard,\n MessageSquare,\n Code,\n type LucideIcon,\n} from 'lucide-react';\n\n// ============================================================================\n// Icon Mapping - Maps string icon names to Lucide components\n// ============================================================================\n\nconst ICON_MAP: Record<string, LucideIcon> = {\n TrendingUp,\n BarChart3,\n Filter,\n Table,\n Grid3x3,\n Gauge,\n Activity,\n List,\n FileText,\n Type,\n ExternalLink,\n MapPin,\n Calendar,\n Columns,\n GitBranch,\n Puzzle,\n LayoutDashboard,\n};\n\nfunction getIconComponent(iconName: string): LucideIcon {\n return ICON_MAP[iconName] || Puzzle;\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface WidgetTypeSelectorProps {\n selectedType?: WidgetType;\n onSelect: (type: WidgetType, definition?: WidgetDefinition) => void;\n categories?: WidgetCategory[];\n onRendererSelect?: (renderer: RendererType) => void;\n selectedRenderer?: RendererType;\n /** Installed widgets from the store (fetched by parent) */\n installedWidgets?: WidgetDefinition[];\n}\n\ntype RendererFilter = RendererType | 'ALL';\n\ninterface RendererFilterOption {\n id: RendererFilter;\n label: string;\n icon: LucideIcon;\n}\n\nconst RENDERER_FILTERS: RendererFilterOption[] = [\n { id: 'ALL', label: 'All', icon: Layers },\n { id: 'ADAPTIVE_CARD', label: 'Adaptive Card', icon: CreditCard },\n { id: 'BLOCKKIT', label: 'Block Kit', icon: MessageSquare },\n { id: 'CUSTOM', label: 'Custom', icon: Code },\n];\n\n// Widget types that support each renderer (for filtering)\nconst RENDERER_WIDGET_TYPES: Record<RendererFilter, WidgetType[] | 'all'> = {\n ALL: 'all',\n BIGCONSOLE: 'all',\n ADAPTIVE_CARD: ['metric_card', 'kpi_card_comparison', 'text', 'list', 'table', 'form', 'custom'],\n BLOCKKIT: ['metric_card', 'kpi_card_comparison', 'text', 'list', 'table', 'custom'],\n CUSTOM: ['custom'],\n};\n\nconst ALL_CATEGORIES: WidgetCategory[] = ['KPI', 'Visualization', 'Data', 'Content', 'Temporal', 'Custom', 'Installed'];\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const WidgetTypeSelector: FC<WidgetTypeSelectorProps> = memo(function WidgetTypeSelector({\n selectedType,\n onSelect,\n categories,\n onRendererSelect,\n selectedRenderer,\n installedWidgets = [],\n}) {\n const [searchQuery, setSearchQuery] = useState('');\n const [rendererFilter, setRendererFilter] = useState<RendererFilter>(selectedRenderer || 'ALL');\n\n const widgetsByCategory = useMemo(() => {\n const cats = categories || ALL_CATEGORIES;\n const grouped: Record<string, WidgetDefinition[]> = {};\n\n // Get allowed widget types for current renderer filter\n const allowedTypes = RENDERER_WIDGET_TYPES[rendererFilter];\n\n for (const cat of cats) {\n let widgets = cat === 'Installed' ? installedWidgets : getWidgetsByCategory(cat);\n\n // Filter by search query\n if (searchQuery.trim()) {\n const query = searchQuery.toLowerCase();\n widgets = widgets.filter(\n (w) => w.name.toLowerCase().includes(query) || w.description.toLowerCase().includes(query)\n );\n }\n\n // Filter by renderer\n if (allowedTypes !== 'all') {\n widgets = widgets.filter((w) => allowedTypes.includes(w.type));\n }\n\n if (widgets.length > 0) {\n grouped[cat] = widgets;\n }\n }\n\n return grouped;\n }, [searchQuery, categories, rendererFilter, installedWidgets]);\n\n const handleRendererFilterChange = useCallback(\n (filter: RendererFilter) => {\n setRendererFilter(filter);\n if (onRendererSelect && filter !== 'ALL') {\n onRendererSelect(filter as RendererType);\n }\n },\n [onRendererSelect]\n );\n\n const handleSelect = useCallback(\n (type: WidgetType, definition?: WidgetDefinition) => {\n onSelect(type, definition);\n // If a specific renderer is selected, notify parent\n if (rendererFilter !== 'ALL' && onRendererSelect) {\n onRendererSelect(rendererFilter as RendererType);\n }\n },\n [onSelect, rendererFilter, onRendererSelect]\n );\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', height: '100%', maxHeight: '500px', maxWidth: '500px' }}>\n {/* Renderer Filter Tabs */}\n <div style={{ padding: '8px 12px', borderBottom: '1px solid var(--color-border)' }}>\n <div\n style={{\n display: 'flex',\n gap: '4px',\n backgroundColor: 'var(--color-bg-muted)',\n padding: '3px',\n borderRadius: '6px',\n }}\n >\n {RENDERER_FILTERS.map((filter) => {\n const Icon = filter.icon;\n const isActive = rendererFilter === filter.id;\n return (\n <button\n key={filter.id}\n type=\"button\"\n onClick={() => handleRendererFilterChange(filter.id)}\n style={{\n flex: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '4px',\n padding: '6px 8px',\n borderRadius: '4px',\n border: 'none',\n fontSize: '11px',\n fontWeight: 500,\n cursor: 'pointer',\n transition: 'all 0.15s ease',\n backgroundColor: isActive ? 'var(--color-bg-surface, white)' : 'transparent',\n color: isActive ? 'var(--color-primary)' : 'var(--color-text-secondary)',\n boxShadow: isActive ? '0 1px 2px rgba(0,0,0,0.05)' : 'none',\n }}\n >\n <Icon style={{ width: '12px', height: '12px' }} />\n <span>{filter.label}</span>\n </button>\n );\n })}\n </div>\n </div>\n\n {/* Search */}\n <div style={{ padding: '8px 12px', borderBottom: '1px solid var(--color-border)' }}>\n <div style={{ position: 'relative' }}>\n <Search\n style={{\n position: 'absolute',\n left: '10px',\n top: '50%',\n transform: 'translateY(-50%)',\n width: '14px',\n height: '14px',\n color: 'var(--color-text-secondary)',\n }}\n />\n <Input\n type=\"text\"\n placeholder=\"Search widgets...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n style={{ paddingLeft: '32px', height: '32px', fontSize: '13px' }}\n />\n </div>\n </div>\n\n {/* Categories and widgets - with visible scrollbar */}\n <div\n style={{\n flex: 1,\n overflowY: 'auto',\n padding: '12px',\n backgroundColor: 'var(--color-bg-sunken)',\n maxHeight: '350px',\n minHeight: '200px',\n }}\n >\n {Object.entries(widgetsByCategory).map(([category, widgets]) => (\n <div key={category} style={{ marginBottom: '16px' }}>\n <h3\n style={{\n fontSize: '11px',\n fontWeight: 600,\n textTransform: 'uppercase',\n letterSpacing: '0.05em',\n color: 'var(--color-text-secondary)',\n marginBottom: '8px',\n paddingLeft: '4px',\n }}\n >\n {category === 'search'\n ? `Search Results (${widgets.length})`\n : WIDGET_CATEGORY_LABELS[category as WidgetCategory]}\n </h3>\n\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(2, 1fr)',\n gap: '8px',\n }}\n >\n {widgets.map((widget) => {\n const Icon = getIconComponent(widget.icon);\n const widgetKey = getWidgetKey(widget);\n // For installed widgets (all typed as 'custom'), avoid highlighting\n // every installed widget when one is selected.\n const isSelected = widget.category !== 'Installed' && selectedType === widget.type;\n\n return (\n <div\n key={widgetKey}\n onClick={() => handleSelect(widget.type, widget)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n padding: '10px 12px',\n borderRadius: '8px',\n border: isSelected ? '2px solid var(--color-action-primary-bg)' : '1px solid var(--color-border)',\n backgroundColor: isSelected ? 'var(--color-action-primary-bg)' : 'var(--color-bg-surface)',\n cursor: 'pointer',\n transition: 'all 0.15s ease',\n boxShadow: isSelected ? 'var(--shadow-elevation-2)' : 'var(--shadow-elevation-1)',\n }}\n onMouseEnter={(e) => {\n if (!isSelected) {\n e.currentTarget.style.borderColor = 'var(--color-action-primary-bg)';\n e.currentTarget.style.backgroundColor = 'var(--color-bg-sunken)';\n e.currentTarget.style.boxShadow = 'var(--shadow-elevation-2)';\n }\n }}\n onMouseLeave={(e) => {\n if (!isSelected) {\n e.currentTarget.style.borderColor = 'var(--color-border)';\n e.currentTarget.style.backgroundColor = 'var(--color-bg-surface)';\n e.currentTarget.style.boxShadow = 'var(--shadow-elevation-1)';\n }\n }}\n >\n <div\n style={{\n width: '32px',\n height: '32px',\n flexShrink: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: '6px',\n backgroundColor: isSelected ? 'var(--color-action-primary-bg)' : 'var(--color-bg-muted)',\n color: isSelected ? 'var(--color-action-primary-text)' : 'var(--color-text-secondary)',\n }}\n >\n <Icon style={{ width: '16px', height: '16px' }} />\n </div>\n <span\n style={{\n fontSize: '13px',\n fontWeight: 500,\n color: isSelected ? 'var(--color-action-primary-text)' : 'var(--color-text-primary)',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {widget.name}\n </span>\n </div>\n );\n })}\n </div>\n </div>\n ))}\n\n {Object.keys(widgetsByCategory).length === 0 && (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '32px',\n color: 'var(--color-text-secondary)',\n }}\n >\n <Search style={{ width: '32px', height: '32px', marginBottom: '12px', opacity: 0.5 }} />\n <p style={{ fontSize: '13px' }}>No widgets found</p>\n </div>\n )}\n </div>\n </div>\n );\n});\n\nexport default WidgetTypeSelector;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WidgetTypeSelector.js","names":[],"sources":["../../../../src/bigconsole/components/widgets/WidgetTypeSelector.tsx"],"sourcesContent":["/**\n * WidgetTypeSelector Component\n *\n * Grid of available widget types for selection.\n * v2.0: Added renderer filter tabs for filtering by renderer type.\n * Uses fe-libs shared components for consistent styling.\n */\n\nimport { type FC, memo, useState, useMemo, useCallback } from 'react';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport type { WidgetType, WidgetCategory, RendererType } from '../../types';\nimport { getAllWidgetDefinitions, getWidgetKey, WIDGET_CATEGORY_LABELS, type WidgetDefinition } from './WidgetRegistry';\nimport {\n TrendingUp,\n BarChart3,\n Filter,\n Table,\n Grid3x3,\n Gauge,\n Activity,\n List,\n FileText,\n Type,\n ExternalLink,\n MapPin,\n Calendar,\n Columns,\n GitBranch,\n Puzzle,\n LayoutDashboard,\n Search,\n Layers,\n CreditCard,\n MessageSquare,\n Code,\n type LucideIcon,\n} from 'lucide-react';\n\n// ============================================================================\n// Icon Mapping - Maps string icon names to Lucide components\n// ============================================================================\n\nconst ICON_MAP: Record<string, LucideIcon> = {\n TrendingUp,\n BarChart3,\n Filter,\n Table,\n Grid3x3,\n Gauge,\n Activity,\n List,\n FileText,\n Type,\n ExternalLink,\n MapPin,\n Calendar,\n Columns,\n GitBranch,\n Puzzle,\n LayoutDashboard,\n};\n\nfunction getIconComponent(iconName: string): LucideIcon {\n return ICON_MAP[iconName] || Puzzle;\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface WidgetTypeSelectorProps {\n selectedType?: WidgetType;\n onSelect: (type: WidgetType, definition?: WidgetDefinition) => void;\n categories?: WidgetCategory[];\n onRendererSelect?: (renderer: RendererType) => void;\n selectedRenderer?: RendererType;\n /** Installed widgets from the store (fetched by parent) */\n installedWidgets?: WidgetDefinition[];\n /**\n * Built-in widget catalog (from the backend `getWidgetTypes`, fetched by the\n * parent via useWidgetCatalog). When omitted, falls back to the bundled\n * static registry.\n */\n definitions?: WidgetDefinition[];\n}\n\ntype RendererFilter = RendererType | 'ALL';\n\ninterface RendererFilterOption {\n id: RendererFilter;\n label: string;\n icon: LucideIcon;\n}\n\nconst RENDERER_FILTERS: RendererFilterOption[] = [\n { id: 'ALL', label: 'All', icon: Layers },\n { id: 'ADAPTIVE_CARD', label: 'Adaptive Card', icon: CreditCard },\n { id: 'BLOCKKIT', label: 'Block Kit', icon: MessageSquare },\n { id: 'CUSTOM', label: 'Custom', icon: Code },\n];\n\n// Widget types that support each renderer (for filtering)\nconst RENDERER_WIDGET_TYPES: Record<RendererFilter, WidgetType[] | 'all'> = {\n ALL: 'all',\n BIGCONSOLE: 'all',\n ADAPTIVE_CARD: ['metric_card', 'kpi_card_comparison', 'text', 'list', 'table', 'form', 'custom'],\n BLOCKKIT: ['metric_card', 'kpi_card_comparison', 'text', 'list', 'table', 'custom'],\n CUSTOM: ['custom'],\n};\n\nconst ALL_CATEGORIES: WidgetCategory[] = ['KPI', 'Visualization', 'Data', 'Content', 'Temporal', 'Custom', 'Installed'];\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const WidgetTypeSelector: FC<WidgetTypeSelectorProps> = memo(function WidgetTypeSelector({\n selectedType,\n onSelect,\n categories,\n onRendererSelect,\n selectedRenderer,\n installedWidgets = [],\n definitions,\n}) {\n const [searchQuery, setSearchQuery] = useState('');\n const [rendererFilter, setRendererFilter] = useState<RendererFilter>(selectedRenderer || 'ALL');\n\n // Group the provided catalog by category; fall back to the bundled registry\n // when the parent doesn't supply a backend-sourced catalog.\n const definitionsByCategory = useMemo(() => {\n const source = definitions ?? getAllWidgetDefinitions();\n const grouped: Partial<Record<WidgetCategory, WidgetDefinition[]>> = {};\n for (const def of source) {\n (grouped[def.category] ??= []).push(def);\n }\n return grouped;\n }, [definitions]);\n\n const widgetsByCategory = useMemo(() => {\n const cats = categories || ALL_CATEGORIES;\n const grouped: Record<string, WidgetDefinition[]> = {};\n\n // Get allowed widget types for current renderer filter\n const allowedTypes = RENDERER_WIDGET_TYPES[rendererFilter];\n\n for (const cat of cats) {\n let widgets = cat === 'Installed' ? installedWidgets : (definitionsByCategory[cat] ?? []);\n\n // Filter by search query\n if (searchQuery.trim()) {\n const query = searchQuery.toLowerCase();\n widgets = widgets.filter(\n (w) => w.name.toLowerCase().includes(query) || w.description.toLowerCase().includes(query)\n );\n }\n\n // Filter by renderer\n if (allowedTypes !== 'all') {\n widgets = widgets.filter((w) => allowedTypes.includes(w.type));\n }\n\n if (widgets.length > 0) {\n grouped[cat] = widgets;\n }\n }\n\n return grouped;\n }, [searchQuery, categories, rendererFilter, installedWidgets, definitionsByCategory]);\n\n const handleRendererFilterChange = useCallback(\n (filter: RendererFilter) => {\n setRendererFilter(filter);\n if (onRendererSelect && filter !== 'ALL') {\n onRendererSelect(filter as RendererType);\n }\n },\n [onRendererSelect]\n );\n\n const handleSelect = useCallback(\n (type: WidgetType, definition?: WidgetDefinition) => {\n onSelect(type, definition);\n // If a specific renderer is selected, notify parent\n if (rendererFilter !== 'ALL' && onRendererSelect) {\n onRendererSelect(rendererFilter as RendererType);\n }\n },\n [onSelect, rendererFilter, onRendererSelect]\n );\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', height: '100%', maxHeight: '500px', maxWidth: '500px' }}>\n {/* Renderer Filter Tabs */}\n <div style={{ padding: '8px 12px', borderBottom: '1px solid var(--color-border)' }}>\n <div\n style={{\n display: 'flex',\n gap: '4px',\n backgroundColor: 'var(--color-bg-muted)',\n padding: '3px',\n borderRadius: '6px',\n }}\n >\n {RENDERER_FILTERS.map((filter) => {\n const Icon = filter.icon;\n const isActive = rendererFilter === filter.id;\n return (\n <button\n key={filter.id}\n type=\"button\"\n onClick={() => handleRendererFilterChange(filter.id)}\n style={{\n flex: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '4px',\n padding: '6px 8px',\n borderRadius: '4px',\n border: 'none',\n fontSize: '11px',\n fontWeight: 500,\n cursor: 'pointer',\n transition: 'all 0.15s ease',\n backgroundColor: isActive ? 'var(--color-bg-surface, white)' : 'transparent',\n color: isActive ? 'var(--color-primary)' : 'var(--color-text-secondary)',\n boxShadow: isActive ? '0 1px 2px rgba(0,0,0,0.05)' : 'none',\n }}\n >\n <Icon style={{ width: '12px', height: '12px' }} />\n <span>{filter.label}</span>\n </button>\n );\n })}\n </div>\n </div>\n\n {/* Search */}\n <div style={{ padding: '8px 12px', borderBottom: '1px solid var(--color-border)' }}>\n <div style={{ position: 'relative' }}>\n <Search\n style={{\n position: 'absolute',\n left: '10px',\n top: '50%',\n transform: 'translateY(-50%)',\n width: '14px',\n height: '14px',\n color: 'var(--color-text-secondary)',\n }}\n />\n <Input\n type=\"text\"\n placeholder=\"Search widgets...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n style={{ paddingLeft: '32px', height: '32px', fontSize: '13px' }}\n />\n </div>\n </div>\n\n {/* Categories and widgets - with visible scrollbar */}\n <div\n style={{\n flex: 1,\n overflowY: 'auto',\n padding: '12px',\n backgroundColor: 'var(--color-bg-sunken)',\n maxHeight: '350px',\n minHeight: '200px',\n }}\n >\n {Object.entries(widgetsByCategory).map(([category, widgets]) => (\n <div key={category} style={{ marginBottom: '16px' }}>\n <h3\n style={{\n fontSize: '11px',\n fontWeight: 600,\n textTransform: 'uppercase',\n letterSpacing: '0.05em',\n color: 'var(--color-text-secondary)',\n marginBottom: '8px',\n paddingLeft: '4px',\n }}\n >\n {category === 'search'\n ? `Search Results (${widgets.length})`\n : WIDGET_CATEGORY_LABELS[category as WidgetCategory]}\n </h3>\n\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(2, 1fr)',\n gap: '8px',\n }}\n >\n {widgets.map((widget) => {\n const Icon = getIconComponent(widget.icon);\n const widgetKey = getWidgetKey(widget);\n // For installed widgets (all typed as 'custom'), avoid highlighting\n // every installed widget when one is selected.\n const isSelected = widget.category !== 'Installed' && selectedType === widget.type;\n\n return (\n <div\n key={widgetKey}\n onClick={() => handleSelect(widget.type, widget)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n padding: '10px 12px',\n borderRadius: '8px',\n border: isSelected ? '2px solid var(--color-action-primary-bg)' : '1px solid var(--color-border)',\n backgroundColor: isSelected ? 'var(--color-action-primary-bg)' : 'var(--color-bg-surface)',\n cursor: 'pointer',\n transition: 'all 0.15s ease',\n boxShadow: isSelected ? 'var(--shadow-elevation-2)' : 'var(--shadow-elevation-1)',\n }}\n onMouseEnter={(e) => {\n if (!isSelected) {\n e.currentTarget.style.borderColor = 'var(--color-action-primary-bg)';\n e.currentTarget.style.backgroundColor = 'var(--color-bg-sunken)';\n e.currentTarget.style.boxShadow = 'var(--shadow-elevation-2)';\n }\n }}\n onMouseLeave={(e) => {\n if (!isSelected) {\n e.currentTarget.style.borderColor = 'var(--color-border)';\n e.currentTarget.style.backgroundColor = 'var(--color-bg-surface)';\n e.currentTarget.style.boxShadow = 'var(--shadow-elevation-1)';\n }\n }}\n >\n <div\n style={{\n width: '32px',\n height: '32px',\n flexShrink: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: '6px',\n backgroundColor: isSelected ? 'var(--color-action-primary-bg)' : 'var(--color-bg-muted)',\n color: isSelected ? 'var(--color-action-primary-text)' : 'var(--color-text-secondary)',\n }}\n >\n <Icon style={{ width: '16px', height: '16px' }} />\n </div>\n <span\n style={{\n fontSize: '13px',\n fontWeight: 500,\n color: isSelected ? 'var(--color-action-primary-text)' : 'var(--color-text-primary)',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {widget.name}\n </span>\n </div>\n );\n })}\n </div>\n </div>\n ))}\n\n {Object.keys(widgetsByCategory).length === 0 && (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '32px',\n color: 'var(--color-text-secondary)',\n }}\n >\n <Search style={{ width: '32px', height: '32px', marginBottom: '12px', opacity: 0.5 }} />\n <p style={{ fontSize: '13px' }}>No widgets found</p>\n </div>\n )}\n </div>\n </div>\n );\n});\n\nexport default WidgetTypeSelector;\n"],"mappings":";;;;;;AA0CA,IAAM,IAAuC;CAC3C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,SAAS,EAAiB,GAA8B;AACtD,QAAO,EAAS,MAAa;;AA+B/B,IAAM,IAA2C;CAC/C;EAAE,IAAI;EAAO,OAAO;EAAO,MAAM;EAAQ;CACzC;EAAE,IAAI;EAAiB,OAAO;EAAiB,MAAM;EAAY;CACjE;EAAE,IAAI;EAAY,OAAO;EAAa,MAAM;EAAe;CAC3D;EAAE,IAAI;EAAU,OAAO;EAAU,MAAM;EAAM;CAC9C,EAGK,IAAsE;CAC1E,KAAK;CACL,YAAY;CACZ,eAAe;EAAC;EAAe;EAAuB;EAAQ;EAAQ;EAAS;EAAQ;EAAS;CAChG,UAAU;EAAC;EAAe;EAAuB;EAAQ;EAAQ;EAAS;EAAS;CACnF,QAAQ,CAAC,SAAS;CACnB,EAEK,IAAmC;CAAC;CAAO;CAAiB;CAAQ;CAAW;CAAY;CAAU;CAAY,EAM1G,IAAkD,EAAK,SAA4B,EAC9F,iBACA,aACA,eACA,qBACA,qBACA,sBAAmB,EAAE,EACrB,kBACC;CACD,IAAM,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,CAAC,GAAgB,KAAqB,EAAyB,KAAoB,MAAM,EAIzF,IAAwB,QAAc;EAC1C,IAAM,IAAS,KAAe,GAAyB,EACjD,IAA+D,EAAE;AACvE,OAAK,IAAM,KAAO,EAChB,EAAC,EAAQ,EAAI,cAAc,EAAE,EAAE,KAAK,EAAI;AAE1C,SAAO;IACN,CAAC,EAAY,CAAC,EAEX,IAAoB,QAAc;EACtC,IAAM,IAAO,KAAc,GACrB,IAA8C,EAAE,EAGhD,IAAe,EAAsB;AAE3C,OAAK,IAAM,KAAO,GAAM;GACtB,IAAI,IAAU,MAAQ,cAAc,IAAoB,EAAsB,MAAQ,EAAE;AAGxF,OAAI,EAAY,MAAM,EAAE;IACtB,IAAM,IAAQ,EAAY,aAAa;AACvC,QAAU,EAAQ,QACf,MAAM,EAAE,KAAK,aAAa,CAAC,SAAS,EAAM,IAAI,EAAE,YAAY,aAAa,CAAC,SAAS,EAAM,CAC3F;;AAQH,GAJI,MAAiB,UACnB,IAAU,EAAQ,QAAQ,MAAM,EAAa,SAAS,EAAE,KAAK,CAAC,GAG5D,EAAQ,SAAS,MACnB,EAAQ,KAAO;;AAInB,SAAO;IACN;EAAC;EAAa;EAAY;EAAgB;EAAkB;EAAsB,CAAC,EAEhF,IAA6B,GAChC,MAA2B;AAE1B,EADA,EAAkB,EAAO,EACrB,KAAoB,MAAW,SACjC,EAAiB,EAAuB;IAG5C,CAAC,EAAiB,CACnB,EAEK,IAAe,GAClB,GAAkB,MAAkC;AAGnD,EAFA,EAAS,GAAM,EAAW,EAEtB,MAAmB,SAAS,KAC9B,EAAiB,EAA+B;IAGpD;EAAC;EAAU;EAAgB;EAAiB,CAC7C;AAED,QACE,kBAAC,OAAD;EAAK,OAAO;GAAE,SAAS;GAAQ,eAAe;GAAU,QAAQ;GAAQ,WAAW;GAAS,UAAU;GAAS;YAA/G;GAEE,kBAAC,OAAD;IAAK,OAAO;KAAE,SAAS;KAAY,cAAc;KAAiC;cAChF,kBAAC,OAAD;KACE,OAAO;MACL,SAAS;MACT,KAAK;MACL,iBAAiB;MACjB,SAAS;MACT,cAAc;MACf;eAEA,EAAiB,KAAK,MAAW;MAChC,IAAM,IAAO,EAAO,MACd,IAAW,MAAmB,EAAO;AAC3C,aACE,kBAAC,UAAD;OAEE,MAAK;OACL,eAAe,EAA2B,EAAO,GAAG;OACpD,OAAO;QACL,MAAM;QACN,SAAS;QACT,YAAY;QACZ,gBAAgB;QAChB,KAAK;QACL,SAAS;QACT,cAAc;QACd,QAAQ;QACR,UAAU;QACV,YAAY;QACZ,QAAQ;QACR,YAAY;QACZ,iBAAiB,IAAW,mCAAmC;QAC/D,OAAO,IAAW,yBAAyB;QAC3C,WAAW,IAAW,+BAA+B;QACtD;iBApBH,CAsBE,kBAAC,GAAD,EAAM,OAAO;QAAE,OAAO;QAAQ,QAAQ;QAAQ,EAAI,CAAA,EAClD,kBAAC,QAAD,EAAA,UAAO,EAAO,OAAa,CAAA,CACpB;SAvBF,EAAO,GAuBL;OAEX;KACE,CAAA;IACF,CAAA;GAGN,kBAAC,OAAD;IAAK,OAAO;KAAE,SAAS;KAAY,cAAc;KAAiC;cAChF,kBAAC,OAAD;KAAK,OAAO,EAAE,UAAU,YAAY;eAApC,CACE,kBAAC,GAAD,EACE,OAAO;MACL,UAAU;MACV,MAAM;MACN,KAAK;MACL,WAAW;MACX,OAAO;MACP,QAAQ;MACR,OAAO;MACR,EACD,CAAA,EACF,kBAAC,GAAD;MACE,MAAK;MACL,aAAY;MACZ,OAAO;MACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAM;MAC/C,OAAO;OAAE,aAAa;OAAQ,QAAQ;OAAQ,UAAU;OAAQ;MAChE,CAAA,CACE;;IACF,CAAA;GAGN,kBAAC,OAAD;IACE,OAAO;KACL,MAAM;KACN,WAAW;KACX,SAAS;KACT,iBAAiB;KACjB,WAAW;KACX,WAAW;KACZ;cARH,CAUG,OAAO,QAAQ,EAAkB,CAAC,KAAK,CAAC,GAAU,OACjD,kBAAC,OAAD;KAAoB,OAAO,EAAE,cAAc,QAAQ;eAAnD,CACE,kBAAC,MAAD;MACE,OAAO;OACL,UAAU;OACV,YAAY;OACZ,eAAe;OACf,eAAe;OACf,OAAO;OACP,cAAc;OACd,aAAa;OACd;gBAEA,MAAa,WACV,mBAAmB,EAAQ,OAAO,KAClC,EAAuB;MACxB,CAAA,EAEL,kBAAC,OAAD;MACE,OAAO;OACL,SAAS;OACT,qBAAqB;OACrB,KAAK;OACN;gBAEA,EAAQ,KAAK,MAAW;OACvB,IAAM,IAAO,EAAiB,EAAO,KAAK,EACpC,IAAY,EAAa,EAAO,EAGhC,IAAa,EAAO,aAAa,eAAe,MAAiB,EAAO;AAE9E,cACE,kBAAC,OAAD;QAEE,eAAe,EAAa,EAAO,MAAM,EAAO;QAChD,OAAO;SACL,SAAS;SACT,YAAY;SACZ,KAAK;SACL,SAAS;SACT,cAAc;SACd,QAAQ,IAAa,6CAA6C;SAClE,iBAAiB,IAAa,mCAAmC;SACjE,QAAQ;SACR,YAAY;SACZ,WAAW,IAAa,8BAA8B;SACvD;QACD,eAAe,MAAM;AACnB,SAAK,MACH,EAAE,cAAc,MAAM,cAAc,kCACpC,EAAE,cAAc,MAAM,kBAAkB,0BACxC,EAAE,cAAc,MAAM,YAAY;;QAGtC,eAAe,MAAM;AACnB,SAAK,MACH,EAAE,cAAc,MAAM,cAAc,uBACpC,EAAE,cAAc,MAAM,kBAAkB,2BACxC,EAAE,cAAc,MAAM,YAAY;;kBA1BxC,CA8BE,kBAAC,OAAD;SACE,OAAO;UACL,OAAO;UACP,QAAQ;UACR,YAAY;UACZ,SAAS;UACT,YAAY;UACZ,gBAAgB;UAChB,cAAc;UACd,iBAAiB,IAAa,mCAAmC;UACjE,OAAO,IAAa,qCAAqC;UAC1D;mBAED,kBAAC,GAAD,EAAM,OAAO;UAAE,OAAO;UAAQ,QAAQ;UAAQ,EAAI,CAAA;SAC9C,CAAA,EACN,kBAAC,QAAD;SACE,OAAO;UACL,UAAU;UACV,YAAY;UACZ,OAAO,IAAa,qCAAqC;UACzD,UAAU;UACV,cAAc;UACd,YAAY;UACb;mBAEA,EAAO;SACH,CAAA,CACH;UAxDC,EAwDD;QAER;MACE,CAAA,CACF;OA7FI,EA6FJ,CACN,EAED,OAAO,KAAK,EAAkB,CAAC,WAAW,KACzC,kBAAC,OAAD;KACE,OAAO;MACL,SAAS;MACT,eAAe;MACf,YAAY;MACZ,gBAAgB;MAChB,SAAS;MACT,OAAO;MACR;eARH,CAUE,kBAAC,GAAD,EAAQ,OAAO;MAAE,OAAO;MAAQ,QAAQ;MAAQ,cAAc;MAAQ,SAAS;MAAK,EAAI,CAAA,EACxF,kBAAC,KAAD;MAAG,OAAO,EAAE,UAAU,QAAQ;gBAAE;MAAoB,CAAA,CAChD;OAEJ;;GACF;;EAER"}
|
|
@@ -2,11 +2,11 @@ import { useIsWidgetSelected as e, useWidgetStore as t, useWidgetUIState as n }
|
|
|
2
2
|
import { useDashboardStore as r, useGlobalFilterValues as i } from "../../store/dashboardStore.js";
|
|
3
3
|
import "../../store/index.js";
|
|
4
4
|
import a from "../../hooks/useWidgetData.js";
|
|
5
|
-
import {
|
|
6
|
-
import te from "../../hooks/
|
|
7
|
-
import ne from "../../hooks/
|
|
5
|
+
import { getWidgetDefinition as o } from "./WidgetRegistry.js";
|
|
6
|
+
import { formatTimeUntilRefresh as ee, useWidgetAutoRefresh as te } from "../../hooks/useAutoRefresh.js";
|
|
7
|
+
import ne from "../../hooks/useWidgetExport.js";
|
|
8
|
+
import re from "../../hooks/useDrilldown.js";
|
|
8
9
|
import "../../hooks/index.js";
|
|
9
|
-
import { getWidgetDefinition as re } from "./WidgetRegistry.js";
|
|
10
10
|
import ie from "./WidgetHeader.js";
|
|
11
11
|
import s from "./states/LoadingState.js";
|
|
12
12
|
import ae from "./states/ErrorState.js";
|
|
@@ -47,13 +47,13 @@ var x = p(function({ widget: f, children: p, data: b, className: x = "", isLoadi
|
|
|
47
47
|
N,
|
|
48
48
|
j,
|
|
49
49
|
E
|
|
50
|
-
]), F = Object.keys(P).length > 0, I = Te ?? (Oe && !M) ?? A.isLoading, L = Ee ?? A.errorMessage, ke =
|
|
50
|
+
]), F = Object.keys(P).length > 0, I = Te ?? (Oe && !M) ?? A.isLoading, L = Ee ?? A.errorMessage, ke = o(f.type), R = g(S);
|
|
51
51
|
le(() => {
|
|
52
52
|
R.current = S;
|
|
53
53
|
}, [S]);
|
|
54
54
|
let Ae = m(async () => {
|
|
55
55
|
R.current && await R.current();
|
|
56
|
-
}, []), { timeUntilRefresh: je, isPaused: Me } =
|
|
56
|
+
}, []), { timeUntilRefresh: je, isPaused: Me } = te({
|
|
57
57
|
widgetId: f.id,
|
|
58
58
|
refreshInterval: f.refreshInterval,
|
|
59
59
|
onRefresh: Ae,
|
|
@@ -67,7 +67,7 @@ var x = p(function({ widget: f, children: p, data: b, className: x = "", isLoadi
|
|
|
67
67
|
if (Array.isArray(t)) return t;
|
|
68
68
|
}
|
|
69
69
|
return null;
|
|
70
|
-
}, [b, f]), { exportCSV: Ne, exportPNG: Pe } =
|
|
70
|
+
}, [b, f]), { exportCSV: Ne, exportPNG: Pe } = ne(f, {
|
|
71
71
|
data: B,
|
|
72
72
|
containerRef: z
|
|
73
73
|
}), V = m((e) => {
|
|
@@ -239,7 +239,7 @@ var x = p(function({ widget: f, children: p, data: b, className: x = "", isLoadi
|
|
|
239
239
|
H,
|
|
240
240
|
P,
|
|
241
241
|
V
|
|
242
|
-
]), W = h(() => U ?? null, [U]), { executeDrilldown: G, canDrilldown: K } =
|
|
242
|
+
]), W = h(() => U ?? null, [U]), { executeDrilldown: G, canDrilldown: K } = re({ onDrilldown: (e, t) => {
|
|
243
243
|
C?.(e);
|
|
244
244
|
} }), q = h(() => K(f), [f, K]), J = m((e) => {
|
|
245
245
|
if (!f.drilldown?.enabled) return;
|
|
@@ -440,7 +440,7 @@ var x = p(function({ widget: f, children: p, data: b, className: x = "", isLoadi
|
|
|
440
440
|
isSelected: k,
|
|
441
441
|
isEditMode: D,
|
|
442
442
|
isLoading: I,
|
|
443
|
-
timeUntilRefresh: f.refreshInterval && !Me ?
|
|
443
|
+
timeUntilRefresh: f.refreshInterval && !Me ? ee(je) : void 0,
|
|
444
444
|
hasDrilldown: q,
|
|
445
445
|
onRefresh: S,
|
|
446
446
|
onExportCSV: B ? Ne : void 0,
|