@burdenoff/microfe-bigconsole 2026.717.5 → 2026.727.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bigconsole/components/builder/inspector/AppearanceSection.js +23 -21
- package/dist/bigconsole/components/builder/inspector/AppearanceSection.js.map +1 -1
- package/dist/bigconsole/components/widgets/PropertiesPanel.js +2 -2
- package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetRegistry.js +1 -0
- package/dist/bigconsole/components/widgets/WidgetRegistry.js.map +1 -1
- package/dist/bigconsole/components/widgets/chart/charts/AreaChart.js +14 -2
- package/dist/bigconsole/components/widgets/chart/charts/AreaChart.js.map +1 -1
- package/dist/bigconsole/components/widgets/chart/charts/BarChart.js +14 -2
- package/dist/bigconsole/components/widgets/chart/charts/BarChart.js.map +1 -1
- package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js +126 -0
- package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js.map +1 -0
- package/dist/bigconsole/components/widgets/heatmap/HeatmapWidget.js +2 -2
- package/dist/bigconsole/components/widgets/heatmap/HeatmapWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/heatmap/index.js +2 -1
- package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js +92 -0
- package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js.map +1 -0
- package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js +449 -0
- package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js.map +1 -0
- package/dist/bigconsole/customWidget/index.js +4 -0
- package/dist/bigconsole/customWidget/proposalContract.js +106 -0
- package/dist/bigconsole/customWidget/proposalContract.js.map +1 -0
- package/dist/bigconsole/customWidget/proposalSource.js +204 -0
- package/dist/bigconsole/customWidget/proposalSource.js.map +1 -0
- package/dist/bigconsole/pages/DashboardBuilderPage.js +159 -139
- package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/HomePage.js +47 -44
- package/dist/bigconsole/pages/HomePage.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 /**\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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"}
|
|
1
|
+
{"version":3,"file":"WidgetRegistry.js","names":[],"sources":["../../../../src/bigconsole/components/widgets/WidgetRegistry.ts"],"sourcesContent":["/**\n * Widget Registry\n *\n * Central registry mapping widget types to their components,\n * metadata, and configuration schemas.\n */\n\nimport type { ComponentType } from 'react';\nimport type { WidgetType, WidgetCategory, Widget } from '../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface WidgetComponentProps {\n /** The widget data */\n widget: Widget;\n /** Widget data (processed) */\n data: Record<string, unknown>;\n /** Whether the widget is in edit mode */\n isEditMode?: boolean;\n /** Whether the widget is selected */\n isSelected?: boolean;\n /** Whether data is loading */\n isLoading?: boolean;\n /** Error message if any */\n error?: string | null;\n /** Callback when widget is clicked */\n onClick?: () => void;\n /** Callback for drilldown navigation */\n onDrilldown?: (params: Record<string, unknown>) => void;\n}\n\nexport interface WidgetDefinition {\n /** Widget type */\n type: WidgetType;\n /** Human-readable name */\n name: string;\n /** Description */\n description: string;\n /** Lucide icon name */\n icon: string;\n /** Category for grouping */\n category: WidgetCategory;\n /** Component to render. Null for all current widget types because the render path\n * uses WidgetRendererFactory + RendererRegistry instead of this field. */\n component: ComponentType<WidgetComponentProps> | null;\n /** Default configuration */\n defaultConfig: Record<string, unknown>;\n /** Default size (fixed grid) */\n defaultSize: { width: number; height: number };\n /**\n * Default responsive position (v1.0 spec). `xl` is optional and falls back\n * to `lg` when not set so existing widget defaults remain valid.\n */\n defaultResponsive: { xs: number; sm: number; md: number; lg: number; xl?: number };\n /** Minimum size constraints */\n minSize: { width: number; height: number };\n /** Maximum size constraints */\n maxSize: { width: number; height: number };\n /** Whether the widget supports data binding */\n supportsDataBinding: boolean;\n /** Whether the widget supports drilldown */\n supportsDrilldown: boolean;\n /** Whether the widget supports auto-refresh */\n supportsAutoRefresh: boolean;\n /**\n * Whether the widget honors rule-based conditional formatting\n * (`config.conditionalRules`). Drives which options the config UI shows.\n */\n supportsConditionalFormat?: boolean;\n /**\n * Whether the widget supports reference / threshold lines & bands\n * (`config.referenceLines`).\n */\n supportsThresholds?: boolean;\n /** Whether the widget supports a combo / dual-axis layout (`config.dualAxis`). */\n supportsDualAxis?: boolean;\n /** Whether the widget supports a totals/aggregate footer (`config.showTotals`). */\n supportsTotals?: boolean;\n /** Tags for search/filter */\n tags: string[];\n}\n\n// ============================================================================\n// Widget Definitions\n// ============================================================================\n\nexport const WIDGET_DEFINITIONS: Record<WidgetType, WidgetDefinition> = {\n // ============================================================================\n // Core Visualization (6 types)\n // ============================================================================\n\n kpi_card_comparison: {\n type: 'kpi_card_comparison',\n name: 'KPI Card Comparison',\n description: 'Compare multiple KPIs side by side with trends',\n icon: 'LayoutDashboard',\n category: 'KPI',\n component: null,\n defaultConfig: {\n comparisons: [],\n showSparklines: true,\n layout: 'horizontal',\n format: 'number',\n },\n defaultSize: { width: 6, height: 3 },\n defaultResponsive: { xs: 12, sm: 6, md: 6, lg: 4 },\n minSize: { width: 4, height: 2 },\n maxSize: { width: 12, height: 6 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n supportsConditionalFormat: true,\n tags: ['kpi', 'comparison', 'metrics', 'multi'],\n },\n\n metric_card: {\n type: 'metric_card',\n name: 'Metric Card',\n description: 'Display a single KPI value with trend indicator',\n icon: 'TrendingUp',\n category: 'KPI',\n component: null,\n defaultConfig: {\n format: 'number',\n decimalPlaces: 0,\n showTrend: true,\n showSparkline: false,\n },\n defaultSize: { width: 3, height: 2 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 3 },\n minSize: { width: 2, height: 2 },\n maxSize: { width: 6, height: 4 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n supportsConditionalFormat: true,\n tags: ['kpi', 'metric', 'number', 'trend'],\n },\n\n chart: {\n type: 'chart',\n name: 'Chart',\n description: 'Multi-type chart (Line, Bar, Area, Pie)',\n icon: 'BarChart3',\n category: 'Visualization',\n component: null,\n defaultConfig: {\n chartType: 'line',\n showLegend: true,\n legendPosition: 'bottom',\n showGrid: true,\n showTooltip: true,\n },\n defaultSize: { width: 6, height: 4 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 3, height: 3 },\n maxSize: { width: 12, height: 8 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n supportsConditionalFormat: true,\n supportsThresholds: true,\n supportsDualAxis: true,\n tags: ['chart', 'graph', 'visualization', 'line', 'bar', 'area', 'pie', 'combo', 'dual-axis'],\n },\n\n funnel_chart: {\n type: 'funnel_chart',\n name: 'Funnel Chart',\n description: 'Visualize conversion or drop-off stages',\n icon: 'Filter',\n category: 'Visualization',\n component: null,\n defaultConfig: {\n // ChartWidget dispatches on `chartType` and falls back to 'line' when it is\n // absent, so a palette-created funnel must seed it explicitly.\n chartType: 'funnel',\n showLabels: true,\n showValues: true,\n showPercentages: true,\n orientation: 'vertical',\n },\n defaultSize: { width: 4, height: 5 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 3, height: 4 },\n maxSize: { width: 8, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['funnel', 'conversion', 'stages', 'pipeline'],\n },\n\n table: {\n type: 'table',\n name: 'Data Table',\n description: 'Display data in sortable, filterable rows and columns',\n icon: 'Table',\n category: 'Data',\n component: null,\n defaultConfig: {\n pageSize: 10,\n sortable: true,\n filterable: true,\n stickyHeader: true,\n columns: [],\n },\n defaultSize: { width: 8, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 8, lg: 8 },\n minSize: { width: 4, height: 3 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n supportsConditionalFormat: true,\n supportsTotals: true,\n tags: ['table', 'data', 'grid', 'rows'],\n },\n\n pivot_table: {\n type: 'pivot_table',\n name: 'Pivot Table',\n description: 'Interactive pivot table for data analysis',\n icon: 'Grid3x3',\n category: 'Data',\n component: null,\n defaultConfig: {\n rows: [],\n columns: [],\n values: [],\n aggregation: 'sum',\n showTotals: true,\n },\n defaultSize: { width: 10, height: 6 },\n defaultResponsive: { xs: 12, sm: 12, md: 12, lg: 10 },\n minSize: { width: 6, height: 4 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['pivot', 'table', 'analysis', 'aggregation'],\n },\n\n // ============================================================================\n // Indicators (2 types)\n // ============================================================================\n\n gauge: {\n type: 'gauge',\n name: 'Gauge',\n description: 'Display a value within a range',\n icon: 'Gauge',\n category: 'KPI',\n component: null,\n defaultConfig: {\n variant: 'circular',\n min: 0,\n max: 100,\n showValue: true,\n showLabels: true,\n thresholds: [\n { value: 33, color: 'red' },\n { value: 66, color: 'yellow' },\n { value: 100, color: 'green' },\n ],\n },\n defaultSize: { width: 3, height: 3 },\n defaultResponsive: { xs: 6, sm: 4, md: 3, lg: 3 },\n minSize: { width: 2, height: 2 },\n maxSize: { width: 6, height: 6 },\n supportsDataBinding: true,\n supportsDrilldown: false,\n supportsAutoRefresh: true,\n tags: ['gauge', 'meter', 'dial', 'indicator'],\n },\n\n progress: {\n type: 'progress',\n name: 'Progress Bar',\n description: 'Show progress towards a goal with milestones',\n icon: 'Activity',\n category: 'KPI',\n component: null,\n defaultConfig: {\n showPercentage: true,\n showValue: false,\n target: null,\n milestones: [],\n },\n defaultSize: { width: 4, height: 2 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 3, height: 2 },\n maxSize: { width: 12, height: 3 },\n supportsDataBinding: true,\n supportsDrilldown: false,\n supportsAutoRefresh: true,\n tags: ['progress', 'bar', 'goal', 'completion'],\n },\n\n // ============================================================================\n // Data Display (2 types)\n // ============================================================================\n\n list: {\n type: 'list',\n name: 'List',\n description: 'Display items in a scrollable list',\n icon: 'List',\n category: 'Data',\n component: null,\n defaultConfig: {\n showMetadata: true,\n showActions: false,\n showBadges: true,\n maxItems: 10,\n itemClickable: true,\n },\n defaultSize: { width: 4, height: 5 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 3, height: 3 },\n maxSize: { width: 8, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: true,\n supportsAutoRefresh: true,\n tags: ['list', 'items', 'scroll'],\n },\n\n form: {\n type: 'form',\n name: 'Form',\n description: 'Interactive form widget for data input',\n icon: 'FileText',\n category: 'Data',\n component: null,\n defaultConfig: {\n fields: [],\n submitAction: null,\n layout: 'vertical',\n showLabels: true,\n },\n defaultSize: { width: 6, height: 5 },\n defaultResponsive: { xs: 12, sm: 12, md: 6, lg: 6 },\n minSize: { width: 4, height: 3 },\n maxSize: { width: 12, height: 10 },\n supportsDataBinding: true,\n supportsDrilldown: false,\n supportsAutoRefresh: false,\n tags: ['form', 'input', 'submit', 'fields'],\n },\n\n // ============================================================================\n // Content (2 types)\n // ============================================================================\n\n text: {\n type: 'text',\n name: 'Text',\n description: 'Rich text or markdown content widget',\n icon: 'Type',\n category: 'Content',\n component: null,\n defaultConfig: {\n content: '',\n format: 'markdown',\n alignment: 'left',\n },\n defaultSize: { width: 4, height: 3 },\n defaultResponsive: { xs: 12, sm: 6, md: 4, lg: 4 },\n minSize: { width: 2, height: 1 },\n maxSize: { width: 12, height: 12 },\n supportsDataBinding: 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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"}
|
|
@@ -61,7 +61,13 @@ var m = [
|
|
|
61
61
|
fontSize: 12
|
|
62
62
|
},
|
|
63
63
|
tickLine: { stroke: "var(--color-border-default)" },
|
|
64
|
-
axisLine: { stroke: "var(--color-border-default)" }
|
|
64
|
+
axisLine: { stroke: "var(--color-border-default)" },
|
|
65
|
+
label: h.xAxisLabel ? {
|
|
66
|
+
value: h.xAxisLabel,
|
|
67
|
+
position: "insideBottom",
|
|
68
|
+
offset: -5,
|
|
69
|
+
fill: "var(--color-text-secondary)"
|
|
70
|
+
} : void 0
|
|
65
71
|
}),
|
|
66
72
|
/* @__PURE__ */ i(p, {
|
|
67
73
|
tick: {
|
|
@@ -73,7 +79,13 @@ var m = [
|
|
|
73
79
|
tickFormatter: y,
|
|
74
80
|
scale: h.logScale ? "log" : "auto",
|
|
75
81
|
domain: h.logScale ? ["auto", "auto"] : void 0,
|
|
76
|
-
allowDataOverflow: h.logScale || void 0
|
|
82
|
+
allowDataOverflow: h.logScale || void 0,
|
|
83
|
+
label: h.yAxisLabel ? {
|
|
84
|
+
value: h.yAxisLabel,
|
|
85
|
+
angle: -90,
|
|
86
|
+
position: "insideLeft",
|
|
87
|
+
fill: "var(--color-text-secondary)"
|
|
88
|
+
} : void 0
|
|
77
89
|
}),
|
|
78
90
|
/* @__PURE__ */ i(d, {
|
|
79
91
|
content: /* @__PURE__ */ i(e, { valueFormatter: y }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AreaChart.js","names":[],"sources":["../../../../../../src/bigconsole/components/widgets/chart/charts/AreaChart.tsx"],"sourcesContent":["/**\n * AreaChart Component\n *\n * Area chart using Recharts.\n */\n\nimport { type FC, memo, useMemo } from 'react';\nimport {\n AreaChart as RechartsAreaChart,\n Area,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n ResponsiveContainer,\n Legend,\n} from 'recharts';\nimport { ChartTooltip } from '../ChartTooltip';\nimport type { ChartConfig, ChartData } from './types';\nimport { buildReferenceElements } from './referenceElements';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface AreaChartProps {\n /** Chart data */\n data: ChartData[];\n /** Chart configuration */\n config: ChartConfig;\n /** Series to hide */\n hiddenSeries?: string[];\n /** Click handler for data points */\n onDataClick?: (data: ChartData, index: number) => 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 AreaChart: FC<AreaChartProps> = memo(function AreaChart({\n data = [],\n config,\n hiddenSeries = [],\n onDataClick,\n}) {\n // Extract data keys (series)\n const dataKeys = useMemo(() => {\n if (!data?.length) return [];\n const keys = Object.keys(data[0]).filter((key) => key !== config.xAxisKey && typeof data[0][key] === 'number');\n return keys;\n }, [data, config.xAxisKey]);\n\n // Format value\n const formatValue = (value: number | string): string => {\n if (typeof value !== 'number') return String(value);\n return new Intl.NumberFormat('en-US', {\n notation: value >= 10000 ? 'compact' : 'standard',\n maximumFractionDigits: 2,\n }).format(value);\n };\n\n // Generate gradient ID\n const getGradientId = (key: string) => `gradient-${key}`;\n\n if (!data?.length) {\n return null;\n }\n\n return (\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <RechartsAreaChart\n data={data}\n margin={{ top: 10, right: 10, left: 0, bottom: 0 }}\n onClick={(e) => {\n if (e?.activePayload?.[0] && onDataClick) {\n onDataClick(e.activePayload[0].payload, e.activeTooltipIndex || 0);\n }\n }}\n >\n {/* Gradients */}\n <defs>\n {dataKeys.map((key, index) => {\n const color = config.colors?.[index] || DEFAULT_COLORS[index % DEFAULT_COLORS.length];\n return (\n <linearGradient key={key} id={getGradientId(key)} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor={color} stopOpacity={0.4} />\n <stop offset=\"95%\" stopColor={color} stopOpacity={0.05} />\n </linearGradient>\n );\n })}\n </defs>\n\n {config.showGrid !== false && (\n <CartesianGrid strokeDasharray=\"3 3\" stroke=\"var(--color-border-default)\" opacity={0.5} />\n )}\n\n <XAxis\n dataKey={config.xAxisKey || 'name'}\n tick={{ fill: 'var(--color-text-secondary)', fontSize: 12 }}\n tickLine={{ stroke: 'var(--color-border-default)' }}\n axisLine={{ stroke: 'var(--color-border-default)' }}\n />\n\n <YAxis\n tick={{ fill: 'var(--color-text-secondary)', fontSize: 12 }}\n tickLine={{ stroke: 'var(--color-border-default)' }}\n axisLine={{ stroke: 'var(--color-border-default)' }}\n tickFormatter={formatValue}\n scale={config.logScale ? 'log' : 'auto'}\n domain={config.logScale ? ['auto', 'auto'] : undefined}\n allowDataOverflow={config.logScale || undefined}\n />\n\n <Tooltip\n content={<ChartTooltip valueFormatter={formatValue} />}\n cursor={{ stroke: 'var(--color-border-default)' }}\n />\n\n {config.showLegend !== false && (\n <Legend\n wrapperStyle={{ paddingTop: 20 }}\n formatter={(value) => <span style={{ color: 'var(--color-text-primary)' }}>{value}</span>}\n />\n )}\n\n {buildReferenceElements(config.referenceLines)}\n\n {dataKeys.map((key, index) => (\n <Area\n key={key}\n type={config.curveType || 'monotone'}\n dataKey={key}\n name={config.seriesNames?.[key] || key}\n stroke={config.colors?.[index] || DEFAULT_COLORS[index % DEFAULT_COLORS.length]}\n strokeWidth={2}\n fill={`url(#${getGradientId(key)})`}\n dot={config.showDots}\n activeDot={{ r: 6 }}\n hide={hiddenSeries.includes(key)}\n stackId={config.stacked ? 'stack' : undefined}\n />\n ))}\n </RechartsAreaChart>\n </ResponsiveContainer>\n );\n});\n\nexport default AreaChart;\n"],"mappings":";;;;;;AAwCA,IAAM,IAAiB;CACrB;CACA;CACA;CACA;CACA;CACD,EAMY,IAAgC,EAAK,SAAmB,EACnE,UAAO,EAAE,EACT,WACA,kBAAe,EAAE,EACjB,kBACC;CAED,IAAM,IAAW,QACV,GAAM,SACE,OAAO,KAAK,EAAK,GAAG,CAAC,QAAQ,MAAQ,MAAQ,EAAO,YAAY,OAAO,EAAK,GAAG,MAAS,SAAS,GADpF,EAAE,EAG3B,CAAC,GAAM,EAAO,SAAS,CAAC,EAGrB,KAAe,MACf,OAAO,KAAU,WACd,IAAI,KAAK,aAAa,SAAS;EACpC,UAAU,KAAS,MAAQ,YAAY;EACvC,uBAAuB;EACxB,CAAC,CAAC,OAAO,EAAM,GAJsB,OAAO,EAAM,EAQ/C,KAAiB,MAAgB,YAAY;AAMnD,QAJK,GAAM,SAKT,kBAAC,GAAD;EAAqB,OAAM;EAAO,QAAO;YACvC,kBAAC,GAAD;GACQ;GACN,QAAQ;IAAE,KAAK;IAAI,OAAO;IAAI,MAAM;IAAG,QAAQ;IAAG;GAClD,UAAU,MAAM;AACd,IAAI,GAAG,gBAAgB,MAAM,KAC3B,EAAY,EAAE,cAAc,GAAG,SAAS,EAAE,sBAAsB,EAAE;;aALxE;IAUE,kBAAC,QAAD,EAAA,UACG,EAAS,KAAK,GAAK,MAAU;KAC5B,IAAM,IAAQ,EAAO,SAAS,MAAU,EAAe,IAAQ,EAAe;AAC9E,YACE,kBAAC,kBAAD;MAA0B,IAAI,EAAc,EAAI;MAAE,IAAG;MAAI,IAAG;MAAI,IAAG;MAAI,IAAG;gBAA1E,CACE,kBAAC,QAAD;OAAM,QAAO;OAAK,WAAW;OAAO,aAAa;OAAO,CAAA,EACxD,kBAAC,QAAD;OAAM,QAAO;OAAM,WAAW;OAAO,aAAa;OAAQ,CAAA,CAC3C;QAHI,EAGJ;MAEnB,EACG,CAAA;IAEN,EAAO,aAAa,MACnB,kBAAC,GAAD;KAAe,iBAAgB;KAAM,QAAO;KAA8B,SAAS;KAAO,CAAA;IAG5F,kBAAC,GAAD;KACE,SAAS,EAAO,YAAY;KAC5B,MAAM;MAAE,MAAM;MAA+B,UAAU;MAAI;KAC3D,UAAU,EAAE,QAAQ,+BAA+B;KACnD,UAAU,EAAE,QAAQ,+BAA+B;KACnD,CAAA;IAEF,kBAAC,GAAD;KACE,MAAM;MAAE,MAAM;MAA+B,UAAU;MAAI;KAC3D,UAAU,EAAE,QAAQ,+BAA+B;KACnD,UAAU,EAAE,QAAQ,+BAA+B;KACnD,eAAe;KACf,OAAO,EAAO,WAAW,QAAQ;KACjC,QAAQ,EAAO,WAAW,CAAC,QAAQ,OAAO,GAAG,KAAA;KAC7C,mBAAmB,EAAO,YAAY,KAAA;KACtC,CAAA;IAEF,kBAAC,GAAD;KACE,SAAS,kBAAC,GAAD,EAAc,gBAAgB,GAAe,CAAA;KACtD,QAAQ,EAAE,QAAQ,+BAA+B;KACjD,CAAA;IAED,EAAO,eAAe,MACrB,kBAAC,GAAD;KACE,cAAc,EAAE,YAAY,IAAI;KAChC,YAAY,MAAU,kBAAC,QAAD;MAAM,OAAO,EAAE,OAAO,6BAA6B;gBAAG;MAAa,CAAA;KACzF,CAAA;IAGH,EAAuB,EAAO,eAAe;IAE7C,EAAS,KAAK,GAAK,MAClB,kBAAC,GAAD;KAEE,MAAM,EAAO,aAAa;KAC1B,SAAS;KACT,MAAM,EAAO,cAAc,MAAQ;KACnC,QAAQ,EAAO,SAAS,MAAU,EAAe,IAAQ,EAAe;KACxE,aAAa;KACb,MAAM,QAAQ,EAAc,EAAI,CAAC;KACjC,KAAK,EAAO;KACZ,WAAW,EAAE,GAAG,GAAG;KACnB,MAAM,EAAa,SAAS,EAAI;KAChC,SAAS,EAAO,UAAU,UAAU,KAAA;KACpC,EAXK,EAWL,CACF;IACgB;;EACA,CAAA,
|
|
1
|
+
{"version":3,"file":"AreaChart.js","names":[],"sources":["../../../../../../src/bigconsole/components/widgets/chart/charts/AreaChart.tsx"],"sourcesContent":["/**\n * AreaChart Component\n *\n * Area chart using Recharts.\n */\n\nimport { type FC, memo, useMemo } from 'react';\nimport {\n AreaChart as RechartsAreaChart,\n Area,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n ResponsiveContainer,\n Legend,\n} from 'recharts';\nimport { ChartTooltip } from '../ChartTooltip';\nimport type { ChartConfig, ChartData } from './types';\nimport { buildReferenceElements } from './referenceElements';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface AreaChartProps {\n /** Chart data */\n data: ChartData[];\n /** Chart configuration */\n config: ChartConfig;\n /** Series to hide */\n hiddenSeries?: string[];\n /** Click handler for data points */\n onDataClick?: (data: ChartData, index: number) => 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 AreaChart: FC<AreaChartProps> = memo(function AreaChart({\n data = [],\n config,\n hiddenSeries = [],\n onDataClick,\n}) {\n // Extract data keys (series)\n const dataKeys = useMemo(() => {\n if (!data?.length) return [];\n const keys = Object.keys(data[0]).filter((key) => key !== config.xAxisKey && typeof data[0][key] === 'number');\n return keys;\n }, [data, config.xAxisKey]);\n\n // Format value\n const formatValue = (value: number | string): string => {\n if (typeof value !== 'number') return String(value);\n return new Intl.NumberFormat('en-US', {\n notation: value >= 10000 ? 'compact' : 'standard',\n maximumFractionDigits: 2,\n }).format(value);\n };\n\n // Generate gradient ID\n const getGradientId = (key: string) => `gradient-${key}`;\n\n if (!data?.length) {\n return null;\n }\n\n return (\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <RechartsAreaChart\n data={data}\n margin={{ top: 10, right: 10, left: 0, bottom: 0 }}\n onClick={(e) => {\n if (e?.activePayload?.[0] && onDataClick) {\n onDataClick(e.activePayload[0].payload, e.activeTooltipIndex || 0);\n }\n }}\n >\n {/* Gradients */}\n <defs>\n {dataKeys.map((key, index) => {\n const color = config.colors?.[index] || DEFAULT_COLORS[index % DEFAULT_COLORS.length];\n return (\n <linearGradient key={key} id={getGradientId(key)} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor={color} stopOpacity={0.4} />\n <stop offset=\"95%\" stopColor={color} stopOpacity={0.05} />\n </linearGradient>\n );\n })}\n </defs>\n\n {config.showGrid !== false && (\n <CartesianGrid strokeDasharray=\"3 3\" stroke=\"var(--color-border-default)\" opacity={0.5} />\n )}\n\n <XAxis\n dataKey={config.xAxisKey || 'name'}\n tick={{ fill: 'var(--color-text-secondary)', fontSize: 12 }}\n tickLine={{ stroke: 'var(--color-border-default)' }}\n axisLine={{ stroke: 'var(--color-border-default)' }}\n label={\n config.xAxisLabel\n ? {\n value: config.xAxisLabel,\n position: 'insideBottom',\n offset: -5,\n fill: 'var(--color-text-secondary)',\n }\n : undefined\n }\n />\n\n <YAxis\n tick={{ fill: 'var(--color-text-secondary)', fontSize: 12 }}\n tickLine={{ stroke: 'var(--color-border-default)' }}\n axisLine={{ stroke: 'var(--color-border-default)' }}\n tickFormatter={formatValue}\n scale={config.logScale ? 'log' : 'auto'}\n domain={config.logScale ? ['auto', 'auto'] : undefined}\n allowDataOverflow={config.logScale || undefined}\n label={\n config.yAxisLabel\n ? {\n value: config.yAxisLabel,\n angle: -90,\n position: 'insideLeft',\n fill: 'var(--color-text-secondary)',\n }\n : undefined\n }\n />\n\n <Tooltip\n content={<ChartTooltip valueFormatter={formatValue} />}\n cursor={{ stroke: 'var(--color-border-default)' }}\n />\n\n {config.showLegend !== false && (\n <Legend\n wrapperStyle={{ paddingTop: 20 }}\n formatter={(value) => <span style={{ color: 'var(--color-text-primary)' }}>{value}</span>}\n />\n )}\n\n {buildReferenceElements(config.referenceLines)}\n\n {dataKeys.map((key, index) => (\n <Area\n key={key}\n type={config.curveType || 'monotone'}\n dataKey={key}\n name={config.seriesNames?.[key] || key}\n stroke={config.colors?.[index] || DEFAULT_COLORS[index % DEFAULT_COLORS.length]}\n strokeWidth={2}\n fill={`url(#${getGradientId(key)})`}\n dot={config.showDots}\n activeDot={{ r: 6 }}\n hide={hiddenSeries.includes(key)}\n stackId={config.stacked ? 'stack' : undefined}\n />\n ))}\n </RechartsAreaChart>\n </ResponsiveContainer>\n );\n});\n\nexport default AreaChart;\n"],"mappings":";;;;;;AAwCA,IAAM,IAAiB;CACrB;CACA;CACA;CACA;CACA;CACD,EAMY,IAAgC,EAAK,SAAmB,EACnE,UAAO,EAAE,EACT,WACA,kBAAe,EAAE,EACjB,kBACC;CAED,IAAM,IAAW,QACV,GAAM,SACE,OAAO,KAAK,EAAK,GAAG,CAAC,QAAQ,MAAQ,MAAQ,EAAO,YAAY,OAAO,EAAK,GAAG,MAAS,SAAS,GADpF,EAAE,EAG3B,CAAC,GAAM,EAAO,SAAS,CAAC,EAGrB,KAAe,MACf,OAAO,KAAU,WACd,IAAI,KAAK,aAAa,SAAS;EACpC,UAAU,KAAS,MAAQ,YAAY;EACvC,uBAAuB;EACxB,CAAC,CAAC,OAAO,EAAM,GAJsB,OAAO,EAAM,EAQ/C,KAAiB,MAAgB,YAAY;AAMnD,QAJK,GAAM,SAKT,kBAAC,GAAD;EAAqB,OAAM;EAAO,QAAO;YACvC,kBAAC,GAAD;GACQ;GACN,QAAQ;IAAE,KAAK;IAAI,OAAO;IAAI,MAAM;IAAG,QAAQ;IAAG;GAClD,UAAU,MAAM;AACd,IAAI,GAAG,gBAAgB,MAAM,KAC3B,EAAY,EAAE,cAAc,GAAG,SAAS,EAAE,sBAAsB,EAAE;;aALxE;IAUE,kBAAC,QAAD,EAAA,UACG,EAAS,KAAK,GAAK,MAAU;KAC5B,IAAM,IAAQ,EAAO,SAAS,MAAU,EAAe,IAAQ,EAAe;AAC9E,YACE,kBAAC,kBAAD;MAA0B,IAAI,EAAc,EAAI;MAAE,IAAG;MAAI,IAAG;MAAI,IAAG;MAAI,IAAG;gBAA1E,CACE,kBAAC,QAAD;OAAM,QAAO;OAAK,WAAW;OAAO,aAAa;OAAO,CAAA,EACxD,kBAAC,QAAD;OAAM,QAAO;OAAM,WAAW;OAAO,aAAa;OAAQ,CAAA,CAC3C;QAHI,EAGJ;MAEnB,EACG,CAAA;IAEN,EAAO,aAAa,MACnB,kBAAC,GAAD;KAAe,iBAAgB;KAAM,QAAO;KAA8B,SAAS;KAAO,CAAA;IAG5F,kBAAC,GAAD;KACE,SAAS,EAAO,YAAY;KAC5B,MAAM;MAAE,MAAM;MAA+B,UAAU;MAAI;KAC3D,UAAU,EAAE,QAAQ,+BAA+B;KACnD,UAAU,EAAE,QAAQ,+BAA+B;KACnD,OACE,EAAO,aACH;MACE,OAAO,EAAO;MACd,UAAU;MACV,QAAQ;MACR,MAAM;MACP,GACD,KAAA;KAEN,CAAA;IAEF,kBAAC,GAAD;KACE,MAAM;MAAE,MAAM;MAA+B,UAAU;MAAI;KAC3D,UAAU,EAAE,QAAQ,+BAA+B;KACnD,UAAU,EAAE,QAAQ,+BAA+B;KACnD,eAAe;KACf,OAAO,EAAO,WAAW,QAAQ;KACjC,QAAQ,EAAO,WAAW,CAAC,QAAQ,OAAO,GAAG,KAAA;KAC7C,mBAAmB,EAAO,YAAY,KAAA;KACtC,OACE,EAAO,aACH;MACE,OAAO,EAAO;MACd,OAAO;MACP,UAAU;MACV,MAAM;MACP,GACD,KAAA;KAEN,CAAA;IAEF,kBAAC,GAAD;KACE,SAAS,kBAAC,GAAD,EAAc,gBAAgB,GAAe,CAAA;KACtD,QAAQ,EAAE,QAAQ,+BAA+B;KACjD,CAAA;IAED,EAAO,eAAe,MACrB,kBAAC,GAAD;KACE,cAAc,EAAE,YAAY,IAAI;KAChC,YAAY,MAAU,kBAAC,QAAD;MAAM,OAAO,EAAE,OAAO,6BAA6B;gBAAG;MAAa,CAAA;KACzF,CAAA;IAGH,EAAuB,EAAO,eAAe;IAE7C,EAAS,KAAK,GAAK,MAClB,kBAAC,GAAD;KAEE,MAAM,EAAO,aAAa;KAC1B,SAAS;KACT,MAAM,EAAO,cAAc,MAAQ;KACnC,QAAQ,EAAO,SAAS,MAAU,EAAe,IAAQ,EAAe;KACxE,aAAa;KACb,MAAM,QAAQ,EAAc,EAAI,CAAC;KACjC,KAAK,EAAO;KACZ,WAAW,EAAE,GAAG,GAAG;KACnB,MAAM,EAAa,SAAS,EAAI;KAChC,SAAS,EAAO,UAAU,UAAU,KAAA;KACpC,EAXK,EAWL,CACF;IACgB;;EACA,CAAA,GAlGf;EAoGT"}
|
|
@@ -43,7 +43,13 @@ var m = [
|
|
|
43
43
|
fontSize: 12
|
|
44
44
|
},
|
|
45
45
|
tickLine: { stroke: "var(--color-border-default)" },
|
|
46
|
-
axisLine: { stroke: "var(--color-border-default)" }
|
|
46
|
+
axisLine: { stroke: "var(--color-border-default)" },
|
|
47
|
+
label: h.xAxisLabel ? {
|
|
48
|
+
value: h.xAxisLabel,
|
|
49
|
+
position: "insideBottom",
|
|
50
|
+
offset: -5,
|
|
51
|
+
fill: "var(--color-text-secondary)"
|
|
52
|
+
} : void 0
|
|
47
53
|
}),
|
|
48
54
|
/* @__PURE__ */ i(p, {
|
|
49
55
|
tick: {
|
|
@@ -55,7 +61,13 @@ var m = [
|
|
|
55
61
|
tickFormatter: y,
|
|
56
62
|
scale: h.logScale ? "log" : "auto",
|
|
57
63
|
domain: h.logScale ? ["auto", "auto"] : void 0,
|
|
58
|
-
allowDataOverflow: h.logScale || void 0
|
|
64
|
+
allowDataOverflow: h.logScale || void 0,
|
|
65
|
+
label: h.yAxisLabel ? {
|
|
66
|
+
value: h.yAxisLabel,
|
|
67
|
+
angle: -90,
|
|
68
|
+
position: "insideLeft",
|
|
69
|
+
fill: "var(--color-text-secondary)"
|
|
70
|
+
} : void 0
|
|
59
71
|
}),
|
|
60
72
|
/* @__PURE__ */ i(d, {
|
|
61
73
|
content: /* @__PURE__ */ i(e, { valueFormatter: y }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BarChart.js","names":[],"sources":["../../../../../../src/bigconsole/components/widgets/chart/charts/BarChart.tsx"],"sourcesContent":["/**\n * BarChart Component\n *\n * Bar chart using Recharts.\n */\n\nimport { type FC, memo, useMemo } from 'react';\nimport {\n BarChart as RechartsBarChart,\n Bar,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n ResponsiveContainer,\n Legend,\n} from 'recharts';\nimport { ChartTooltip } from '../ChartTooltip';\nimport type { ChartConfig, ChartData } from './types';\nimport { buildReferenceElements } from './referenceElements';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface BarChartProps {\n /** Chart data */\n data: ChartData[];\n /** Chart configuration */\n config: ChartConfig;\n /** Series to hide */\n hiddenSeries?: string[];\n /** Click handler for bars */\n onDataClick?: (data: ChartData, index: number) => 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 BarChart: FC<BarChartProps> = memo(function BarChart({\n data = [],\n config,\n hiddenSeries = [],\n onDataClick,\n}) {\n // Extract data keys (series)\n const dataKeys = useMemo(() => {\n if (!data?.length) return [];\n const keys = Object.keys(data[0]).filter((key) => key !== config.xAxisKey && typeof data[0][key] === 'number');\n return keys;\n }, [data, config.xAxisKey]);\n\n // Format value\n const formatValue = (value: number | string): string => {\n if (typeof value !== 'number') return String(value);\n return new Intl.NumberFormat('en-US', {\n notation: value >= 10000 ? 'compact' : 'standard',\n maximumFractionDigits: 2,\n }).format(value);\n };\n\n if (!data?.length) {\n return null;\n }\n\n return (\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <RechartsBarChart\n data={data}\n margin={{ top: 10, right: 10, left: 0, bottom: 0 }}\n onClick={(e) => {\n if (e?.activePayload?.[0] && onDataClick) {\n onDataClick(e.activePayload[0].payload, e.activeTooltipIndex || 0);\n }\n }}\n >\n {config.showGrid !== false && (\n <CartesianGrid strokeDasharray=\"3 3\" stroke=\"var(--color-border-default)\" opacity={0.5} vertical={false} />\n )}\n\n <XAxis\n dataKey={config.xAxisKey || 'name'}\n tick={{ fill: 'var(--color-text-secondary)', fontSize: 12 }}\n tickLine={{ stroke: 'var(--color-border-default)' }}\n axisLine={{ stroke: 'var(--color-border-default)' }}\n />\n\n <YAxis\n tick={{ fill: 'var(--color-text-secondary)', fontSize: 12 }}\n tickLine={{ stroke: 'var(--color-border-default)' }}\n axisLine={{ stroke: 'var(--color-border-default)' }}\n tickFormatter={formatValue}\n scale={config.logScale ? 'log' : 'auto'}\n domain={config.logScale ? ['auto', 'auto'] : undefined}\n allowDataOverflow={config.logScale || undefined}\n />\n\n <Tooltip\n content={<ChartTooltip valueFormatter={formatValue} />}\n cursor={{ fill: 'var(--color-bg-muted)', opacity: 0.5 }}\n />\n\n {config.showLegend !== false && (\n <Legend\n wrapperStyle={{ paddingTop: 20 }}\n formatter={(value) => <span style={{ color: 'var(--color-text-primary)' }}>{value}</span>}\n />\n )}\n\n {buildReferenceElements(config.referenceLines)}\n\n {dataKeys.map((key, index) => (\n <Bar\n key={key}\n dataKey={key}\n name={config.seriesNames?.[key] || key}\n fill={config.colors?.[index] || DEFAULT_COLORS[index % DEFAULT_COLORS.length]}\n radius={[4, 4, 0, 0]}\n hide={hiddenSeries.includes(key)}\n stackId={config.stacked ? 'stack' : undefined}\n />\n ))}\n </RechartsBarChart>\n </ResponsiveContainer>\n );\n});\n\nexport default BarChart;\n"],"mappings":";;;;;;AAwCA,IAAM,IAAiB;CACrB;CACA;CACA;CACA;CACA;CACD,EAMY,IAA8B,EAAK,SAAkB,EAChE,UAAO,EAAE,EACT,WACA,kBAAe,EAAE,EACjB,kBACC;CAED,IAAM,IAAW,QACV,GAAM,SACE,OAAO,KAAK,EAAK,GAAG,CAAC,QAAQ,MAAQ,MAAQ,EAAO,YAAY,OAAO,EAAK,GAAG,MAAS,SAAS,GADpF,EAAE,EAG3B,CAAC,GAAM,EAAO,SAAS,CAAC,EAGrB,KAAe,MACf,OAAO,KAAU,WACd,IAAI,KAAK,aAAa,SAAS;EACpC,UAAU,KAAS,MAAQ,YAAY;EACvC,uBAAuB;EACxB,CAAC,CAAC,OAAO,EAAM,GAJsB,OAAO,EAAM;AAWrD,QAJK,GAAM,SAKT,kBAAC,GAAD;EAAqB,OAAM;EAAO,QAAO;YACvC,kBAAC,GAAD;GACQ;GACN,QAAQ;IAAE,KAAK;IAAI,OAAO;IAAI,MAAM;IAAG,QAAQ;IAAG;GAClD,UAAU,MAAM;AACd,IAAI,GAAG,gBAAgB,MAAM,KAC3B,EAAY,EAAE,cAAc,GAAG,SAAS,EAAE,sBAAsB,EAAE;;aALxE;IASG,EAAO,aAAa,MACnB,kBAAC,GAAD;KAAe,iBAAgB;KAAM,QAAO;KAA8B,SAAS;KAAK,UAAU;KAAS,CAAA;IAG7G,kBAAC,GAAD;KACE,SAAS,EAAO,YAAY;KAC5B,MAAM;MAAE,MAAM;MAA+B,UAAU;MAAI;KAC3D,UAAU,EAAE,QAAQ,+BAA+B;KACnD,UAAU,EAAE,QAAQ,+BAA+B;KACnD,CAAA;IAEF,kBAAC,GAAD;KACE,MAAM;MAAE,MAAM;MAA+B,UAAU;MAAI;KAC3D,UAAU,EAAE,QAAQ,+BAA+B;KACnD,UAAU,EAAE,QAAQ,+BAA+B;KACnD,eAAe;KACf,OAAO,EAAO,WAAW,QAAQ;KACjC,QAAQ,EAAO,WAAW,CAAC,QAAQ,OAAO,GAAG,KAAA;KAC7C,mBAAmB,EAAO,YAAY,KAAA;KACtC,CAAA;IAEF,kBAAC,GAAD;KACE,SAAS,kBAAC,GAAD,EAAc,gBAAgB,GAAe,CAAA;KACtD,QAAQ;MAAE,MAAM;MAAyB,SAAS;MAAK;KACvD,CAAA;IAED,EAAO,eAAe,MACrB,kBAAC,GAAD;KACE,cAAc,EAAE,YAAY,IAAI;KAChC,YAAY,MAAU,kBAAC,QAAD;MAAM,OAAO,EAAE,OAAO,6BAA6B;gBAAG;MAAa,CAAA;KACzF,CAAA;IAGH,EAAuB,EAAO,eAAe;IAE7C,EAAS,KAAK,GAAK,MAClB,kBAAC,GAAD;KAEE,SAAS;KACT,MAAM,EAAO,cAAc,MAAQ;KACnC,MAAM,EAAO,SAAS,MAAU,EAAe,IAAQ,EAAe;KACtE,QAAQ;MAAC;MAAG;MAAG;MAAG;MAAE;KACpB,MAAM,EAAa,SAAS,EAAI;KAChC,SAAS,EAAO,UAAU,UAAU,KAAA;KACpC,EAPK,EAOL,CACF;IACe;;EACC,CAAA,
|
|
1
|
+
{"version":3,"file":"BarChart.js","names":[],"sources":["../../../../../../src/bigconsole/components/widgets/chart/charts/BarChart.tsx"],"sourcesContent":["/**\n * BarChart Component\n *\n * Bar chart using Recharts.\n */\n\nimport { type FC, memo, useMemo } from 'react';\nimport {\n BarChart as RechartsBarChart,\n Bar,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n ResponsiveContainer,\n Legend,\n} from 'recharts';\nimport { ChartTooltip } from '../ChartTooltip';\nimport type { ChartConfig, ChartData } from './types';\nimport { buildReferenceElements } from './referenceElements';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface BarChartProps {\n /** Chart data */\n data: ChartData[];\n /** Chart configuration */\n config: ChartConfig;\n /** Series to hide */\n hiddenSeries?: string[];\n /** Click handler for bars */\n onDataClick?: (data: ChartData, index: number) => 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 BarChart: FC<BarChartProps> = memo(function BarChart({\n data = [],\n config,\n hiddenSeries = [],\n onDataClick,\n}) {\n // Extract data keys (series)\n const dataKeys = useMemo(() => {\n if (!data?.length) return [];\n const keys = Object.keys(data[0]).filter((key) => key !== config.xAxisKey && typeof data[0][key] === 'number');\n return keys;\n }, [data, config.xAxisKey]);\n\n // Format value\n const formatValue = (value: number | string): string => {\n if (typeof value !== 'number') return String(value);\n return new Intl.NumberFormat('en-US', {\n notation: value >= 10000 ? 'compact' : 'standard',\n maximumFractionDigits: 2,\n }).format(value);\n };\n\n if (!data?.length) {\n return null;\n }\n\n return (\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <RechartsBarChart\n data={data}\n margin={{ top: 10, right: 10, left: 0, bottom: 0 }}\n onClick={(e) => {\n if (e?.activePayload?.[0] && onDataClick) {\n onDataClick(e.activePayload[0].payload, e.activeTooltipIndex || 0);\n }\n }}\n >\n {config.showGrid !== false && (\n <CartesianGrid strokeDasharray=\"3 3\" stroke=\"var(--color-border-default)\" opacity={0.5} vertical={false} />\n )}\n\n <XAxis\n dataKey={config.xAxisKey || 'name'}\n tick={{ fill: 'var(--color-text-secondary)', fontSize: 12 }}\n tickLine={{ stroke: 'var(--color-border-default)' }}\n axisLine={{ stroke: 'var(--color-border-default)' }}\n label={\n config.xAxisLabel\n ? {\n value: config.xAxisLabel,\n position: 'insideBottom',\n offset: -5,\n fill: 'var(--color-text-secondary)',\n }\n : undefined\n }\n />\n\n <YAxis\n tick={{ fill: 'var(--color-text-secondary)', fontSize: 12 }}\n tickLine={{ stroke: 'var(--color-border-default)' }}\n axisLine={{ stroke: 'var(--color-border-default)' }}\n tickFormatter={formatValue}\n scale={config.logScale ? 'log' : 'auto'}\n domain={config.logScale ? ['auto', 'auto'] : undefined}\n allowDataOverflow={config.logScale || undefined}\n label={\n config.yAxisLabel\n ? {\n value: config.yAxisLabel,\n angle: -90,\n position: 'insideLeft',\n fill: 'var(--color-text-secondary)',\n }\n : undefined\n }\n />\n\n <Tooltip\n content={<ChartTooltip valueFormatter={formatValue} />}\n cursor={{ fill: 'var(--color-bg-muted)', opacity: 0.5 }}\n />\n\n {config.showLegend !== false && (\n <Legend\n wrapperStyle={{ paddingTop: 20 }}\n formatter={(value) => <span style={{ color: 'var(--color-text-primary)' }}>{value}</span>}\n />\n )}\n\n {buildReferenceElements(config.referenceLines)}\n\n {dataKeys.map((key, index) => (\n <Bar\n key={key}\n dataKey={key}\n name={config.seriesNames?.[key] || key}\n fill={config.colors?.[index] || DEFAULT_COLORS[index % DEFAULT_COLORS.length]}\n radius={[4, 4, 0, 0]}\n hide={hiddenSeries.includes(key)}\n stackId={config.stacked ? 'stack' : undefined}\n />\n ))}\n </RechartsBarChart>\n </ResponsiveContainer>\n );\n});\n\nexport default BarChart;\n"],"mappings":";;;;;;AAwCA,IAAM,IAAiB;CACrB;CACA;CACA;CACA;CACA;CACD,EAMY,IAA8B,EAAK,SAAkB,EAChE,UAAO,EAAE,EACT,WACA,kBAAe,EAAE,EACjB,kBACC;CAED,IAAM,IAAW,QACV,GAAM,SACE,OAAO,KAAK,EAAK,GAAG,CAAC,QAAQ,MAAQ,MAAQ,EAAO,YAAY,OAAO,EAAK,GAAG,MAAS,SAAS,GADpF,EAAE,EAG3B,CAAC,GAAM,EAAO,SAAS,CAAC,EAGrB,KAAe,MACf,OAAO,KAAU,WACd,IAAI,KAAK,aAAa,SAAS;EACpC,UAAU,KAAS,MAAQ,YAAY;EACvC,uBAAuB;EACxB,CAAC,CAAC,OAAO,EAAM,GAJsB,OAAO,EAAM;AAWrD,QAJK,GAAM,SAKT,kBAAC,GAAD;EAAqB,OAAM;EAAO,QAAO;YACvC,kBAAC,GAAD;GACQ;GACN,QAAQ;IAAE,KAAK;IAAI,OAAO;IAAI,MAAM;IAAG,QAAQ;IAAG;GAClD,UAAU,MAAM;AACd,IAAI,GAAG,gBAAgB,MAAM,KAC3B,EAAY,EAAE,cAAc,GAAG,SAAS,EAAE,sBAAsB,EAAE;;aALxE;IASG,EAAO,aAAa,MACnB,kBAAC,GAAD;KAAe,iBAAgB;KAAM,QAAO;KAA8B,SAAS;KAAK,UAAU;KAAS,CAAA;IAG7G,kBAAC,GAAD;KACE,SAAS,EAAO,YAAY;KAC5B,MAAM;MAAE,MAAM;MAA+B,UAAU;MAAI;KAC3D,UAAU,EAAE,QAAQ,+BAA+B;KACnD,UAAU,EAAE,QAAQ,+BAA+B;KACnD,OACE,EAAO,aACH;MACE,OAAO,EAAO;MACd,UAAU;MACV,QAAQ;MACR,MAAM;MACP,GACD,KAAA;KAEN,CAAA;IAEF,kBAAC,GAAD;KACE,MAAM;MAAE,MAAM;MAA+B,UAAU;MAAI;KAC3D,UAAU,EAAE,QAAQ,+BAA+B;KACnD,UAAU,EAAE,QAAQ,+BAA+B;KACnD,eAAe;KACf,OAAO,EAAO,WAAW,QAAQ;KACjC,QAAQ,EAAO,WAAW,CAAC,QAAQ,OAAO,GAAG,KAAA;KAC7C,mBAAmB,EAAO,YAAY,KAAA;KACtC,OACE,EAAO,aACH;MACE,OAAO,EAAO;MACd,OAAO;MACP,UAAU;MACV,MAAM;MACP,GACD,KAAA;KAEN,CAAA;IAEF,kBAAC,GAAD;KACE,SAAS,kBAAC,GAAD,EAAc,gBAAgB,GAAe,CAAA;KACtD,QAAQ;MAAE,MAAM;MAAyB,SAAS;MAAK;KACvD,CAAA;IAED,EAAO,eAAe,MACrB,kBAAC,GAAD;KACE,cAAc,EAAE,YAAY,IAAI;KAChC,YAAY,MAAU,kBAAC,QAAD;MAAM,OAAO,EAAE,OAAO,6BAA6B;gBAAG;MAAa,CAAA;KACzF,CAAA;IAGH,EAAuB,EAAO,eAAe;IAE7C,EAAS,KAAK,GAAK,MAClB,kBAAC,GAAD;KAEE,SAAS;KACT,MAAM,EAAO,cAAc,MAAQ;KACnC,MAAM,EAAO,SAAS,MAAU,EAAe,IAAQ,EAAe;KACtE,QAAQ;MAAC;MAAG;MAAG;MAAG;MAAE;KACpB,MAAM,EAAa,SAAS,EAAI;KAChC,SAAS,EAAO,UAAU,UAAU,KAAA;KACpC,EAPK,EAOL,CACF;IACe;;EACC,CAAA,GAjFf;EAmFT"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { memo as e, useCallback as t } from "react";
|
|
2
|
+
import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
3
|
+
//#region src/bigconsole/components/widgets/heatmap/HeatmapConfig.tsx
|
|
4
|
+
var i = [
|
|
5
|
+
{
|
|
6
|
+
value: "blue",
|
|
7
|
+
label: "Blue"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
value: "green",
|
|
11
|
+
label: "Green"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
value: "red",
|
|
15
|
+
label: "Red"
|
|
16
|
+
}
|
|
17
|
+
], a = "\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n", o = e(function({ config: e, onChange: o }) {
|
|
18
|
+
let s = t((t, n) => {
|
|
19
|
+
o({
|
|
20
|
+
...e,
|
|
21
|
+
[t]: n
|
|
22
|
+
});
|
|
23
|
+
}, [e, o]);
|
|
24
|
+
return /* @__PURE__ */ r("div", {
|
|
25
|
+
className: "space-y-4",
|
|
26
|
+
children: [
|
|
27
|
+
/* @__PURE__ */ r("div", { children: [/* @__PURE__ */ n("label", {
|
|
28
|
+
className: "block text-sm font-medium text-text-primary mb-1",
|
|
29
|
+
children: "X-Axis Field"
|
|
30
|
+
}), /* @__PURE__ */ n("input", {
|
|
31
|
+
type: "text",
|
|
32
|
+
value: e.xAxisField || "",
|
|
33
|
+
onChange: (e) => s("xAxisField", e.target.value),
|
|
34
|
+
placeholder: "e.g., hour, column",
|
|
35
|
+
className: a
|
|
36
|
+
})] }),
|
|
37
|
+
/* @__PURE__ */ r("div", { children: [/* @__PURE__ */ n("label", {
|
|
38
|
+
className: "block text-sm font-medium text-text-primary mb-1",
|
|
39
|
+
children: "Y-Axis Field"
|
|
40
|
+
}), /* @__PURE__ */ n("input", {
|
|
41
|
+
type: "text",
|
|
42
|
+
value: e.yAxisField || "",
|
|
43
|
+
onChange: (e) => s("yAxisField", e.target.value),
|
|
44
|
+
placeholder: "e.g., day, row",
|
|
45
|
+
className: a
|
|
46
|
+
})] }),
|
|
47
|
+
/* @__PURE__ */ r("div", { children: [
|
|
48
|
+
/* @__PURE__ */ n("label", {
|
|
49
|
+
className: "block text-sm font-medium text-text-primary mb-1",
|
|
50
|
+
children: "Value Field"
|
|
51
|
+
}),
|
|
52
|
+
/* @__PURE__ */ n("input", {
|
|
53
|
+
type: "text",
|
|
54
|
+
value: e.valueField || "",
|
|
55
|
+
onChange: (e) => s("valueField", e.target.value),
|
|
56
|
+
placeholder: "e.g., tickets, count",
|
|
57
|
+
className: a
|
|
58
|
+
}),
|
|
59
|
+
/* @__PURE__ */ r("p", {
|
|
60
|
+
className: "mt-1 text-xs text-text-secondary",
|
|
61
|
+
children: [
|
|
62
|
+
"Left empty, the widget reads the parser's ",
|
|
63
|
+
/* @__PURE__ */ n("code", { children: "rows" }),
|
|
64
|
+
" / ",
|
|
65
|
+
/* @__PURE__ */ n("code", { children: "columns" }),
|
|
66
|
+
" / ",
|
|
67
|
+
/* @__PURE__ */ n("code", { children: "cells" }),
|
|
68
|
+
" ",
|
|
69
|
+
"output directly."
|
|
70
|
+
]
|
|
71
|
+
})
|
|
72
|
+
] }),
|
|
73
|
+
/* @__PURE__ */ r("div", { children: [/* @__PURE__ */ n("label", {
|
|
74
|
+
className: "block text-sm font-medium text-text-primary mb-1",
|
|
75
|
+
children: "Color Scheme"
|
|
76
|
+
}), /* @__PURE__ */ n("select", {
|
|
77
|
+
value: e.colorScheme || "blue",
|
|
78
|
+
onChange: (e) => s("colorScheme", e.target.value),
|
|
79
|
+
className: a,
|
|
80
|
+
children: i.map((e) => /* @__PURE__ */ n("option", {
|
|
81
|
+
value: e.value,
|
|
82
|
+
children: e.label
|
|
83
|
+
}, e.value))
|
|
84
|
+
})] }),
|
|
85
|
+
/* @__PURE__ */ r("div", { children: [/* @__PURE__ */ n("label", {
|
|
86
|
+
className: "block text-sm font-medium text-text-primary mb-1",
|
|
87
|
+
children: "Decimal Places"
|
|
88
|
+
}), /* @__PURE__ */ n("input", {
|
|
89
|
+
type: "number",
|
|
90
|
+
min: 0,
|
|
91
|
+
max: 6,
|
|
92
|
+
value: e.decimals ?? 0,
|
|
93
|
+
onChange: (e) => s("decimals", Number(e.target.value)),
|
|
94
|
+
className: a
|
|
95
|
+
})] }),
|
|
96
|
+
/* @__PURE__ */ r("label", {
|
|
97
|
+
className: "flex items-center gap-3",
|
|
98
|
+
children: [/* @__PURE__ */ n("input", {
|
|
99
|
+
type: "checkbox",
|
|
100
|
+
checked: e.showValues !== !1,
|
|
101
|
+
onChange: (e) => s("showValues", e.target.checked),
|
|
102
|
+
className: "\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n "
|
|
103
|
+
}), /* @__PURE__ */ n("span", {
|
|
104
|
+
className: "text-sm text-text-primary",
|
|
105
|
+
children: "Show cell values"
|
|
106
|
+
})]
|
|
107
|
+
}),
|
|
108
|
+
/* @__PURE__ */ r("label", {
|
|
109
|
+
className: "flex items-center gap-3",
|
|
110
|
+
children: [/* @__PURE__ */ n("input", {
|
|
111
|
+
type: "checkbox",
|
|
112
|
+
checked: e.showLegend !== !1,
|
|
113
|
+
onChange: (e) => s("showLegend", e.target.checked),
|
|
114
|
+
className: "\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n "
|
|
115
|
+
}), /* @__PURE__ */ n("span", {
|
|
116
|
+
className: "text-sm text-text-primary",
|
|
117
|
+
children: "Show color legend"
|
|
118
|
+
})]
|
|
119
|
+
})
|
|
120
|
+
]
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
//#endregion
|
|
124
|
+
export { o as default };
|
|
125
|
+
|
|
126
|
+
//# sourceMappingURL=HeatmapConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HeatmapConfig.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/heatmap/HeatmapConfig.tsx"],"sourcesContent":["/**\n * HeatmapConfig Component\n *\n * Configuration panel for Heatmap widgets.\n */\n\nimport { type FC, memo, useCallback } from 'react';\nimport type { HeatmapConfig as ConfigType } from '../../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface HeatmapConfigProps {\n /** Current configuration */\n config: ConfigType;\n /** Callback when config changes */\n onChange: (config: ConfigType) => void;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst COLOR_SCHEMES = [\n { value: 'blue', label: 'Blue' },\n { value: 'green', label: 'Green' },\n { value: 'red', label: 'Red' },\n];\n\nconst FIELD_CLASSES = `\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n`;\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const HeatmapConfig: FC<HeatmapConfigProps> = memo(function HeatmapConfig({ config, onChange }) {\n const handleChange = useCallback(\n <K extends keyof ConfigType>(key: K, value: ConfigType[K]) => {\n onChange({ ...config, [key]: value });\n },\n [config, onChange]\n );\n\n return (\n <div className=\"space-y-4\">\n {/* Axis + value fields */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">X-Axis Field</label>\n <input\n type=\"text\"\n value={config.xAxisField || ''}\n onChange={(e) => handleChange('xAxisField', e.target.value)}\n placeholder=\"e.g., hour, column\"\n className={FIELD_CLASSES}\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Y-Axis Field</label>\n <input\n type=\"text\"\n value={config.yAxisField || ''}\n onChange={(e) => handleChange('yAxisField', e.target.value)}\n placeholder=\"e.g., day, row\"\n className={FIELD_CLASSES}\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Value Field</label>\n <input\n type=\"text\"\n value={config.valueField || ''}\n onChange={(e) => handleChange('valueField', e.target.value)}\n placeholder=\"e.g., tickets, count\"\n className={FIELD_CLASSES}\n />\n <p className=\"mt-1 text-xs text-text-secondary\">\n Left empty, the widget reads the parser's <code>rows</code> / <code>columns</code> / <code>cells</code>{' '}\n output directly.\n </p>\n </div>\n\n {/* Color scheme */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Color Scheme</label>\n <select\n value={config.colorScheme || 'blue'}\n onChange={(e) => handleChange('colorScheme', e.target.value)}\n className={FIELD_CLASSES}\n >\n {COLOR_SCHEMES.map((scheme) => (\n <option key={scheme.value} value={scheme.value}>\n {scheme.label}\n </option>\n ))}\n </select>\n </div>\n\n {/* Decimals */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Decimal Places</label>\n <input\n type=\"number\"\n min={0}\n max={6}\n value={config.decimals ?? 0}\n onChange={(e) => handleChange('decimals', Number(e.target.value))}\n className={FIELD_CLASSES}\n />\n </div>\n\n {/* Toggles */}\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showValues !== false}\n onChange={(e) => handleChange('showValues', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Show cell values</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showLegend !== false}\n onChange={(e) => handleChange('showLegend', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Show color legend</span>\n </label>\n </div>\n );\n});\n\nexport default HeatmapConfig;\n"],"mappings":";;;AAwBA,IAAM,IAAgB;CACpB;EAAE,OAAO;EAAQ,OAAO;EAAQ;CAChC;EAAE,OAAO;EAAS,OAAO;EAAS;CAClC;EAAE,OAAO;EAAO,OAAO;EAAO;CAC/B,EAEK,IAAgB,sLAaT,IAAwC,EAAK,SAAuB,EAAE,WAAQ,eAAY;CACrG,IAAM,IAAe,GACU,GAAQ,MAAyB;AAC5D,IAAS;GAAE,GAAG;IAAS,IAAM;GAAO,CAAC;IAEvC,CAAC,GAAQ,EAAS,CACnB;AAED,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;IAAO,WAAU;cAAmD;IAAoB,CAAA,EACxF,kBAAC,SAAD;IACE,MAAK;IACL,OAAO,EAAO,cAAc;IAC5B,WAAW,MAAM,EAAa,cAAc,EAAE,OAAO,MAAM;IAC3D,aAAY;IACZ,WAAW;IACX,CAAA,CACE,EAAA,CAAA;GAEN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;IAAO,WAAU;cAAmD;IAAoB,CAAA,EACxF,kBAAC,SAAD;IACE,MAAK;IACL,OAAO,EAAO,cAAc;IAC5B,WAAW,MAAM,EAAa,cAAc,EAAE,OAAO,MAAM;IAC3D,aAAY;IACZ,WAAW;IACX,CAAA,CACE,EAAA,CAAA;GAEN,kBAAC,OAAD,EAAA,UAAA;IACE,kBAAC,SAAD;KAAO,WAAU;eAAmD;KAAmB,CAAA;IACvF,kBAAC,SAAD;KACE,MAAK;KACL,OAAO,EAAO,cAAc;KAC5B,WAAW,MAAM,EAAa,cAAc,EAAE,OAAO,MAAM;KAC3D,aAAY;KACZ,WAAW;KACX,CAAA;IACF,kBAAC,KAAD;KAAG,WAAU;eAAb;MAAgD;MACC,kBAAC,QAAD,EAAA,UAAM,QAAW,CAAA;;MAAG,kBAAC,QAAD,EAAA,UAAM,WAAc,CAAA;;MAAG,kBAAC,QAAD,EAAA,UAAM,SAAY,CAAA;MAAC;MAAI;MAE/G;;IACA,EAAA,CAAA;GAGN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;IAAO,WAAU;cAAmD;IAAoB,CAAA,EACxF,kBAAC,UAAD;IACE,OAAO,EAAO,eAAe;IAC7B,WAAW,MAAM,EAAa,eAAe,EAAE,OAAO,MAAM;IAC5D,WAAW;cAEV,EAAc,KAAK,MAClB,kBAAC,UAAD;KAA2B,OAAO,EAAO;eACtC,EAAO;KACD,EAFI,EAAO,MAEX,CACT;IACK,CAAA,CACL,EAAA,CAAA;GAGN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;IAAO,WAAU;cAAmD;IAAsB,CAAA,EAC1F,kBAAC,SAAD;IACE,MAAK;IACL,KAAK;IACL,KAAK;IACL,OAAO,EAAO,YAAY;IAC1B,WAAW,MAAM,EAAa,YAAY,OAAO,EAAE,OAAO,MAAM,CAAC;IACjE,WAAW;IACX,CAAA,CACE,EAAA,CAAA;GAGN,kBAAC,SAAD;IAAO,WAAU;cAAjB,CACE,kBAAC,SAAD;KACE,MAAK;KACL,SAAS,EAAO,eAAe;KAC/B,WAAW,MAAM,EAAa,cAAc,EAAE,OAAO,QAAQ;KAC7D,WAAU;KAQV,CAAA,EACF,kBAAC,QAAD;KAAM,WAAU;eAA4B;KAAuB,CAAA,CAC7D;;GAER,kBAAC,SAAD;IAAO,WAAU;cAAjB,CACE,kBAAC,SAAD;KACE,MAAK;KACL,SAAS,EAAO,eAAe;KAC/B,WAAW,MAAM,EAAa,cAAc,EAAE,OAAO,QAAQ;KAC7D,WAAU;KAQV,CAAA,EACF,kBAAC,QAAD;KAAM,WAAU;eAA4B;KAAwB,CAAA,CAC9D;;GACJ;;EAER"}
|
|
@@ -32,9 +32,9 @@ var o = e(function({ widget: e, data: o, onClick: s }) {
|
|
|
32
32
|
className: "flex items-center justify-center h-full text-text-secondary text-sm",
|
|
33
33
|
children: "No heatmap data available"
|
|
34
34
|
}) : /* @__PURE__ */ i("div", {
|
|
35
|
-
className: "flex flex-col h-full p-4
|
|
35
|
+
className: "flex flex-col h-full p-4",
|
|
36
36
|
children: [/* @__PURE__ */ r("div", {
|
|
37
|
-
className: "overflow-auto",
|
|
37
|
+
className: "min-h-0 flex-1 overflow-auto",
|
|
38
38
|
children: /* @__PURE__ */ i("table", {
|
|
39
39
|
className: "w-full border-collapse",
|
|
40
40
|
children: [/* @__PURE__ */ r("thead", { children: /* @__PURE__ */ i("tr", { children: [/* @__PURE__ */ r("th", { className: "p-2 text-xs text-text-secondary text-left" }), o.columns.map((e) => /* @__PURE__ */ r("th", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HeatmapWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/heatmap/HeatmapWidget.tsx"],"sourcesContent":["/**\n * HeatmapWidget Component\n *\n * Heatmap grid visualization with color intensity based on values.\n */\n\nimport { type FC, memo, useMemo, useCallback } from 'react';\nimport type { Widget, HeatmapConfig } from '../../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface HeatmapWidgetProps {\n widget: Widget;\n data?: HeatmapData;\n onClick?: (cell: HeatmapCell) => void;\n}\n\nexport interface HeatmapCell {\n row: string;\n column: string;\n value: number;\n}\n\nexport interface HeatmapData {\n rows: string[];\n columns: string[];\n cells: HeatmapCell[];\n minValue?: number;\n maxValue?: number;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction getColorIntensity(value: number, min: number, max: number, colorScheme: string = 'blue'): string {\n const normalized = Math.max(0, Math.min(1, (value - min) / (max - min || 1)));\n\n // Color schemes using CSS variables\n if (colorScheme === 'green') {\n if (normalized < 0.2) return 'bg-state-success/10';\n if (normalized < 0.4) return 'bg-state-success/30';\n if (normalized < 0.6) return 'bg-state-success/50';\n if (normalized < 0.8) return 'bg-state-success/70';\n return 'bg-state-success/90';\n }\n\n if (colorScheme === 'red') {\n if (normalized < 0.2) return 'bg-state-error/10';\n if (normalized < 0.4) return 'bg-state-error/30';\n if (normalized < 0.6) return 'bg-state-error/50';\n if (normalized < 0.8) return 'bg-state-error/70';\n return 'bg-state-error/90';\n }\n\n // Default blue\n if (normalized < 0.2) return 'bg-action-primary-bg/10';\n if (normalized < 0.4) return 'bg-action-primary-bg/30';\n if (normalized < 0.6) return 'bg-action-primary-bg/50';\n if (normalized < 0.8) return 'bg-action-primary-bg/70';\n return 'bg-action-primary-bg/90';\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const HeatmapWidget: FC<HeatmapWidgetProps> = memo(function HeatmapWidget({ widget, data, onClick }) {\n const config = widget.config as unknown as HeatmapConfig | undefined;\n\n // Build cell lookup map\n const cellMap = useMemo(() => {\n const map = new Map<string, number>();\n if (data?.cells && Array.isArray(data.cells)) {\n data.cells.forEach((cell) => {\n map.set(`${cell.row}:${cell.column}`, cell.value);\n });\n }\n return map;\n }, [data?.cells]);\n\n // Calculate min/max\n const { minValue, maxValue } = useMemo(() => {\n if (!data?.cells || !Array.isArray(data.cells) || !data.cells.length) {\n return { minValue: 0, maxValue: 100 };\n }\n\n const values = data.cells.map((c) => c.value);\n return {\n minValue: data.minValue ?? Math.min(...values),\n maxValue: data.maxValue ?? Math.max(...values),\n };\n }, [data]);\n\n const handleCellClick = useCallback(\n (row: string, column: string, value: number) => {\n if (onClick && widget.drilldowns?.length) {\n onClick({ row, column, value });\n }\n },\n [onClick, widget.drilldowns]\n );\n\n const isClickable = Boolean(onClick && widget.drilldowns?.length);\n\n // Early return if data is not properly structured\n if (!data || !Array.isArray(data.rows) || !Array.isArray(data.columns) || !data.rows.length || !data.columns.length) {\n return (\n <div className=\"flex items-center justify-center h-full text-text-secondary text-sm\">\n No heatmap data available\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col h-full p-4
|
|
1
|
+
{"version":3,"file":"HeatmapWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/heatmap/HeatmapWidget.tsx"],"sourcesContent":["/**\n * HeatmapWidget Component\n *\n * Heatmap grid visualization with color intensity based on values.\n */\n\nimport { type FC, memo, useMemo, useCallback } from 'react';\nimport type { Widget, HeatmapConfig } from '../../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface HeatmapWidgetProps {\n widget: Widget;\n data?: HeatmapData;\n onClick?: (cell: HeatmapCell) => void;\n}\n\nexport interface HeatmapCell {\n row: string;\n column: string;\n value: number;\n}\n\nexport interface HeatmapData {\n rows: string[];\n columns: string[];\n cells: HeatmapCell[];\n minValue?: number;\n maxValue?: number;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction getColorIntensity(value: number, min: number, max: number, colorScheme: string = 'blue'): string {\n const normalized = Math.max(0, Math.min(1, (value - min) / (max - min || 1)));\n\n // Color schemes using CSS variables\n if (colorScheme === 'green') {\n if (normalized < 0.2) return 'bg-state-success/10';\n if (normalized < 0.4) return 'bg-state-success/30';\n if (normalized < 0.6) return 'bg-state-success/50';\n if (normalized < 0.8) return 'bg-state-success/70';\n return 'bg-state-success/90';\n }\n\n if (colorScheme === 'red') {\n if (normalized < 0.2) return 'bg-state-error/10';\n if (normalized < 0.4) return 'bg-state-error/30';\n if (normalized < 0.6) return 'bg-state-error/50';\n if (normalized < 0.8) return 'bg-state-error/70';\n return 'bg-state-error/90';\n }\n\n // Default blue\n if (normalized < 0.2) return 'bg-action-primary-bg/10';\n if (normalized < 0.4) return 'bg-action-primary-bg/30';\n if (normalized < 0.6) return 'bg-action-primary-bg/50';\n if (normalized < 0.8) return 'bg-action-primary-bg/70';\n return 'bg-action-primary-bg/90';\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const HeatmapWidget: FC<HeatmapWidgetProps> = memo(function HeatmapWidget({ widget, data, onClick }) {\n const config = widget.config as unknown as HeatmapConfig | undefined;\n\n // Build cell lookup map\n const cellMap = useMemo(() => {\n const map = new Map<string, number>();\n if (data?.cells && Array.isArray(data.cells)) {\n data.cells.forEach((cell) => {\n map.set(`${cell.row}:${cell.column}`, cell.value);\n });\n }\n return map;\n }, [data?.cells]);\n\n // Calculate min/max\n const { minValue, maxValue } = useMemo(() => {\n if (!data?.cells || !Array.isArray(data.cells) || !data.cells.length) {\n return { minValue: 0, maxValue: 100 };\n }\n\n const values = data.cells.map((c) => c.value);\n return {\n minValue: data.minValue ?? Math.min(...values),\n maxValue: data.maxValue ?? Math.max(...values),\n };\n }, [data]);\n\n const handleCellClick = useCallback(\n (row: string, column: string, value: number) => {\n if (onClick && widget.drilldowns?.length) {\n onClick({ row, column, value });\n }\n },\n [onClick, widget.drilldowns]\n );\n\n const isClickable = Boolean(onClick && widget.drilldowns?.length);\n\n // Early return if data is not properly structured\n if (!data || !Array.isArray(data.rows) || !Array.isArray(data.columns) || !data.rows.length || !data.columns.length) {\n return (\n <div className=\"flex items-center justify-center h-full text-text-secondary text-sm\">\n No heatmap data available\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col h-full p-4\">\n {/* Grid — `min-h-0` lets this flex child shrink so it scrolls instead of\n clipping its last rows when the widget is shorter than the grid. */}\n <div className=\"min-h-0 flex-1 overflow-auto\">\n <table className=\"w-full border-collapse\">\n <thead>\n <tr>\n <th className=\"p-2 text-xs text-text-secondary text-left\" />\n {data.columns.map((col) => (\n <th key={col} className=\"p-2 text-xs font-medium text-text-secondary text-center min-w-[60px]\">\n {col}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.rows.map((row) => (\n <tr key={row}>\n <td className=\"p-2 text-xs font-medium text-text-secondary text-left\">{row}</td>\n {data.columns.map((col) => {\n const value = cellMap.get(`${row}:${col}`) ?? 0;\n const colorClass = getColorIntensity(value, minValue, maxValue, config?.colorScheme);\n\n return (\n <td\n key={col}\n className={`\n p-0 text-center\n ${isClickable ? 'cursor-pointer' : ''}\n `}\n onClick={() => handleCellClick(row, col, value)}\n >\n <div\n className={`\n m-0.5 p-2 rounded\n ${colorClass}\n ${isClickable ? 'hover:ring-2 hover:ring-action-primary-bg' : ''}\n transition-all\n `}\n title={`${row} / ${col}: ${value}`}\n >\n {config?.showValues !== false && (\n <span className=\"text-xs font-medium text-text-primary\">\n {typeof value === 'number' ? value.toFixed(config?.decimals || 0) : value}\n </span>\n )}\n </div>\n </td>\n );\n })}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n\n {/* Legend */}\n {config?.showLegend !== false && (\n <div className=\"flex items-center justify-center gap-2 mt-4\">\n <span className=\"text-xs text-text-secondary\">Low</span>\n <div className=\"flex gap-0.5\">\n {[10, 30, 50, 70, 90].map((opacity) => (\n <div key={opacity} className={`w-6 h-4 rounded bg-action-primary-bg/${opacity}`} />\n ))}\n </div>\n <span className=\"text-xs text-text-secondary\">High</span>\n </div>\n )}\n </div>\n );\n});\n\nexport default HeatmapWidget;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import e from "../hooks/useWidgetOperations.js";
|
|
2
|
+
import t from "../hooks/useDataSinkOperations.js";
|
|
3
|
+
import n from "../hooks/useParserOperations.js";
|
|
4
|
+
import "../hooks/index.js";
|
|
5
|
+
import r from "./CustomWidgetProposalPanel.js";
|
|
6
|
+
import { memo as i, useCallback as a, useMemo as o } from "react";
|
|
7
|
+
import { Sheet as s, SheetContent as c, SheetDescription as l, SheetHeader as u, SheetTitle as d } from "@burdenoff/fe-libs/ui";
|
|
8
|
+
import { jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
9
|
+
//#region src/bigconsole/customWidget/CustomWidgetBuilderSheet.tsx
|
|
10
|
+
var m = {
|
|
11
|
+
x: 0,
|
|
12
|
+
y: 0,
|
|
13
|
+
width: 6,
|
|
14
|
+
height: 4
|
|
15
|
+
}, h = i(function({ isOpen: i, onClose: h, dashboardId: g, pageId: _, source: v }) {
|
|
16
|
+
let { dataSinks: y } = t({ skipFetch: !i }), { parsers: b, executeParser: x } = n({
|
|
17
|
+
consoleId: g,
|
|
18
|
+
skipFetch: !i
|
|
19
|
+
}), { createWidget: S } = e(_, g, { skipFetch: !0 }), C = o(() => y.map((e) => ({
|
|
20
|
+
id: e.id,
|
|
21
|
+
key: e.key,
|
|
22
|
+
name: e.name
|
|
23
|
+
})), [y]), w = o(() => b.map((e) => ({
|
|
24
|
+
id: e.id,
|
|
25
|
+
name: e.name,
|
|
26
|
+
inputSinkKey: e.inputSinkKey
|
|
27
|
+
})), [b]), T = a(async (e) => {
|
|
28
|
+
if (!e.binding.parserId) return;
|
|
29
|
+
let t = await x(e.binding.parserId);
|
|
30
|
+
if (!t || !t.success) throw Error(t?.error || "Could not resolve the binding.");
|
|
31
|
+
return t.output;
|
|
32
|
+
}, [x]), E = a(async (e) => {
|
|
33
|
+
if (!await S({
|
|
34
|
+
pageId: _,
|
|
35
|
+
dashboardId: g,
|
|
36
|
+
type: e.widgetType,
|
|
37
|
+
title: e.presentation.title,
|
|
38
|
+
description: e.presentation.description,
|
|
39
|
+
dataSinkId: e.binding.dataSinkId || void 0,
|
|
40
|
+
parserId: e.binding.parserId,
|
|
41
|
+
config: {
|
|
42
|
+
...e.presentation.config,
|
|
43
|
+
...e.fieldMapping,
|
|
44
|
+
generatedBy: e.generatedBy,
|
|
45
|
+
sourcePrompt: e.sourcePrompt,
|
|
46
|
+
proposalVersion: e.version
|
|
47
|
+
},
|
|
48
|
+
position: { ...m }
|
|
49
|
+
})) throw Error("The widget could not be created.");
|
|
50
|
+
}, [
|
|
51
|
+
S,
|
|
52
|
+
_,
|
|
53
|
+
g
|
|
54
|
+
]);
|
|
55
|
+
return /* @__PURE__ */ f(s, {
|
|
56
|
+
open: i,
|
|
57
|
+
onOpenChange: (e) => !e && h(),
|
|
58
|
+
children: /* @__PURE__ */ p(c, {
|
|
59
|
+
style: {
|
|
60
|
+
width: 480,
|
|
61
|
+
maxWidth: "95vw",
|
|
62
|
+
padding: 0,
|
|
63
|
+
display: "flex",
|
|
64
|
+
flexDirection: "column"
|
|
65
|
+
},
|
|
66
|
+
children: [/* @__PURE__ */ p(u, {
|
|
67
|
+
style: {
|
|
68
|
+
padding: 16,
|
|
69
|
+
paddingBottom: 0
|
|
70
|
+
},
|
|
71
|
+
children: [/* @__PURE__ */ f(d, { children: "AI custom widget" }), /* @__PURE__ */ f(l, { children: "Describe a widget, review the proposal, then approve it onto the dashboard." })]
|
|
72
|
+
}), /* @__PURE__ */ f("div", {
|
|
73
|
+
style: {
|
|
74
|
+
flex: 1,
|
|
75
|
+
minHeight: 0
|
|
76
|
+
},
|
|
77
|
+
children: /* @__PURE__ */ f(r, {
|
|
78
|
+
sinks: C,
|
|
79
|
+
parsers: w,
|
|
80
|
+
resolvePreviewData: T,
|
|
81
|
+
onApprove: E,
|
|
82
|
+
onClose: h,
|
|
83
|
+
source: v
|
|
84
|
+
})
|
|
85
|
+
})]
|
|
86
|
+
})
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
//#endregion
|
|
90
|
+
export { h as default };
|
|
91
|
+
|
|
92
|
+
//# sourceMappingURL=CustomWidgetBuilderSheet.js.map
|