@burdenoff/microfe-bigconsole 2026.613.3 → 2026.613.4
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/widgets/WidgetRegistry.js +55 -1
- package/dist/bigconsole/components/widgets/WidgetRegistry.js.map +1 -1
- package/dist/bigconsole/components/widgets/chart/ChartWidget.js +123 -91
- package/dist/bigconsole/components/widgets/chart/ChartWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/chart/charts/AreaChart.js +40 -35
- package/dist/bigconsole/components/widgets/chart/charts/AreaChart.js.map +1 -1
- package/dist/bigconsole/components/widgets/chart/charts/BarChart.js +30 -25
- package/dist/bigconsole/components/widgets/chart/charts/BarChart.js.map +1 -1
- package/dist/bigconsole/components/widgets/chart/charts/ComboChart.js +139 -0
- package/dist/bigconsole/components/widgets/chart/charts/ComboChart.js.map +1 -0
- package/dist/bigconsole/components/widgets/chart/charts/LineChart.js +35 -30
- package/dist/bigconsole/components/widgets/chart/charts/LineChart.js.map +1 -1
- package/dist/bigconsole/components/widgets/chart/charts/ScatterChart.js +128 -0
- package/dist/bigconsole/components/widgets/chart/charts/ScatterChart.js.map +1 -0
- package/dist/bigconsole/components/widgets/chart/charts/WaterfallChart.js +111 -0
- package/dist/bigconsole/components/widgets/chart/charts/WaterfallChart.js.map +1 -0
- package/dist/bigconsole/components/widgets/chart/charts/index.js +4 -0
- package/dist/bigconsole/components/widgets/chart/charts/referenceElements.js +49 -0
- package/dist/bigconsole/components/widgets/chart/charts/referenceElements.js.map +1 -0
- package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js +72 -68
- package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/map-widget/MapWidget.js +74 -24
- package/dist/bigconsole/components/widgets/map-widget/MapWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js +87 -86
- package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/table/TableCell.js +55 -26
- package/dist/bigconsole/components/widgets/table/TableCell.js.map +1 -1
- package/dist/bigconsole/components/widgets/table/TableHeader.js +25 -18
- package/dist/bigconsole/components/widgets/table/TableHeader.js.map +1 -1
- package/dist/bigconsole/components/widgets/table/TableWidget.js +255 -107
- package/dist/bigconsole/components/widgets/table/TableWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/utils/conditionalFormat.js +91 -0
- package/dist/bigconsole/components/widgets/utils/conditionalFormat.js.map +1 -0
- package/dist/bigconsole/hooks/index.js +1 -0
- package/dist/bigconsole/hooks/useDashboardImageExport.js +1 -0
- package/dist/bigconsole/utils/widgetTypeMapping.js +1 -0
- package/dist/bigconsole/utils/widgetTypeMapping.js.map +1 -1
- package/package.json +1 -1
|
@@ -34,6 +34,7 @@ var e = {
|
|
|
34
34
|
supportsDataBinding: !0,
|
|
35
35
|
supportsDrilldown: !0,
|
|
36
36
|
supportsAutoRefresh: !0,
|
|
37
|
+
supportsConditionalFormat: !0,
|
|
37
38
|
tags: [
|
|
38
39
|
"kpi",
|
|
39
40
|
"comparison",
|
|
@@ -75,6 +76,7 @@ var e = {
|
|
|
75
76
|
supportsDataBinding: !0,
|
|
76
77
|
supportsDrilldown: !0,
|
|
77
78
|
supportsAutoRefresh: !0,
|
|
79
|
+
supportsConditionalFormat: !0,
|
|
78
80
|
tags: [
|
|
79
81
|
"kpi",
|
|
80
82
|
"metric",
|
|
@@ -117,6 +119,9 @@ var e = {
|
|
|
117
119
|
supportsDataBinding: !0,
|
|
118
120
|
supportsDrilldown: !0,
|
|
119
121
|
supportsAutoRefresh: !0,
|
|
122
|
+
supportsConditionalFormat: !0,
|
|
123
|
+
supportsThresholds: !0,
|
|
124
|
+
supportsDualAxis: !0,
|
|
120
125
|
tags: [
|
|
121
126
|
"chart",
|
|
122
127
|
"graph",
|
|
@@ -124,7 +129,9 @@ var e = {
|
|
|
124
129
|
"line",
|
|
125
130
|
"bar",
|
|
126
131
|
"area",
|
|
127
|
-
"pie"
|
|
132
|
+
"pie",
|
|
133
|
+
"combo",
|
|
134
|
+
"dual-axis"
|
|
128
135
|
]
|
|
129
136
|
},
|
|
130
137
|
funnel_chart: {
|
|
@@ -203,6 +210,8 @@ var e = {
|
|
|
203
210
|
supportsDataBinding: !0,
|
|
204
211
|
supportsDrilldown: !0,
|
|
205
212
|
supportsAutoRefresh: !0,
|
|
213
|
+
supportsConditionalFormat: !0,
|
|
214
|
+
supportsTotals: !0,
|
|
206
215
|
tags: [
|
|
207
216
|
"table",
|
|
208
217
|
"data",
|
|
@@ -724,6 +733,51 @@ var e = {
|
|
|
724
733
|
"schedule"
|
|
725
734
|
]
|
|
726
735
|
},
|
|
736
|
+
retention: {
|
|
737
|
+
type: "retention",
|
|
738
|
+
name: "Retention / Cohort",
|
|
739
|
+
description: "Cohort-by-period retention grid with decay shading",
|
|
740
|
+
icon: "Grid3x3",
|
|
741
|
+
category: "Data",
|
|
742
|
+
component: null,
|
|
743
|
+
defaultConfig: {
|
|
744
|
+
cohortField: "cohort",
|
|
745
|
+
periodField: "period",
|
|
746
|
+
valueField: "value",
|
|
747
|
+
periodType: "month",
|
|
748
|
+
showPercentages: !0,
|
|
749
|
+
showAverages: !0,
|
|
750
|
+
showLegend: !0
|
|
751
|
+
},
|
|
752
|
+
defaultSize: {
|
|
753
|
+
width: 8,
|
|
754
|
+
height: 5
|
|
755
|
+
},
|
|
756
|
+
defaultResponsive: {
|
|
757
|
+
xs: 12,
|
|
758
|
+
sm: 12,
|
|
759
|
+
md: 8,
|
|
760
|
+
lg: 8
|
|
761
|
+
},
|
|
762
|
+
minSize: {
|
|
763
|
+
width: 4,
|
|
764
|
+
height: 3
|
|
765
|
+
},
|
|
766
|
+
maxSize: {
|
|
767
|
+
width: 12,
|
|
768
|
+
height: 10
|
|
769
|
+
},
|
|
770
|
+
supportsDataBinding: !0,
|
|
771
|
+
supportsDrilldown: !1,
|
|
772
|
+
supportsAutoRefresh: !0,
|
|
773
|
+
tags: [
|
|
774
|
+
"retention",
|
|
775
|
+
"cohort",
|
|
776
|
+
"grid",
|
|
777
|
+
"churn",
|
|
778
|
+
"saas"
|
|
779
|
+
]
|
|
780
|
+
},
|
|
727
781
|
custom: {
|
|
728
782
|
type: "custom",
|
|
729
783
|
name: "Custom Widget",
|
|
@@ -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 /**\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 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: 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 // 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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"}
|
|
@@ -5,86 +5,102 @@ import r from "./charts/BarChart.js";
|
|
|
5
5
|
import i from "./charts/AreaChart.js";
|
|
6
6
|
import a from "./charts/PieChart.js";
|
|
7
7
|
import o from "./charts/FunnelChart.js";
|
|
8
|
-
import s from "./
|
|
9
|
-
import
|
|
10
|
-
import
|
|
8
|
+
import s from "./charts/ComboChart.js";
|
|
9
|
+
import c from "./charts/WaterfallChart.js";
|
|
10
|
+
import l from "./charts/ScatterChart.js";
|
|
11
|
+
import u from "./ChartLegend.js";
|
|
12
|
+
import { memo as d, useCallback as f, useMemo as p, useState as m } from "react";
|
|
13
|
+
import { jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
11
14
|
//#region src/bigconsole/components/widgets/chart/ChartWidget.tsx
|
|
12
|
-
var
|
|
15
|
+
var _ = [
|
|
13
16
|
"var(--color-chart-1)",
|
|
14
17
|
"var(--color-chart-2)",
|
|
15
18
|
"var(--color-chart-3)",
|
|
16
19
|
"var(--color-chart-4)",
|
|
17
20
|
"var(--color-chart-5)"
|
|
18
|
-
],
|
|
19
|
-
let
|
|
20
|
-
sourceField:
|
|
21
|
+
], v = d(function({ widget: d, data: v = [], onClick: y, onDrilldown: b }) {
|
|
22
|
+
let x = d.config, [S, C] = m([]), { handleDataClick: w, enabled: T } = t(d.id, x?.crossFilterMappings || [{
|
|
23
|
+
sourceField: x?.labelField || "name",
|
|
21
24
|
targetFilterId: "category"
|
|
22
|
-
}]), { clearAllCrossFilters:
|
|
23
|
-
type:
|
|
24
|
-
xAxisKey:
|
|
25
|
-
xAxisLabel:
|
|
26
|
-
yAxisLabel:
|
|
27
|
-
showGrid:
|
|
28
|
-
showLegend:
|
|
29
|
-
legendPosition:
|
|
30
|
-
showDots:
|
|
31
|
-
curveType:
|
|
32
|
-
colors:
|
|
33
|
-
seriesNames:
|
|
34
|
-
stacked:
|
|
35
|
-
isDonut:
|
|
36
|
-
innerRadius:
|
|
37
|
-
outerRadius:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
25
|
+
}]), { clearAllCrossFilters: E, hasCrossFilters: D } = e(), O = p(() => ({
|
|
26
|
+
type: x?.chartType?.toLowerCase() || "line",
|
|
27
|
+
xAxisKey: x?.xAxisField || "name",
|
|
28
|
+
xAxisLabel: x?.xAxisLabel,
|
|
29
|
+
yAxisLabel: x?.yAxisLabel,
|
|
30
|
+
showGrid: x?.showGrid,
|
|
31
|
+
showLegend: x?.showLegend,
|
|
32
|
+
legendPosition: x?.legendPosition,
|
|
33
|
+
showDots: x?.showDataPoints,
|
|
34
|
+
curveType: x?.curveType,
|
|
35
|
+
colors: x?.colors,
|
|
36
|
+
seriesNames: x?.seriesLabels,
|
|
37
|
+
stacked: x?.stacked,
|
|
38
|
+
isDonut: x?.showAsDonut,
|
|
39
|
+
innerRadius: x?.innerRadius,
|
|
40
|
+
outerRadius: x?.outerRadius,
|
|
41
|
+
referenceLines: x?.referenceLines,
|
|
42
|
+
series: x?.series,
|
|
43
|
+
dualAxis: x?.dualAxis,
|
|
44
|
+
yAxisRightLabel: x?.yAxisRightLabel,
|
|
45
|
+
logScale: x?.logScale,
|
|
46
|
+
valueField: x?.valueField,
|
|
47
|
+
labelField: x?.labelField,
|
|
48
|
+
showTotal: x?.showTotal,
|
|
49
|
+
totalLabel: x?.totalLabel,
|
|
50
|
+
xField: x?.xField,
|
|
51
|
+
yField: x?.yField,
|
|
52
|
+
sizeField: x?.sizeField,
|
|
53
|
+
colorField: x?.colorField
|
|
54
|
+
}), [x]), k = p(() => {
|
|
55
|
+
if (!v.length || O.type === "pie" || O.type === "funnel" || O.type === "scatter" || O.type === "waterfall") return [];
|
|
56
|
+
let e = x?.selectedFields;
|
|
57
|
+
return Object.keys(v[0]).filter((t) => {
|
|
58
|
+
let n = t !== O.xAxisKey && typeof v[0][t] == "number";
|
|
43
59
|
return e && e.length > 0 ? n && e.includes(t) : n;
|
|
44
60
|
}).map((e, t) => ({
|
|
45
61
|
dataKey: e,
|
|
46
|
-
name:
|
|
47
|
-
color:
|
|
48
|
-
hidden:
|
|
62
|
+
name: O.seriesNames?.[e] || e,
|
|
63
|
+
color: O.colors?.[t] || _[t % _.length],
|
|
64
|
+
hidden: S.includes(e)
|
|
49
65
|
}));
|
|
50
66
|
}, [
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
]),
|
|
56
|
-
|
|
57
|
-
}, []),
|
|
58
|
-
if (
|
|
59
|
-
let t = e[
|
|
60
|
-
|
|
67
|
+
v,
|
|
68
|
+
O,
|
|
69
|
+
S,
|
|
70
|
+
x?.selectedFields
|
|
71
|
+
]), A = f((e) => {
|
|
72
|
+
C((t) => t.includes(e) ? t.filter((t) => t !== e) : [...t, e]);
|
|
73
|
+
}, []), j = f((e, t) => {
|
|
74
|
+
if (T) {
|
|
75
|
+
let t = e[x?.labelField || "name"];
|
|
76
|
+
w(e, t);
|
|
61
77
|
}
|
|
62
|
-
|
|
78
|
+
b ? b(e) : y && d.drilldowns?.length && y(e, t);
|
|
63
79
|
}, [
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
]);
|
|
71
|
-
return /* @__PURE__ */
|
|
80
|
+
y,
|
|
81
|
+
b,
|
|
82
|
+
d.drilldowns,
|
|
83
|
+
T,
|
|
84
|
+
w,
|
|
85
|
+
x?.labelField
|
|
86
|
+
]), M = O.type === "combo" || O.dualAxis === !0 || O.series?.some((e) => e.axis === "right" || e.type === "bar") && O.series?.some((e) => e.type === "line") || !1;
|
|
87
|
+
return /* @__PURE__ */ g("div", {
|
|
72
88
|
className: "flex flex-col h-full p-4",
|
|
73
89
|
children: [
|
|
74
|
-
|
|
90
|
+
D && /* @__PURE__ */ h("div", {
|
|
75
91
|
className: "flex items-center gap-2 mb-2 -mt-1",
|
|
76
|
-
children: /* @__PURE__ */
|
|
92
|
+
children: /* @__PURE__ */ g("button", {
|
|
77
93
|
type: "button",
|
|
78
94
|
onClick: (e) => {
|
|
79
|
-
e.stopPropagation(),
|
|
95
|
+
e.stopPropagation(), E();
|
|
80
96
|
},
|
|
81
97
|
className: "\n inline-flex items-center gap-1.5\n px-2.5 py-1 rounded-md\n text-xs font-medium\n bg-action-primary-bg/10 text-action-primary-text\n hover:bg-action-primary-bg/20\n transition-colors\n ",
|
|
82
|
-
children: [/* @__PURE__ */
|
|
98
|
+
children: [/* @__PURE__ */ h("svg", {
|
|
83
99
|
className: "w-3.5 h-3.5",
|
|
84
100
|
fill: "none",
|
|
85
101
|
stroke: "currentColor",
|
|
86
102
|
viewBox: "0 0 24 24",
|
|
87
|
-
children: /* @__PURE__ */
|
|
103
|
+
children: /* @__PURE__ */ h("path", {
|
|
88
104
|
strokeLinecap: "round",
|
|
89
105
|
strokeLinejoin: "round",
|
|
90
106
|
strokeWidth: 2,
|
|
@@ -93,59 +109,75 @@ var m = [
|
|
|
93
109
|
}), "Clear Filter"]
|
|
94
110
|
})
|
|
95
111
|
}),
|
|
96
|
-
|
|
97
|
-
items:
|
|
112
|
+
O.legendPosition === "top" && k.length > 0 && /* @__PURE__ */ h(u, {
|
|
113
|
+
items: k,
|
|
98
114
|
position: "top",
|
|
99
|
-
onItemClick:
|
|
115
|
+
onItemClick: A
|
|
100
116
|
}),
|
|
101
|
-
/* @__PURE__ */
|
|
117
|
+
/* @__PURE__ */ h("div", {
|
|
102
118
|
className: "flex-1 min-h-0",
|
|
103
119
|
children: (() => {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
120
|
+
if (M) return /* @__PURE__ */ h(s, {
|
|
121
|
+
data: v,
|
|
122
|
+
config: O,
|
|
123
|
+
hiddenSeries: S,
|
|
124
|
+
onDataClick: j
|
|
125
|
+
});
|
|
126
|
+
switch (O.type) {
|
|
127
|
+
case "waterfall": return /* @__PURE__ */ h(c, {
|
|
128
|
+
data: v,
|
|
129
|
+
config: O,
|
|
130
|
+
onDataClick: j
|
|
131
|
+
});
|
|
132
|
+
case "scatter": return /* @__PURE__ */ h(l, {
|
|
133
|
+
data: v,
|
|
134
|
+
config: O,
|
|
135
|
+
onDataClick: j
|
|
136
|
+
});
|
|
137
|
+
case "bar": return /* @__PURE__ */ h(r, {
|
|
138
|
+
data: v,
|
|
139
|
+
config: O,
|
|
140
|
+
hiddenSeries: S,
|
|
141
|
+
onDataClick: j
|
|
110
142
|
});
|
|
111
|
-
case "area": return /* @__PURE__ */
|
|
112
|
-
data:
|
|
113
|
-
config:
|
|
114
|
-
hiddenSeries:
|
|
115
|
-
onDataClick:
|
|
143
|
+
case "area": return /* @__PURE__ */ h(i, {
|
|
144
|
+
data: v,
|
|
145
|
+
config: O,
|
|
146
|
+
hiddenSeries: S,
|
|
147
|
+
onDataClick: j
|
|
116
148
|
});
|
|
117
|
-
case "pie": return /* @__PURE__ */
|
|
118
|
-
data:
|
|
119
|
-
config:
|
|
120
|
-
dataKey:
|
|
121
|
-
nameKey:
|
|
122
|
-
onDataClick:
|
|
149
|
+
case "pie": return /* @__PURE__ */ h(a, {
|
|
150
|
+
data: v,
|
|
151
|
+
config: O,
|
|
152
|
+
dataKey: x?.valueField || "value",
|
|
153
|
+
nameKey: x?.labelField || "name",
|
|
154
|
+
onDataClick: j
|
|
123
155
|
});
|
|
124
|
-
case "funnel": return /* @__PURE__ */
|
|
125
|
-
data:
|
|
126
|
-
config:
|
|
127
|
-
dataKey:
|
|
128
|
-
nameKey:
|
|
129
|
-
onDataClick:
|
|
156
|
+
case "funnel": return /* @__PURE__ */ h(o, {
|
|
157
|
+
data: v,
|
|
158
|
+
config: O,
|
|
159
|
+
dataKey: x?.valueField || "value",
|
|
160
|
+
nameKey: x?.labelField || "name",
|
|
161
|
+
onDataClick: j
|
|
130
162
|
});
|
|
131
|
-
default: return /* @__PURE__ */
|
|
132
|
-
data:
|
|
133
|
-
config:
|
|
134
|
-
hiddenSeries:
|
|
135
|
-
onDataClick:
|
|
163
|
+
default: return /* @__PURE__ */ h(n, {
|
|
164
|
+
data: v,
|
|
165
|
+
config: O,
|
|
166
|
+
hiddenSeries: S,
|
|
167
|
+
onDataClick: j
|
|
136
168
|
});
|
|
137
169
|
}
|
|
138
170
|
})()
|
|
139
171
|
}),
|
|
140
|
-
|
|
141
|
-
items:
|
|
172
|
+
O.legendPosition === "bottom" && k.length > 0 && /* @__PURE__ */ h(u, {
|
|
173
|
+
items: k,
|
|
142
174
|
position: "bottom",
|
|
143
|
-
onItemClick:
|
|
175
|
+
onItemClick: A
|
|
144
176
|
})
|
|
145
177
|
]
|
|
146
178
|
});
|
|
147
179
|
});
|
|
148
180
|
//#endregion
|
|
149
|
-
export {
|
|
181
|
+
export { v as default };
|
|
150
182
|
|
|
151
183
|
//# sourceMappingURL=ChartWidget.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChartWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/chart/ChartWidget.tsx"],"sourcesContent":["/**\n * ChartWidget Component\n *\n * Wrapper component that renders the appropriate chart type.\n */\n\nimport { type FC, memo, useState, useMemo, useCallback } from 'react';\nimport type { Widget, ChartConfig as WidgetChartConfig } from '../../../types';\nimport { LineChart } from './charts/LineChart';\nimport { BarChart } from './charts/BarChart';\nimport { AreaChart } from './charts/AreaChart';\nimport { PieChart } from './charts/PieChart';\nimport { FunnelChart } from './charts/FunnelChart';\nimport { ChartLegend, type LegendItem } from './ChartLegend';\nimport type { ChartConfig, ChartData, ChartType, CurveType } from './charts/types';\n// Phase 2: Cross-filtering support\nimport { useWidgetCrossFilter, useCrossFilterContext } from '../../../contexts';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ChartWidgetProps {\n /** Widget configuration */\n widget: Widget;\n /** Chart data */\n data?: ChartData[];\n /** Click handler for drilldown */\n onClick?: (dataPoint: ChartData, index: number) => void;\n /** Drilldown handler - receives selected data point */\n onDrilldown?: (selectedData: Record<string, unknown>) => void;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_COLORS = [\n 'var(--color-chart-1)',\n 'var(--color-chart-2)',\n 'var(--color-chart-3)',\n 'var(--color-chart-4)',\n 'var(--color-chart-5)',\n];\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const ChartWidget: FC<ChartWidgetProps> = memo(function ChartWidget({\n widget,\n data = [],\n onClick,\n onDrilldown,\n}) {\n const widgetConfig = widget.config as unknown as WidgetChartConfig | undefined;\n const [hiddenSeries, setHiddenSeries] = useState<string[]>([]);\n\n // Phase 2: Cross-filtering support\n const { handleDataClick: triggerCrossFilter, enabled: crossFilterEnabled } = useWidgetCrossFilter(\n widget.id,\n // Map chart data fields to filter IDs\n widgetConfig?.crossFilterMappings || [\n { sourceField: widgetConfig?.labelField || 'name', targetFilterId: 'category' },\n ]\n );\n const { clearAllCrossFilters, hasCrossFilters } = useCrossFilterContext();\n\n // Normalize widget config to chart config\n const chartConfig: ChartConfig = useMemo(\n () =>\n ({\n type: (widgetConfig?.chartType?.toLowerCase() || 'line') as ChartType,\n xAxisKey: widgetConfig?.xAxisField || 'name',\n xAxisLabel: widgetConfig?.xAxisLabel,\n yAxisLabel: widgetConfig?.yAxisLabel,\n showGrid: widgetConfig?.showGrid,\n showLegend: widgetConfig?.showLegend,\n legendPosition: widgetConfig?.legendPosition,\n showDots: widgetConfig?.showDataPoints,\n curveType: widgetConfig?.curveType as CurveType | undefined,\n colors: widgetConfig?.colors,\n seriesNames: widgetConfig?.seriesLabels,\n stacked: widgetConfig?.stacked,\n isDonut: widgetConfig?.showAsDonut,\n innerRadius: widgetConfig?.innerRadius,\n outerRadius: widgetConfig?.outerRadius,\n }) as ChartConfig,\n [widgetConfig]\n );\n\n // Extract legend items for cartesian charts\n const legendItems: LegendItem[] = useMemo(() => {\n if (!data.length) return [];\n\n // For pie/funnel charts, legend is handled internally\n if (chartConfig.type === 'pie' || chartConfig.type === 'funnel') {\n return [];\n }\n\n // Get selected fields from widget config (if specified)\n const selectedFields = widgetConfig?.selectedFields as string[] | undefined;\n\n // Filter to numeric fields, and apply selectedFields filter if configured\n const keys = Object.keys(data[0]).filter((key) => {\n // Must not be the x-axis key and must be numeric\n const isValidNumericField = key !== chartConfig.xAxisKey && typeof data[0][key] === 'number';\n\n // If selectedFields is configured and not empty, only include those fields\n if (selectedFields && selectedFields.length > 0) {\n return isValidNumericField && selectedFields.includes(key);\n }\n\n // Otherwise, show all numeric fields\n return isValidNumericField;\n });\n\n return keys.map((key, index) => ({\n dataKey: key,\n name: chartConfig.seriesNames?.[key] || key,\n color: chartConfig.colors?.[index] || DEFAULT_COLORS[index % DEFAULT_COLORS.length],\n hidden: hiddenSeries.includes(key),\n }));\n }, [data, chartConfig, hiddenSeries, widgetConfig?.selectedFields]);\n\n // Toggle series visibility\n const handleLegendClick = useCallback((dataKey: string) => {\n setHiddenSeries((prev) => (prev.includes(dataKey) ? prev.filter((k) => k !== dataKey) : [...prev, dataKey]));\n }, []);\n\n // Handle data point click\n // Clicking a bar/slice triggers BOTH cross-filtering AND drilldown:\n // 1. Cross-filter: highlights the clicked item across all widgets\n // 2. Drilldown: opens the detail modal/page for the clicked item\n const handleDataClick = useCallback(\n (dataPoint: ChartData, index: number) => {\n // Trigger cross-filtering on data click when enabled\n if (crossFilterEnabled) {\n const label = dataPoint[widgetConfig?.labelField || 'name'] as string;\n triggerCrossFilter(dataPoint as Record<string, unknown>, label);\n }\n\n // Trigger drilldown if configured\n if (onDrilldown) {\n onDrilldown(dataPoint as Record<string, unknown>);\n } else if (onClick && widget.drilldowns?.length) {\n onClick(dataPoint, index);\n }\n },\n [onClick, onDrilldown, widget.drilldowns, crossFilterEnabled, triggerCrossFilter, widgetConfig?.labelField]\n );\n\n // Render the appropriate chart\n const renderChart = () => {\n switch (chartConfig.type) {\n case 'bar':\n return <BarChart data={data} config={chartConfig} hiddenSeries={hiddenSeries} onDataClick={handleDataClick} />;\n\n case 'area':\n return <AreaChart data={data} config={chartConfig} hiddenSeries={hiddenSeries} onDataClick={handleDataClick} />;\n\n case 'pie':\n return (\n <PieChart\n data={data}\n config={chartConfig}\n dataKey={widgetConfig?.valueField || 'value'}\n nameKey={widgetConfig?.labelField || 'name'}\n onDataClick={handleDataClick}\n />\n );\n\n case 'funnel':\n return (\n <FunnelChart\n data={data}\n config={chartConfig}\n dataKey={widgetConfig?.valueField || 'value'}\n nameKey={widgetConfig?.labelField || 'name'}\n onDataClick={handleDataClick}\n />\n );\n\n case 'line':\n default:\n return <LineChart data={data} config={chartConfig} hiddenSeries={hiddenSeries} onDataClick={handleDataClick} />;\n }\n };\n\n return (\n <div className=\"flex flex-col h-full p-4\">\n {/* Cross-filter active indicator with clear button */}\n {hasCrossFilters && (\n <div className=\"flex items-center gap-2 mb-2 -mt-1\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n clearAllCrossFilters();\n }}\n className=\"\n inline-flex items-center gap-1.5\n px-2.5 py-1 rounded-md\n text-xs font-medium\n bg-action-primary-bg/10 text-action-primary-text\n hover:bg-action-primary-bg/20\n transition-colors\n \"\n >\n <svg className=\"w-3.5 h-3.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M10 19l-7-7m0 0l7-7m-7 7h18\" />\n </svg>\n Clear Filter\n </button>\n </div>\n )}\n\n {/* Custom legend (for line/bar/area charts with external legend) */}\n {chartConfig.legendPosition === 'top' && legendItems.length > 0 && (\n <ChartLegend items={legendItems} position=\"top\" onItemClick={handleLegendClick} />\n )}\n\n {/* Chart container */}\n <div className=\"flex-1 min-h-0\">{renderChart()}</div>\n\n {/* Custom legend (bottom) */}\n {chartConfig.legendPosition === 'bottom' && legendItems.length > 0 && (\n <ChartLegend items={legendItems} position=\"bottom\" onItemClick={handleLegendClick} />\n )}\n </div>\n );\n});\n\nexport default ChartWidget;\n"],"mappings":";;;;;;;;;;;AAqCA,IAAM,IAAiB;CACrB;CACA;CACA;CACA;CACA;CACD,EAMY,IAAoC,EAAK,SAAqB,EACzE,WACA,UAAO,EAAE,EACT,YACA,kBACC;CACD,IAAM,IAAe,EAAO,QACtB,CAAC,GAAc,KAAmB,EAAmB,EAAE,CAAC,EAGxD,EAAE,iBAAiB,GAAoB,SAAS,MAAuB,EAC3E,EAAO,IAEP,GAAc,uBAAuB,CACnC;EAAE,aAAa,GAAc,cAAc;EAAQ,gBAAgB;EAAY,CAChF,CACF,EACK,EAAE,yBAAsB,uBAAoB,GAAuB,EAGnE,IAA2B,SAE5B;EACC,MAAO,GAAc,WAAW,aAAa,IAAI;EACjD,UAAU,GAAc,cAAc;EACtC,YAAY,GAAc;EAC1B,YAAY,GAAc;EAC1B,UAAU,GAAc;EACxB,YAAY,GAAc;EAC1B,gBAAgB,GAAc;EAC9B,UAAU,GAAc;EACxB,WAAW,GAAc;EACzB,QAAQ,GAAc;EACtB,aAAa,GAAc;EAC3B,SAAS,GAAc;EACvB,SAAS,GAAc;EACvB,aAAa,GAAc;EAC3B,aAAa,GAAc;EAC5B,GACH,CAAC,EAAa,CACf,EAGK,IAA4B,QAAc;AAI9C,MAHI,CAAC,EAAK,UAGN,EAAY,SAAS,SAAS,EAAY,SAAS,SACrD,QAAO,EAAE;EAIX,IAAM,IAAiB,GAAc;AAgBrC,SAba,OAAO,KAAK,EAAK,GAAG,CAAC,QAAQ,MAAQ;GAEhD,IAAM,IAAsB,MAAQ,EAAY,YAAY,OAAO,EAAK,GAAG,MAAS;AAQpF,UALI,KAAkB,EAAe,SAAS,IACrC,KAAuB,EAAe,SAAS,EAAI,GAIrD;IACP,CAEU,KAAK,GAAK,OAAW;GAC/B,SAAS;GACT,MAAM,EAAY,cAAc,MAAQ;GACxC,OAAO,EAAY,SAAS,MAAU,EAAe,IAAQ,EAAe;GAC5E,QAAQ,EAAa,SAAS,EAAI;GACnC,EAAE;IACF;EAAC;EAAM;EAAa;EAAc,GAAc;EAAe,CAAC,EAG7D,IAAoB,GAAa,MAAoB;AACzD,KAAiB,MAAU,EAAK,SAAS,EAAQ,GAAG,EAAK,QAAQ,MAAM,MAAM,EAAQ,GAAG,CAAC,GAAG,GAAM,EAAQ,CAAE;IAC3G,EAAE,CAAC,EAMA,IAAkB,GACrB,GAAsB,MAAkB;AAEvC,MAAI,GAAoB;GACtB,IAAM,IAAQ,EAAU,GAAc,cAAc;AACpD,KAAmB,GAAsC,EAAM;;AAIjE,EAAI,IACF,EAAY,EAAqC,GACxC,KAAW,EAAO,YAAY,UACvC,EAAQ,GAAW,EAAM;IAG7B;EAAC;EAAS;EAAa,EAAO;EAAY;EAAoB;EAAoB,GAAc;EAAW,CAC5G;AAuCD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEG,KACC,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,UAAD;KACE,MAAK;KACL,UAAU,MAAM;AAEd,MADA,EAAE,iBAAiB,EACnB,GAAsB;;KAExB,WAAU;eANZ,CAeE,kBAAC,OAAD;MAAK,WAAU;MAAc,MAAK;MAAO,QAAO;MAAe,SAAQ;gBACrE,kBAAC,QAAD;OAAM,eAAc;OAAQ,gBAAe;OAAQ,aAAa;OAAG,GAAE;OAAgC,CAAA;MACjG,CAAA,EAAA,eAEC;;IACL,CAAA;GAIP,EAAY,mBAAmB,SAAS,EAAY,SAAS,KAC5D,kBAAC,GAAD;IAAa,OAAO;IAAa,UAAS;IAAM,aAAa;IAAqB,CAAA;GAIpF,kBAAC,OAAD;IAAK,WAAU;qBAtEO;AACxB,aAAQ,EAAY,MAApB;MACE,KAAK,MACH,QAAO,kBAAC,GAAD;OAAgB;OAAM,QAAQ;OAA2B;OAAc,aAAa;OAAmB,CAAA;MAEhH,KAAK,OACH,QAAO,kBAAC,GAAD;OAAiB;OAAM,QAAQ;OAA2B;OAAc,aAAa;OAAmB,CAAA;MAEjH,KAAK,MACH,QACE,kBAAC,GAAD;OACQ;OACN,QAAQ;OACR,SAAS,GAAc,cAAc;OACrC,SAAS,GAAc,cAAc;OACrC,aAAa;OACb,CAAA;MAGN,KAAK,SACH,QACE,kBAAC,GAAD;OACQ;OACN,QAAQ;OACR,SAAS,GAAc,cAAc;OACrC,SAAS,GAAc,cAAc;OACrC,aAAa;OACb,CAAA;MAIN,QACE,QAAO,kBAAC,GAAD;OAAiB;OAAM,QAAQ;OAA2B;OAAc,aAAa;OAAmB,CAAA;;QAsCnE;IAAO,CAAA;GAGpD,EAAY,mBAAmB,YAAY,EAAY,SAAS,KAC/D,kBAAC,GAAD;IAAa,OAAO;IAAa,UAAS;IAAS,aAAa;IAAqB,CAAA;GAEnF;;EAER"}
|
|
1
|
+
{"version":3,"file":"ChartWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/chart/ChartWidget.tsx"],"sourcesContent":["/**\n * ChartWidget Component\n *\n * Wrapper component that renders the appropriate chart type.\n */\n\nimport { type FC, memo, useState, useMemo, useCallback } from 'react';\nimport type { Widget, ChartConfig as WidgetChartConfig } from '../../../types';\nimport { LineChart } from './charts/LineChart';\nimport { BarChart } from './charts/BarChart';\nimport { AreaChart } from './charts/AreaChart';\nimport { PieChart } from './charts/PieChart';\nimport { FunnelChart } from './charts/FunnelChart';\nimport { ComboChart } from './charts/ComboChart';\nimport { WaterfallChart } from './charts/WaterfallChart';\nimport { ScatterChart } from './charts/ScatterChart';\nimport { ChartLegend, type LegendItem } from './ChartLegend';\nimport type { ChartConfig, ChartData, ChartType, CurveType, ReferenceLineConfig, SeriesConfig } from './charts/types';\n// Phase 2: Cross-filtering support\nimport { useWidgetCrossFilter, useCrossFilterContext } from '../../../contexts';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ChartWidgetProps {\n /** Widget configuration */\n widget: Widget;\n /** Chart data */\n data?: ChartData[];\n /** Click handler for drilldown */\n onClick?: (dataPoint: ChartData, index: number) => void;\n /** Drilldown handler - receives selected data point */\n onDrilldown?: (selectedData: Record<string, unknown>) => void;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_COLORS = [\n 'var(--color-chart-1)',\n 'var(--color-chart-2)',\n 'var(--color-chart-3)',\n 'var(--color-chart-4)',\n 'var(--color-chart-5)',\n];\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const ChartWidget: FC<ChartWidgetProps> = memo(function ChartWidget({\n widget,\n data = [],\n onClick,\n onDrilldown,\n}) {\n const widgetConfig = widget.config as unknown as WidgetChartConfig | undefined;\n const [hiddenSeries, setHiddenSeries] = useState<string[]>([]);\n\n // Phase 2: Cross-filtering support\n const { handleDataClick: triggerCrossFilter, enabled: crossFilterEnabled } = useWidgetCrossFilter(\n widget.id,\n // Map chart data fields to filter IDs\n widgetConfig?.crossFilterMappings || [\n { sourceField: widgetConfig?.labelField || 'name', targetFilterId: 'category' },\n ]\n );\n const { clearAllCrossFilters, hasCrossFilters } = useCrossFilterContext();\n\n // Normalize widget config to chart config\n const chartConfig: ChartConfig = useMemo(\n () =>\n ({\n type: (widgetConfig?.chartType?.toLowerCase() || 'line') as ChartType,\n xAxisKey: widgetConfig?.xAxisField || 'name',\n xAxisLabel: widgetConfig?.xAxisLabel,\n yAxisLabel: widgetConfig?.yAxisLabel,\n showGrid: widgetConfig?.showGrid,\n showLegend: widgetConfig?.showLegend,\n legendPosition: widgetConfig?.legendPosition,\n showDots: widgetConfig?.showDataPoints,\n curveType: widgetConfig?.curveType as CurveType | undefined,\n colors: widgetConfig?.colors,\n seriesNames: widgetConfig?.seriesLabels,\n stacked: widgetConfig?.stacked,\n isDonut: widgetConfig?.showAsDonut,\n innerRadius: widgetConfig?.innerRadius,\n outerRadius: widgetConfig?.outerRadius,\n referenceLines: widgetConfig?.referenceLines as ReferenceLineConfig[] | undefined,\n series: widgetConfig?.series as SeriesConfig[] | undefined,\n dualAxis: widgetConfig?.dualAxis,\n yAxisRightLabel: widgetConfig?.yAxisRightLabel,\n logScale: (widgetConfig as { logScale?: boolean } | undefined)?.logScale,\n valueField: widgetConfig?.valueField,\n labelField: widgetConfig?.labelField,\n showTotal: (widgetConfig as { showTotal?: boolean } | undefined)?.showTotal,\n totalLabel: (widgetConfig as { totalLabel?: string } | undefined)?.totalLabel,\n xField: (widgetConfig as { xField?: string } | undefined)?.xField,\n yField: (widgetConfig as { yField?: string } | undefined)?.yField,\n sizeField: (widgetConfig as { sizeField?: string } | undefined)?.sizeField,\n colorField: (widgetConfig as { colorField?: string } | undefined)?.colorField,\n }) as ChartConfig,\n [widgetConfig]\n );\n\n // Extract legend items for cartesian charts\n const legendItems: LegendItem[] = useMemo(() => {\n if (!data.length) return [];\n\n // For pie/funnel/scatter/waterfall charts, legend is handled internally\n if (\n chartConfig.type === 'pie' ||\n chartConfig.type === 'funnel' ||\n chartConfig.type === 'scatter' ||\n chartConfig.type === 'waterfall'\n ) {\n return [];\n }\n\n // Get selected fields from widget config (if specified)\n const selectedFields = widgetConfig?.selectedFields as string[] | undefined;\n\n // Filter to numeric fields, and apply selectedFields filter if configured\n const keys = Object.keys(data[0]).filter((key) => {\n // Must not be the x-axis key and must be numeric\n const isValidNumericField = key !== chartConfig.xAxisKey && typeof data[0][key] === 'number';\n\n // If selectedFields is configured and not empty, only include those fields\n if (selectedFields && selectedFields.length > 0) {\n return isValidNumericField && selectedFields.includes(key);\n }\n\n // Otherwise, show all numeric fields\n return isValidNumericField;\n });\n\n return keys.map((key, index) => ({\n dataKey: key,\n name: chartConfig.seriesNames?.[key] || key,\n color: chartConfig.colors?.[index] || DEFAULT_COLORS[index % DEFAULT_COLORS.length],\n hidden: hiddenSeries.includes(key),\n }));\n }, [data, chartConfig, hiddenSeries, widgetConfig?.selectedFields]);\n\n // Toggle series visibility\n const handleLegendClick = useCallback((dataKey: string) => {\n setHiddenSeries((prev) => (prev.includes(dataKey) ? prev.filter((k) => k !== dataKey) : [...prev, dataKey]));\n }, []);\n\n // Handle data point click\n // Clicking a bar/slice triggers BOTH cross-filtering AND drilldown:\n // 1. Cross-filter: highlights the clicked item across all widgets\n // 2. Drilldown: opens the detail modal/page for the clicked item\n const handleDataClick = useCallback(\n (dataPoint: ChartData, index: number) => {\n // Trigger cross-filtering on data click when enabled\n if (crossFilterEnabled) {\n const label = dataPoint[widgetConfig?.labelField || 'name'] as string;\n triggerCrossFilter(dataPoint as Record<string, unknown>, label);\n }\n\n // Trigger drilldown if configured\n if (onDrilldown) {\n onDrilldown(dataPoint as Record<string, unknown>);\n } else if (onClick && widget.drilldowns?.length) {\n onClick(dataPoint, index);\n }\n },\n [onClick, onDrilldown, widget.drilldowns, crossFilterEnabled, triggerCrossFilter, widgetConfig?.labelField]\n );\n\n // A combo chart is requested explicitly, or implied by a dual axis / a\n // per-series config that mixes bar+line or binds a series to the right axis.\n const isCombo =\n chartConfig.type === 'combo' ||\n chartConfig.dualAxis === true ||\n (chartConfig.series?.some((s) => s.axis === 'right' || s.type === 'bar') &&\n chartConfig.series?.some((s) => s.type === 'line')) ||\n false;\n\n // Render the appropriate chart\n const renderChart = () => {\n if (isCombo) {\n return <ComboChart data={data} config={chartConfig} hiddenSeries={hiddenSeries} onDataClick={handleDataClick} />;\n }\n switch (chartConfig.type) {\n case 'waterfall':\n return <WaterfallChart data={data} config={chartConfig} onDataClick={handleDataClick} />;\n\n case 'scatter':\n return <ScatterChart data={data} config={chartConfig} onDataClick={handleDataClick} />;\n\n case 'bar':\n return <BarChart data={data} config={chartConfig} hiddenSeries={hiddenSeries} onDataClick={handleDataClick} />;\n\n case 'area':\n return <AreaChart data={data} config={chartConfig} hiddenSeries={hiddenSeries} onDataClick={handleDataClick} />;\n\n case 'pie':\n return (\n <PieChart\n data={data}\n config={chartConfig}\n dataKey={widgetConfig?.valueField || 'value'}\n nameKey={widgetConfig?.labelField || 'name'}\n onDataClick={handleDataClick}\n />\n );\n\n case 'funnel':\n return (\n <FunnelChart\n data={data}\n config={chartConfig}\n dataKey={widgetConfig?.valueField || 'value'}\n nameKey={widgetConfig?.labelField || 'name'}\n onDataClick={handleDataClick}\n />\n );\n\n case 'line':\n default:\n return <LineChart data={data} config={chartConfig} hiddenSeries={hiddenSeries} onDataClick={handleDataClick} />;\n }\n };\n\n return (\n <div className=\"flex flex-col h-full p-4\">\n {/* Cross-filter active indicator with clear button */}\n {hasCrossFilters && (\n <div className=\"flex items-center gap-2 mb-2 -mt-1\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n clearAllCrossFilters();\n }}\n className=\"\n inline-flex items-center gap-1.5\n px-2.5 py-1 rounded-md\n text-xs font-medium\n bg-action-primary-bg/10 text-action-primary-text\n hover:bg-action-primary-bg/20\n transition-colors\n \"\n >\n <svg className=\"w-3.5 h-3.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M10 19l-7-7m0 0l7-7m-7 7h18\" />\n </svg>\n Clear Filter\n </button>\n </div>\n )}\n\n {/* Custom legend (for line/bar/area charts with external legend) */}\n {chartConfig.legendPosition === 'top' && legendItems.length > 0 && (\n <ChartLegend items={legendItems} position=\"top\" onItemClick={handleLegendClick} />\n )}\n\n {/* Chart container */}\n <div className=\"flex-1 min-h-0\">{renderChart()}</div>\n\n {/* Custom legend (bottom) */}\n {chartConfig.legendPosition === 'bottom' && legendItems.length > 0 && (\n <ChartLegend items={legendItems} position=\"bottom\" onItemClick={handleLegendClick} />\n )}\n </div>\n );\n});\n\nexport default ChartWidget;\n"],"mappings":"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"}
|