@burdenoff/microfe-bigconsole 2026.717.4 → 2026.727.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,43 +1,45 @@
1
1
  import e from "../../widgets/chart/ChartConfig.js";
2
2
  import t from "../../widgets/gauge/GaugeConfig.js";
3
- import n from "../../widgets/list/ListConfig.js";
4
- import r from "../../widgets/metric-card/MetricCardConfig.js";
5
- import i from "../../widgets/progress/ProgressConfig.js";
6
- import a from "../../widgets/table/TableConfig.js";
7
- import { memo as o } from "react";
8
- import { jsx as s } from "react/jsx-runtime";
3
+ import n from "../../widgets/heatmap/HeatmapConfig.js";
4
+ import r from "../../widgets/list/ListConfig.js";
5
+ import i from "../../widgets/metric-card/MetricCardConfig.js";
6
+ import a from "../../widgets/progress/ProgressConfig.js";
7
+ import o from "../../widgets/table/TableConfig.js";
8
+ import { memo as s } from "react";
9
+ import { jsx as c } from "react/jsx-runtime";
9
10
  //#region src/bigconsole/components/builder/inspector/AppearanceSection.tsx
10
- function c(e) {
11
+ function l(e) {
11
12
  return e;
12
13
  }
13
- function l(o) {
14
- switch (o) {
14
+ function u(s) {
15
+ switch (s) {
15
16
  case "metric_card":
16
- case "kpi_card_comparison": return c(r);
17
+ case "kpi_card_comparison": return l(i);
17
18
  case "chart":
18
- case "funnel_chart": return c(e);
19
+ case "funnel_chart": return l(e);
19
20
  case "table":
20
- case "pivot_table": return c(a);
21
- case "gauge": return c(t);
22
- case "progress": return c(i);
23
- case "list": return c(n);
21
+ case "pivot_table": return l(o);
22
+ case "gauge": return l(t);
23
+ case "progress": return l(a);
24
+ case "list": return l(r);
25
+ case "heatmap": return l(n);
24
26
  default: return null;
25
27
  }
26
28
  }
27
- var u = o(function({ widgetType: e, config: t, onChange: n }) {
28
- let r = l(e);
29
- return r ? /* @__PURE__ */ s(r, {
29
+ var d = s(function({ widgetType: e, config: t, onChange: n }) {
30
+ let r = u(e);
31
+ return r ? /* @__PURE__ */ c(r, {
30
32
  config: t,
31
33
  onChange: n
32
- }) : /* @__PURE__ */ s("div", {
34
+ }) : /* @__PURE__ */ c("div", {
33
35
  className: "rounded-lg bg-bg-sunken p-4 text-center",
34
- children: /* @__PURE__ */ s("p", {
36
+ children: /* @__PURE__ */ c("p", {
35
37
  className: "text-sm text-text-secondary",
36
38
  children: "No style options for this widget type"
37
39
  })
38
40
  });
39
41
  });
40
42
  //#endregion
41
- export { u as AppearanceSection };
43
+ export { d as AppearanceSection };
42
44
 
43
45
  //# sourceMappingURL=AppearanceSection.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AppearanceSection.js","names":[],"sources":["../../../../../src/bigconsole/components/builder/inspector/AppearanceSection.tsx"],"sourcesContent":["import { type ComponentType, type FC, memo } from 'react';\nimport type { WidgetType } from '../../../types';\nimport { MetricCardConfig } from '../../widgets/metric-card/MetricCardConfig';\nimport { ChartConfig } from '../../widgets/chart/ChartConfig';\nimport { TableConfig } from '../../widgets/table/TableConfig';\nimport { GaugeConfig } from '../../widgets/gauge/GaugeConfig';\nimport { ProgressConfig } from '../../widgets/progress/ProgressConfig';\nimport { ListConfig } from '../../widgets/list/ListConfig';\n\ninterface ConfigComponentProps {\n config: never;\n onChange: (config: never) => void;\n}\n\n// Legacy widget config components expose distinct config interfaces even though\n// they share the same runtime { config, onChange } contract. Keep the narrowing\n// cast in this adapter instead of spreading `never` casts across inspector code.\nfunction asConfigComponent(component: ComponentType<unknown>): ComponentType<ConfigComponentProps> {\n return component as unknown as ComponentType<ConfigComponentProps>;\n}\n\nexport interface AppearanceSectionProps {\n widgetType: WidgetType;\n config: Record<string, unknown>;\n onChange: (config: Record<string, unknown>) => void;\n}\n\nfunction getConfigComponent(type: WidgetType): ComponentType<ConfigComponentProps> | null {\n switch (type) {\n case 'metric_card':\n case 'kpi_card_comparison':\n return asConfigComponent(MetricCardConfig as ComponentType<unknown>);\n case 'chart':\n case 'funnel_chart':\n return asConfigComponent(ChartConfig as ComponentType<unknown>);\n case 'table':\n case 'pivot_table':\n return asConfigComponent(TableConfig as ComponentType<unknown>);\n case 'gauge':\n return asConfigComponent(GaugeConfig as ComponentType<unknown>);\n case 'progress':\n return asConfigComponent(ProgressConfig as ComponentType<unknown>);\n case 'list':\n return asConfigComponent(ListConfig as ComponentType<unknown>);\n default:\n return null;\n }\n}\n\n/** Widget-specific visual configuration with a shared empty state. */\nexport const AppearanceSection: FC<AppearanceSectionProps> = memo(function AppearanceSection({\n widgetType,\n config,\n onChange,\n}) {\n const ConfigComponent = getConfigComponent(widgetType);\n\n if (!ConfigComponent) {\n return (\n <div className=\"rounded-lg bg-bg-sunken p-4 text-center\">\n <p className=\"text-sm text-text-secondary\">No style options for this widget type</p>\n </div>\n );\n }\n\n return <ConfigComponent config={config as never} onChange={onChange as (config: never) => void} />;\n});\n"],"mappings":";;;;;;;;;AAiBA,SAAS,EAAkB,GAAwE;AACjG,QAAO;;AAST,SAAS,EAAmB,GAA8D;AACxF,SAAQ,GAAR;EACE,KAAK;EACL,KAAK,sBACH,QAAO,EAAkB,EAA2C;EACtE,KAAK;EACL,KAAK,eACH,QAAO,EAAkB,EAAsC;EACjE,KAAK;EACL,KAAK,cACH,QAAO,EAAkB,EAAsC;EACjE,KAAK,QACH,QAAO,EAAkB,EAAsC;EACjE,KAAK,WACH,QAAO,EAAkB,EAAyC;EACpE,KAAK,OACH,QAAO,EAAkB,EAAqC;EAChE,QACE,QAAO;;;AAKb,IAAa,IAAgD,EAAK,SAA2B,EAC3F,eACA,WACA,eACC;CACD,IAAM,IAAkB,EAAmB,EAAW;AAUtD,QARK,IAQE,kBAAC,GAAD;EAAyB;EAA2B;EAAuC,CAAA,GAN9F,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,KAAD;GAAG,WAAU;aAA8B;GAAyC,CAAA;EAChF,CAAA;EAKV"}
1
+ {"version":3,"file":"AppearanceSection.js","names":[],"sources":["../../../../../src/bigconsole/components/builder/inspector/AppearanceSection.tsx"],"sourcesContent":["import { type ComponentType, type FC, memo } from 'react';\nimport type { WidgetType } from '../../../types';\nimport { MetricCardConfig } from '../../widgets/metric-card/MetricCardConfig';\nimport { ChartConfig } from '../../widgets/chart/ChartConfig';\nimport { TableConfig } from '../../widgets/table/TableConfig';\nimport { GaugeConfig } from '../../widgets/gauge/GaugeConfig';\nimport { ProgressConfig } from '../../widgets/progress/ProgressConfig';\nimport { ListConfig } from '../../widgets/list/ListConfig';\nimport { HeatmapConfig } from '../../widgets/heatmap/HeatmapConfig';\n\ninterface ConfigComponentProps {\n config: never;\n onChange: (config: never) => void;\n}\n\n// Legacy widget config components expose distinct config interfaces even though\n// they share the same runtime { config, onChange } contract. Keep the narrowing\n// cast in this adapter instead of spreading `never` casts across inspector code.\nfunction asConfigComponent(component: ComponentType<unknown>): ComponentType<ConfigComponentProps> {\n return component as unknown as ComponentType<ConfigComponentProps>;\n}\n\nexport interface AppearanceSectionProps {\n widgetType: WidgetType;\n config: Record<string, unknown>;\n onChange: (config: Record<string, unknown>) => void;\n}\n\nfunction getConfigComponent(type: WidgetType): ComponentType<ConfigComponentProps> | null {\n switch (type) {\n case 'metric_card':\n case 'kpi_card_comparison':\n return asConfigComponent(MetricCardConfig as ComponentType<unknown>);\n case 'chart':\n case 'funnel_chart':\n return asConfigComponent(ChartConfig as ComponentType<unknown>);\n case 'table':\n case 'pivot_table':\n return asConfigComponent(TableConfig as ComponentType<unknown>);\n case 'gauge':\n return asConfigComponent(GaugeConfig as ComponentType<unknown>);\n case 'progress':\n return asConfigComponent(ProgressConfig as ComponentType<unknown>);\n case 'list':\n return asConfigComponent(ListConfig as ComponentType<unknown>);\n case 'heatmap':\n return asConfigComponent(HeatmapConfig as ComponentType<unknown>);\n default:\n return null;\n }\n}\n\n/** Widget-specific visual configuration with a shared empty state. */\nexport const AppearanceSection: FC<AppearanceSectionProps> = memo(function AppearanceSection({\n widgetType,\n config,\n onChange,\n}) {\n const ConfigComponent = getConfigComponent(widgetType);\n\n if (!ConfigComponent) {\n return (\n <div className=\"rounded-lg bg-bg-sunken p-4 text-center\">\n <p className=\"text-sm text-text-secondary\">No style options for this widget type</p>\n </div>\n );\n }\n\n return <ConfigComponent config={config as never} onChange={onChange as (config: never) => void} />;\n});\n"],"mappings":";;;;;;;;;;AAkBA,SAAS,EAAkB,GAAwE;AACjG,QAAO;;AAST,SAAS,EAAmB,GAA8D;AACxF,SAAQ,GAAR;EACE,KAAK;EACL,KAAK,sBACH,QAAO,EAAkB,EAA2C;EACtE,KAAK;EACL,KAAK,eACH,QAAO,EAAkB,EAAsC;EACjE,KAAK;EACL,KAAK,cACH,QAAO,EAAkB,EAAsC;EACjE,KAAK,QACH,QAAO,EAAkB,EAAsC;EACjE,KAAK,WACH,QAAO,EAAkB,EAAyC;EACpE,KAAK,OACH,QAAO,EAAkB,EAAqC;EAChE,KAAK,UACH,QAAO,EAAkB,EAAwC;EACnE,QACE,QAAO;;;AAKb,IAAa,IAAgD,EAAK,SAA2B,EAC3F,eACA,WACA,eACC;CACD,IAAM,IAAkB,EAAmB,EAAW;AAUtD,QARK,IAQE,kBAAC,GAAD;EAAyB;EAA2B;EAAuC,CAAA,GAN9F,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,KAAD;GAAG,WAAU;aAA8B;GAAyC,CAAA;EAChF,CAAA;EAKV"}
@@ -1206,9 +1206,9 @@ var je = l(function({ isOpen: l, onClose: m }) {
1206
1206
  /* @__PURE__ */ k(E, {
1207
1207
  value: "appearance",
1208
1208
  className: "mt-0",
1209
- children: /* @__PURE__ */ k(oe, {
1209
+ children: N && /* @__PURE__ */ k(oe, {
1210
1210
  widgetType: z.type,
1211
- config: z.config || {},
1211
+ config: N.config || {},
1212
1212
  onChange: st
1213
1213
  })
1214
1214
  })
@@ -1 +1 @@
1
- {"version":3,"file":"PropertiesPanel.js","names":[],"sources":["../../../../src/bigconsole/components/widgets/PropertiesPanel.tsx"],"sourcesContent":["/**\n * PropertiesPanel Component\n *\n * Right-side panel for widget configuration.\n * v2.0: Added Actions tab for managing widget actions.\n * Uses fe-libs shared components for consistent styling.\n */\n\nimport React, { type FC, memo, useCallback, useState, useEffect, useRef } from 'react';\nimport { Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription } from '@burdenoff/fe-libs/ui';\nimport { Tabs, TabsList, TabsTrigger, TabsContent } from '@burdenoff/fe-libs/ui';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { Textarea } from '@burdenoff/fe-libs/ui';\nimport { Label } from '@burdenoff/fe-libs/ui';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@burdenoff/fe-libs/ui';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { Card, CardContent } from '@burdenoff/fe-libs/ui';\nimport { Plus, ChevronUp, ChevronDown, Pencil, Trash2, ExternalLink, Check, X, Info } from 'lucide-react';\nimport type { Widget, DataSourceType, RendererType } from '../../types';\nimport { useWidgetStore } from '../../store';\nimport { useWidgetOperations, useDrilldownOperations } from '../../hooks';\nimport {\n useWidgetActions,\n type WidgetAction,\n type CreateWidgetActionInput,\n type UpdateWidgetActionInput,\n} from '../../hooks/useWidgetActions';\nimport { getWidgetDefinition } from './WidgetRegistry';\nimport { ActionConfigDialog } from './ActionConfigDialog';\nimport { WebhookConfigPanel } from './webhook-config';\nimport { EventLogViewer } from './event-logs';\nimport { DrilldownConfigPanel, type DrilldownConfig } from './DrilldownConfigPanel';\n// Data Source selectors\nimport { useDataSinkOperations } from '../../hooks/useDataSinkOperations';\nimport { useParserOperations } from '../../hooks/useParserOperations';\nimport { AdvancedSection, AppearanceSection, DataBindingSection, GeneralSection } from '../builder/inspector';\nimport { getWidgetBinding, getWidgetBindingStatus, serializeWidgetBinding } from '../../utils/widgetBinding';\n\n// ============================================================================\n// v2.0: Renderer Options\n// ============================================================================\n\nconst RENDERER_OPTIONS: { value: RendererType; label: string; description: string }[] = [\n { value: 'BIGCONSOLE', label: 'BigConsole Native', description: 'Full-featured native widgets' },\n { value: 'ADAPTIVE_CARD', label: 'Adaptive Cards', description: 'Microsoft Teams/Outlook format' },\n { value: 'BLOCKKIT', label: 'Block Kit', description: 'Slack format' },\n { value: 'CUSTOM', label: 'Custom', description: 'Custom React component' },\n];\n\n// ============================================================================\n// Data Source Constants\n// ============================================================================\n\nconst DATA_SOURCE_TYPES: { value: DataSourceType; label: string; description: string }[] = [\n { value: 'DATASINK', label: 'DataSink', description: 'Use data from BigConsole DataSinks' },\n { value: 'REST_API', label: 'REST API', description: 'Fetch data from REST endpoints' },\n { value: 'GRAPHQL', label: 'GraphQL', description: 'Query data using GraphQL' },\n { value: 'SQL', label: 'SQL Database', description: 'Query SQL databases directly' },\n { value: 'WEBSOCKET', label: 'WebSocket', description: 'Real-time data streaming' },\n { value: 'MOCK', label: 'Sample JSON', description: 'Manually enter sample JSON data' },\n];\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface PropertiesPanelProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\ntype TabId = 'general' | 'data' | 'appearance' | 'advanced';\n\n// Action style colors\nconst ACTION_STYLE_COLORS: Record<string, string> = {\n PRIMARY: 'bg-action-primary',\n SECONDARY: 'bg-muted-foreground',\n SUCCESS: 'bg-state-success',\n WARNING: 'bg-state-warning',\n DANGER: 'bg-state-error',\n};\n\n// ============================================================================\n// Config Component Map\n// ============================================================================\n\n/**\n * Detects field names from parser output and returns suggested labelField and valueField\n * @param output - The parser execution output\n * @returns Object with suggested labelField and valueField\n */\nfunction detectFieldsFromParserOutput(output: unknown): {\n labelField?: string;\n valueField?: string;\n xAxisField?: string;\n} {\n if (!output) return {};\n\n // If output is an array, look at the first item\n const sampleItem = Array.isArray(output) ? output[0] : output;\n\n if (!sampleItem || typeof sampleItem !== 'object') return {};\n\n const keys = Object.keys(sampleItem as Record<string, unknown>);\n\n // Common label field names (in order of priority)\n const labelFieldCandidates = [\n 'name',\n 'label',\n 'category',\n 'title',\n 'key',\n 'id',\n 'month',\n 'date',\n 'region',\n 'product',\n ];\n // Common value field names (in order of priority)\n const valueFieldCandidates = ['value', 'amount', 'count', 'total', 'revenue', 'sales', 'quantity', 'orders', 'sum'];\n\n let labelField: string | undefined;\n let valueField: string | undefined;\n\n // Find the best label field\n for (const candidate of labelFieldCandidates) {\n if (keys.includes(candidate)) {\n labelField = candidate;\n break;\n }\n }\n\n // Find the best value field\n for (const candidate of valueFieldCandidates) {\n if (keys.includes(candidate)) {\n valueField = candidate;\n break;\n }\n }\n\n // If no standard names found, use heuristics:\n // - First string field as label\n // - First number field as value\n if (!labelField || !valueField) {\n for (const key of keys) {\n const val = (sampleItem as Record<string, unknown>)[key];\n if (!labelField && typeof val === 'string') {\n labelField = key;\n }\n if (!valueField && typeof val === 'number') {\n valueField = key;\n }\n if (labelField && valueField) break;\n }\n }\n\n return {\n labelField,\n valueField,\n xAxisField: labelField, // For line/bar charts, xAxisField is usually the same as labelField\n };\n}\n\n// ============================================================================\n// Template Editor Component\n// ============================================================================\n\ninterface TemplateEditorProps {\n widget: Widget;\n onSave: (template: Record<string, unknown>) => void;\n}\n\nconst TemplateEditor: FC<TemplateEditorProps> = memo(function TemplateEditor({ widget, onSave }) {\n const [localValue, setLocalValue] = useState<string>('');\n const [jsonError, setJsonError] = useState<string | null>(null);\n const initializedRef = useRef(false);\n\n // Initialize from widget.template only once per widget\n useEffect(() => {\n try {\n const templateStr =\n widget.template && typeof widget.template === 'object' ? JSON.stringify(widget.template, null, 2) : '';\n setLocalValue(templateStr);\n setJsonError(null);\n initializedRef.current = true;\n } catch {\n setLocalValue('');\n }\n }, [widget.id, widget.template]);\n\n const handleChange = useCallback(\n (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n const value = e.target.value;\n setLocalValue(value);\n\n if (value.trim() === '') {\n setJsonError(null);\n // Empty template is valid - notify parent\n onSave({});\n } else {\n try {\n const parsed = JSON.parse(value);\n setJsonError(null);\n // Valid JSON - immediately notify parent so main Save button becomes active\n onSave(parsed);\n } catch (err) {\n setJsonError((err as Error).message);\n // Don't call onSave for invalid JSON\n }\n }\n },\n [onSave]\n );\n\n const handleFormat = useCallback(() => {\n try {\n const parsed = JSON.parse(localValue);\n const formatted = JSON.stringify(parsed, null, 2);\n setLocalValue(formatted);\n setJsonError(null);\n onSave(parsed);\n } catch (err) {\n setJsonError((err as Error).message);\n }\n }, [localValue, onSave]);\n\n return (\n <div\n style={{\n paddingTop: 'var(--space-formGap)',\n borderTop: '1px solid var(--color-border)',\n }}\n >\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n <label\n style={{\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n }}\n >\n Template (JSON)\n </label>\n {jsonError && (\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-status-error-text)',\n fontWeight: 'var(--font-weight-medium)',\n }}\n >\n Invalid JSON\n </span>\n )}\n </div>\n\n <Textarea\n value={localValue}\n onChange={handleChange}\n spellCheck={false}\n placeholder={`Enter ${widget.renderer} template JSON...`}\n style={{\n fontFamily: 'var(--font-family-mono)',\n fontSize: 'var(--font-size-body-sm)',\n minHeight: '180px',\n borderColor: jsonError ? 'var(--color-status-error-border)' : undefined,\n resize: 'vertical',\n }}\n />\n\n {jsonError && (\n <p\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-status-error-text)',\n backgroundColor: 'var(--color-status-error-bgSubtle)',\n padding: 'var(--space-controlGap)',\n borderRadius: 'var(--radius-button)',\n marginTop: 'var(--space-controlGap)',\n }}\n >\n {jsonError}\n </p>\n )}\n\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n marginTop: 'var(--space-controlGap)',\n }}\n >\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleFormat}\n disabled={!!jsonError || localValue.trim() === ''}\n style={{ height: 'var(--size-controlHeight-sm)', fontWeight: 'var(--font-weight-semibold)' }}\n >\n Format\n </Button>\n {!jsonError && localValue.trim() !== '' && (\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-status-success-text)',\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n }}\n >\n <Check style={{ width: '12px', height: '12px' }} />\n Valid JSON\n </span>\n )}\n </div>\n\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-muted)',\n marginTop: 'var(--space-controlGap)',\n paddingTop: 'var(--space-controlGap)',\n borderTop: '1px solid var(--color-border)',\n }}\n >\n <span style={{ fontWeight: 'var(--font-weight-medium)' }}>Ctrl+S to save</span>\n {widget.renderer === 'ADAPTIVE_CARD' && (\n <a\n href=\"https://adaptivecards.io/designer/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n color: 'var(--color-text-link)',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n textDecoration: 'none',\n }}\n >\n Designer\n <ExternalLink style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n </a>\n )}\n {widget.renderer === 'BLOCKKIT' && (\n <a\n href=\"https://app.slack.com/block-kit-builder\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n color: 'var(--color-text-link)',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n textDecoration: 'none',\n }}\n >\n Block Kit Builder\n <ExternalLink style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n </a>\n )}\n </div>\n </div>\n );\n});\n\n// ============================================================================\n// Local Form State Type\n// ============================================================================\n\ninterface LocalFormState {\n title: string;\n description: string;\n refreshInterval: number | undefined;\n renderer: RendererType;\n template: Record<string, unknown> | undefined;\n // v2.0: Data source fields (DataSink → Parser → Widget)\n dataSinkId: string | undefined;\n datasetId: string | undefined;\n parserId: string | undefined;\n parserRules: string | undefined;\n config: Record<string, unknown>;\n // Drilldown configuration\n drilldownConfig: DrilldownConfig | undefined;\n}\n\nfunction createLocalFormStateFromWidget(widget: Widget): LocalFormState {\n const widgetFields = widget as unknown as Record<string, string | undefined>;\n const binding = getWidgetBinding({\n dataSinkId: widgetFields.dataSinkId,\n parserId: widgetFields.parserId,\n config: (widget.config as Record<string, unknown>) || {},\n });\n\n return {\n title: widget.title || '',\n description: widget.description || '',\n refreshInterval: widget.refreshInterval ?? undefined,\n renderer: (widget.renderer as RendererType) || 'BIGCONSOLE',\n template: widget.template as Record<string, unknown> | undefined,\n // v2.0: Data source fields (DataSink → Parser → Widget)\n dataSinkId: binding.source.kind === 'DATASINK' ? binding.source.ref : undefined,\n datasetId: widgetFields.datasetId ?? undefined,\n parserId: binding.parserId,\n parserRules: widgetFields.parserRules ?? undefined,\n config: (widget.config as Record<string, unknown>) || {},\n // Drilldown configuration\n drilldownConfig: widget.drilldown\n ? {\n enabled: widget.drilldown.enabled ?? false,\n targetDashboardId: widget.drilldown.targetDashboardId ?? '',\n navigationMode: widget.drilldown.navigationMode ?? 'MODAL',\n parameterMapping: (widget.drilldown.parameterMapping as Record<string, string>) ?? {},\n passGlobalFilters: widget.drilldown.passGlobalFilters ?? true,\n maxDepth: widget.drilldown.maxDepth ?? 3,\n openIn: widget.drilldown.openIn ?? 'same',\n }\n : undefined,\n };\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const PropertiesPanel: FC<PropertiesPanelProps> = memo(function PropertiesPanel({ isOpen, onClose }) {\n const [activeTab, setActiveTab] = useState<TabId>('general');\n const [saveStatus, setSaveStatus] = useState<'idle' | 'saving' | 'saved' | 'error'>('idle');\n const [localForm, setLocalForm] = useState<LocalFormState | null>(null);\n const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);\n\n const selectedWidgetId = useWidgetStore((state) => state.selectedWidgetId);\n const widgets = useWidgetStore((state) => state.widgets);\n const updateWidgetInStore = useWidgetStore((state) => state.updateWidget);\n\n const selectedWidget = selectedWidgetId ? widgets.get(selectedWidgetId) : undefined;\n const previousSelectedWidgetIdRef = useRef<string | null>(null);\n\n useEffect(() => {\n if (!selectedWidgetId) {\n previousSelectedWidgetIdRef.current = null;\n setLocalForm(null);\n setHasUnsavedChanges(false);\n setSaveStatus('idle');\n return;\n }\n\n const widgetSwitched = previousSelectedWidgetIdRef.current !== selectedWidgetId;\n previousSelectedWidgetIdRef.current = selectedWidgetId;\n\n if (selectedWidget) {\n if (hasUnsavedChanges && !widgetSwitched) return;\n\n setLocalForm(createLocalFormStateFromWidget(selectedWidget));\n setHasUnsavedChanges(false);\n setSaveStatus('idle');\n } else {\n setLocalForm(null);\n setHasUnsavedChanges(false);\n setSaveStatus('idle');\n }\n }, [selectedWidgetId, selectedWidget, hasUnsavedChanges]);\n\n const { updateWidget: updateWidgetApi } = useWidgetOperations(selectedWidget?.pageId, selectedWidget?.dashboardId, {\n skipFetch: true,\n });\n\n // Drilldown operations\n const { createDrilldown, updateDrilldown, deleteDrilldown } = useDrilldownOperations();\n\n // DataSink operations - for looking up DataSink by key\n const { dataSinks } = useDataSinkOperations({ skipFetch: false });\n\n // Track selected DataSink key for filtering parsers\n const [selectedDataSinkKey, setSelectedDataSinkKey] = useState<string | null>(null);\n\n // Parser operations - for executing parser to detect fields\n const { executeParser } = useParserOperations({\n consoleId: selectedWidget?.dashboardId,\n skipFetch: true,\n });\n\n // Track if we're auto-detecting fields\n const [isDetectingFields, setIsDetectingFields] = useState(false);\n const [bindingPreview, setBindingPreview] = useState<unknown>(undefined);\n const [bindingPreviewComplete, setBindingPreviewComplete] = useState(false);\n const [bindingPreviewError, setBindingPreviewError] = useState<string | null>(null);\n\n useEffect(() => {\n setBindingPreview(undefined);\n setBindingPreviewComplete(false);\n setBindingPreviewError(null);\n setIsDetectingFields(false);\n }, [selectedWidgetId]);\n\n const {\n actions,\n loading: actionsLoading,\n createAction,\n updateAction,\n deleteAction,\n reorderActions,\n } = useWidgetActions(selectedWidgetId || undefined);\n\n const [isActionDialogOpen, setIsActionDialogOpen] = useState(false);\n const [editingAction, setEditingAction] = useState<WidgetAction | undefined>(undefined);\n const [actionSaving, setActionSaving] = useState(false);\n\n const handleAddAction = useCallback(() => {\n setEditingAction(undefined);\n setIsActionDialogOpen(true);\n }, []);\n\n const handleEditAction = useCallback((action: WidgetAction) => {\n setEditingAction(action);\n setIsActionDialogOpen(true);\n }, []);\n\n const handleSaveAction = useCallback(\n async (data: Omit<CreateWidgetActionInput, 'widgetId'> | UpdateWidgetActionInput) => {\n if (!selectedWidgetId) return;\n\n setActionSaving(true);\n try {\n let newAction: WidgetAction | null = null;\n if ('id' in data) {\n newAction = await updateAction(data);\n } else {\n newAction = await createAction(data);\n }\n\n // Immediately sync to widget store after successful save\n // This ensures the widget displays the action right away\n if (newAction) {\n const currentActions = [...actions];\n if ('id' in data) {\n // Update existing action\n const idx = currentActions.findIndex((a) => a.id === data.id);\n if (idx >= 0) {\n currentActions[idx] = newAction;\n }\n } else {\n // Add new action\n currentActions.push(newAction);\n }\n // Sort by order and update store\n const sortedActions = currentActions.sort((a, b) => a.order - b.order);\n updateWidgetInStore(selectedWidgetId, { actions: sortedActions });\n }\n\n setIsActionDialogOpen(false);\n setEditingAction(undefined);\n } catch (err) {\n } finally {\n setActionSaving(false);\n }\n },\n [selectedWidgetId, actions, createAction, updateAction, updateWidgetInStore]\n );\n\n const handleDeleteAction = useCallback(\n async (actionId: string) => {\n if (!selectedWidgetId) return;\n\n if (window.confirm('Are you sure you want to delete this action?')) {\n const success = await deleteAction(actionId);\n if (success) {\n // Immediately sync to widget store after deletion\n const updatedActions = actions.filter((a) => a.id !== actionId);\n updateWidgetInStore(selectedWidgetId, { actions: updatedActions });\n }\n }\n },\n [selectedWidgetId, actions, deleteAction, updateWidgetInStore]\n );\n\n const handleMoveActionUp = useCallback(\n async (index: number) => {\n if (!selectedWidgetId || index === 0) return;\n const sortedActions = [...actions].sort((a, b) => a.order - b.order);\n const newOrder = sortedActions.map((a) => a.id);\n [newOrder[index - 1], newOrder[index]] = [newOrder[index], newOrder[index - 1]];\n const success = await reorderActions(newOrder);\n if (success) {\n // Immediately update local order for UI responsiveness\n const reordered = sortedActions\n .map((a, _i) => ({\n ...a,\n order: newOrder.indexOf(a.id),\n }))\n .sort((a, b) => a.order - b.order);\n updateWidgetInStore(selectedWidgetId, { actions: reordered });\n }\n },\n [selectedWidgetId, actions, reorderActions, updateWidgetInStore]\n );\n\n const handleMoveActionDown = useCallback(\n async (index: number) => {\n if (!selectedWidgetId) return;\n const sortedActions = [...actions].sort((a, b) => a.order - b.order);\n if (index === sortedActions.length - 1) return;\n const newOrder = sortedActions.map((a) => a.id);\n [newOrder[index], newOrder[index + 1]] = [newOrder[index + 1], newOrder[index]];\n const success = await reorderActions(newOrder);\n if (success) {\n // Immediately update local order for UI responsiveness\n const reordered = sortedActions\n .map((a, _i) => ({\n ...a,\n order: newOrder.indexOf(a.id),\n }))\n .sort((a, b) => a.order - b.order);\n updateWidgetInStore(selectedWidgetId, { actions: reordered });\n }\n },\n [selectedWidgetId, actions, reorderActions, updateWidgetInStore]\n );\n\n useEffect(() => {\n if (selectedWidgetId && actions.length >= 0 && !actionsLoading) {\n updateWidgetInStore(selectedWidgetId, { actions });\n }\n }, [selectedWidgetId, actions, actionsLoading, updateWidgetInStore]);\n\n const updateLocalForm = useCallback(<K extends keyof LocalFormState>(key: K, value: LocalFormState[K]) => {\n setLocalForm((prev) => (prev ? { ...prev, [key]: value } : prev));\n setHasUnsavedChanges(true);\n }, []);\n\n const updateLocalConfig = useCallback((newConfig: Record<string, unknown>) => {\n setLocalForm((prev) => (prev ? { ...prev, config: newConfig } : prev));\n setHasUnsavedChanges(true);\n }, []);\n\n // Initialize selectedDataSinkKey from widget's dataSinkId\n useEffect(() => {\n if (localForm?.dataSinkId && dataSinks.length > 0) {\n const ds = dataSinks.find((d) => d.id === localForm.dataSinkId);\n if (ds) {\n setSelectedDataSinkKey(ds.key);\n }\n } else {\n setSelectedDataSinkKey(null);\n }\n }, [localForm?.dataSinkId, dataSinks]);\n\n // Handle DataSink selection - looks up ID from key and updates form\n const handleDataSinkChange = useCallback(\n (key: string | null) => {\n setBindingPreview(undefined);\n setBindingPreviewComplete(false);\n setBindingPreviewError(null);\n setSelectedDataSinkKey(key);\n if (key) {\n const ds = dataSinks.find((d) => d.key === key);\n if (ds) {\n updateLocalForm('dataSinkId', ds.id);\n // Also update config.dataSinkKey for backward compatibility\n setLocalForm((prev) =>\n prev\n ? {\n ...prev,\n config: { ...prev.config, dataSinkKey: key },\n }\n : prev\n );\n setHasUnsavedChanges(true);\n }\n } else {\n updateLocalForm('dataSinkId', undefined);\n setLocalForm((prev) =>\n prev\n ? {\n ...prev,\n config: { ...prev.config, dataSinkKey: undefined },\n parserId: undefined, // Clear parser when DataSink is cleared\n }\n : prev\n );\n setHasUnsavedChanges(true);\n }\n },\n [dataSinks, updateLocalForm]\n );\n\n // Handle Parser selection - with auto-detection of field mappings\n const handleParserChange = useCallback(\n async (parserId: string | null) => {\n updateLocalForm('parserId', parserId || undefined);\n setBindingPreview(undefined);\n setBindingPreviewComplete(false);\n setBindingPreviewError(null);\n\n // If a parser is selected, execute it to detect field structure\n if (parserId && selectedWidget) {\n setIsDetectingFields(true);\n try {\n const result = await executeParser(parserId);\n\n if (result?.success) {\n setBindingPreview(result.output);\n setBindingPreviewComplete(true);\n const detectedFields = detectFieldsFromParserOutput(result.output);\n\n // Only auto-populate if fields were detected and not already set\n if (detectedFields.labelField || detectedFields.valueField) {\n setLocalForm((prev) => {\n if (!prev) return prev;\n\n const currentConfig = prev.config || {};\n const newConfig = { ...currentConfig };\n\n // Auto-populate labelField if not already set\n if (detectedFields.labelField && !currentConfig.labelField) {\n newConfig.labelField = detectedFields.labelField;\n }\n\n // Auto-populate valueField if not already set\n if (detectedFields.valueField && !currentConfig.valueField) {\n newConfig.valueField = detectedFields.valueField;\n }\n\n // Auto-populate xAxisField for line/bar/area charts if not already set\n if (detectedFields.xAxisField && !currentConfig.xAxisField) {\n newConfig.xAxisField = detectedFields.xAxisField;\n }\n\n return { ...prev, config: newConfig };\n });\n setHasUnsavedChanges(true);\n }\n } else {\n setBindingPreviewComplete(true);\n setBindingPreviewError(result?.error || 'The parser could not produce a preview.');\n }\n } catch (err) {\n setBindingPreviewComplete(true);\n setBindingPreviewError(err instanceof Error ? err.message : 'The parser could not produce a preview.');\n console.warn('Failed to auto-detect parser fields:', err);\n } finally {\n setIsDetectingFields(false);\n }\n }\n },\n [updateLocalForm, executeParser, selectedWidget]\n );\n\n const handleSaveAll = useCallback(async () => {\n if (!selectedWidget || !localForm) return;\n\n setSaveStatus('saving');\n\n try {\n const metadata = { ...(selectedWidget.metadata || {}), description: localForm.description || '' };\n const bindingDraft = getWidgetBinding({\n dataSinkId: localForm.dataSinkId,\n parserId: localForm.parserId,\n config: { ...localForm.config, binding: undefined },\n });\n const bindingWrite = serializeWidgetBinding(bindingDraft, localForm.config);\n\n const result = await updateWidgetApi({\n id: selectedWidget.id,\n title: localForm.title,\n renderer: localForm.renderer,\n template: localForm.template,\n config: bindingWrite.config,\n refreshInterval: localForm.refreshInterval,\n // v2.0: Data source fields (DataSink → Parser → Widget)\n dataSinkId: bindingWrite.dataSinkId,\n datasetId: localForm.datasetId,\n parserId: bindingWrite.parserId,\n parserRules: localForm.parserRules,\n metadata,\n });\n\n // Save drilldown configuration to backend\n let savedDrilldown = selectedWidget.drilldown;\n if (localForm.drilldownConfig) {\n const { enabled, targetDashboardId, navigationMode, parameterMapping, passGlobalFilters, maxDepth, openIn } =\n localForm.drilldownConfig;\n\n if (selectedWidget.drilldown?.id) {\n // Update existing drilldown\n const drilldownResult = await updateDrilldown({\n id: selectedWidget.drilldown.id,\n targetDashboardId,\n parameterMapping,\n navigationMode,\n enabled,\n passGlobalFilters,\n maxDepth,\n openIn,\n });\n if (drilldownResult) {\n savedDrilldown = drilldownResult;\n }\n } else if (targetDashboardId) {\n // Create new drilldown (only if targetDashboardId is set)\n const drilldownResult = await createDrilldown({\n sourceWidgetId: selectedWidget.id,\n targetDashboardId,\n parameterMapping: parameterMapping || {},\n navigationMode,\n passGlobalFilters,\n maxDepth,\n openIn,\n });\n if (drilldownResult) {\n savedDrilldown = { ...drilldownResult, enabled };\n }\n }\n } else if (selectedWidget.drilldown?.id && !localForm.drilldownConfig) {\n // Delete drilldown if it existed but was removed\n await deleteDrilldown(selectedWidget.drilldown.id);\n savedDrilldown = undefined;\n }\n\n if (result) {\n updateWidgetInStore(selectedWidget.id, {\n title: localForm.title,\n description: localForm.description,\n renderer: localForm.renderer,\n template: localForm.template,\n config: bindingWrite.config,\n refreshInterval: localForm.refreshInterval,\n // v2.0: Data source fields\n dataSinkId: bindingWrite.dataSinkId,\n datasetId: localForm.datasetId,\n parserId: bindingWrite.parserId,\n parserRules: localForm.parserRules,\n // Drilldown configuration from backend\n drilldown: savedDrilldown,\n // Update timestamp to trigger WidgetWrapper re-render (fixes drilldown mode change bug)\n updatedAt: new Date().toISOString(),\n } as Partial<Widget>);\n\n setSaveStatus('saved');\n setHasUnsavedChanges(false);\n setTimeout(() => setSaveStatus('idle'), 2000);\n } else {\n setSaveStatus('error');\n }\n } catch (err) {\n setSaveStatus('error');\n }\n }, [\n selectedWidget,\n localForm,\n updateWidgetApi,\n updateWidgetInStore,\n createDrilldown,\n updateDrilldown,\n deleteDrilldown,\n ]);\n\n const handleDiscardAll = useCallback(() => {\n if (!selectedWidget) return;\n\n setLocalForm(createLocalFormStateFromWidget(selectedWidget));\n setHasUnsavedChanges(false);\n setSaveStatus('idle');\n }, [selectedWidget]);\n\n const handleConfigChange = useCallback(\n (newConfig: Record<string, unknown>) => {\n updateLocalConfig(newConfig);\n },\n [updateLocalConfig]\n );\n\n const handleDrilldownChange = useCallback((config: DrilldownConfig) => {\n setLocalForm((prev) => (prev ? { ...prev, drilldownConfig: config } : prev));\n setHasUnsavedChanges(true);\n }, []);\n\n const definition = selectedWidget ? getWidgetDefinition(selectedWidget.type) : null;\n\n return (\n <Sheet open={isOpen} onOpenChange={(open) => !open && onClose()} modal={false}>\n <SheetContent\n style={{\n width: '420px',\n maxWidth: '90vw',\n padding: 0,\n display: 'flex',\n flexDirection: 'column',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n <SheetHeader\n style={{\n padding: 'var(--space-cardPadding)',\n borderBottom: '1px solid var(--color-border)',\n backgroundColor: 'var(--color-bg-surface)',\n flexShrink: 0,\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-controlGap)' }}>\n <div\n style={{\n display: 'flex',\n height: 'var(--size-controlHeight-lg)',\n width: 'var(--size-controlHeight-lg)',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 'var(--radius-card)',\n backgroundColor: 'var(--color-action-primary-bg)',\n boxShadow: 'var(--shadow-elevation-2)',\n flexShrink: 0,\n }}\n >\n <Info\n style={{\n height: 'var(--size-icon-md)',\n width: 'var(--size-icon-md)',\n color: 'var(--color-action-primary-text)',\n }}\n />\n </div>\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <SheetTitle\n style={{\n fontSize: 'var(--font-size-body-md)',\n fontWeight: 'var(--font-weight-bold)',\n color: 'var(--color-text-primary)',\n margin: 0,\n }}\n >\n {selectedWidget ? 'Widget Properties' : 'Properties'}\n </SheetTitle>\n {saveStatus === 'saving' && (\n <Spinner style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n )}\n {saveStatus === 'saved' && (\n <Check\n style={{\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n color: 'var(--color-status-success-bg)',\n }}\n />\n )}\n {saveStatus === 'error' && (\n <X\n style={{\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n color: 'var(--color-status-error-bg)',\n }}\n />\n )}\n </div>\n {definition && (\n <SheetDescription\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-secondary)',\n margin: 'var(--space-controlGap) 0 0 0',\n fontWeight: 'var(--font-weight-medium)',\n }}\n >\n {definition.name}\n </SheetDescription>\n )}\n </div>\n </div>\n </SheetHeader>\n\n {selectedWidget ? (\n <Tabs\n value={activeTab}\n onValueChange={(v) => setActiveTab(v as TabId)}\n style={{ flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0, overflow: 'hidden' }}\n >\n <TabsList\n style={{\n width: '100%',\n display: 'flex',\n justifyContent: 'flex-start',\n borderRadius: 0,\n borderBottom: '1px solid var(--color-border)',\n padding: '0 8px',\n backgroundColor: 'var(--color-bg-sunken)',\n height: 'var(--size-controlHeight-lg)',\n flexShrink: 0,\n gap: '2px',\n overflowX: 'auto',\n }}\n >\n <TabsTrigger\n value=\"general\"\n style={{\n fontWeight: 'var(--font-weight-semibold)',\n fontSize: '12px',\n padding: '6px 8px',\n flexShrink: 0,\n }}\n >\n General\n </TabsTrigger>\n <TabsTrigger\n value=\"data\"\n style={{\n fontWeight: 'var(--font-weight-semibold)',\n fontSize: '12px',\n padding: '6px 8px',\n flexShrink: 0,\n }}\n >\n Data\n </TabsTrigger>\n <TabsTrigger\n value=\"advanced\"\n style={{\n fontWeight: 'var(--font-weight-semibold)',\n fontSize: '12px',\n padding: '6px 8px',\n flexShrink: 0,\n }}\n >\n Advanced\n </TabsTrigger>\n <TabsTrigger\n value=\"appearance\"\n style={{\n fontWeight: 'var(--font-weight-semibold)',\n fontSize: '12px',\n padding: '6px 8px',\n flexShrink: 0,\n }}\n >\n Style\n </TabsTrigger>\n </TabsList>\n\n <div style={{ flex: 1, overflow: 'auto', padding: 'var(--space-cardPadding)', minHeight: 0 }}>\n <TabsContent value=\"general\" className=\"mt-0\">\n {localForm && (\n <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-formGap)' }}>\n <GeneralSection\n title={localForm.title}\n description={localForm.description}\n refreshInterval={localForm.refreshInterval}\n onTitleChange={(title) => updateLocalForm('title', title)}\n onDescriptionChange={(description) => updateLocalForm('description', description)}\n onRefreshIntervalChange={(refreshInterval) => updateLocalForm('refreshInterval', refreshInterval)}\n />\n </div>\n )}\n </TabsContent>\n\n <TabsContent value=\"data\" className=\"mt-0 space-y-4\">\n {localForm && (\n <>\n {(() => {\n const binding = getWidgetBinding({\n dataSinkId: localForm.dataSinkId,\n parserId: localForm.parserId,\n config: { ...localForm.config, binding: undefined },\n });\n const validation = getWidgetBindingStatus({\n binding,\n loading: isDetectingFields,\n error: bindingPreviewError,\n preview: bindingPreview,\n previewComplete: bindingPreviewComplete,\n });\n\n return (\n <DataBindingSection\n consoleId={selectedWidget?.dashboardId || ''}\n binding={binding}\n dataSinkKey={selectedDataSinkKey}\n dataPath={\n typeof localForm.config.dataPath === 'string' ? localForm.config.dataPath : undefined\n }\n status={validation.status}\n missingFields={validation.missingFields}\n preview={bindingPreview}\n error={bindingPreviewError}\n onDataSinkChange={handleDataSinkChange}\n onParserChange={handleParserChange}\n onDataPathChange={(dataPath) => updateLocalConfig({ ...localForm.config, dataPath })}\n />\n );\n })()}\n\n {/* Divider */}\n <div className=\"border-t border-border-subtle pt-4\">\n <Label className=\"text-xs text-text-secondary uppercase tracking-wide\">\n Alternative Data Sources\n </Label>\n </div>\n\n {/* Data Source Type Selector */}\n <div className=\"space-y-2\">\n <Label>Data Source Type</Label>\n <Select\n value={(localForm.config?.dataSourceType as string) || ''}\n onValueChange={(value) =>\n updateLocalConfig({ ...localForm.config, dataSourceType: value || undefined })\n }\n >\n <SelectTrigger\n style={{ height: 'var(--size-controlHeight-md)', fontSize: 'var(--font-size-body-sm)' }}\n >\n <SelectValue placeholder=\"Select type...\" />\n </SelectTrigger>\n <SelectContent\n position=\"popper\"\n side=\"bottom\"\n sideOffset={4}\n align=\"start\"\n style={{\n zIndex: 9999,\n maxHeight: '200px',\n backgroundColor: 'var(--color-overlay-popoverBg, var(--color-bg-surface, #ffffff))',\n border: '1px solid var(--color-border)',\n boxShadow: 'var(--shadow-elevation-3)',\n borderRadius: 'var(--radius-button)',\n }}\n >\n {DATA_SOURCE_TYPES.map((type) => (\n <SelectItem key={type.value} value={type.value}>\n {type.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {localForm.config?.dataSourceType === 'REST_API' && (\n <div className=\"space-y-3\">\n {/* Endpoint URL */}\n <div className=\"space-y-2\">\n <Label>Endpoint URL *</Label>\n <Input\n value={(localForm.config?.endpointUrl as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, endpointUrl: e.target.value || undefined })\n }\n placeholder=\"https://api.example.com/data\"\n />\n </div>\n\n {/* HTTP Method */}\n <div className=\"space-y-2\">\n <Label>HTTP Method</Label>\n <Select\n value={(localForm.config?.httpMethod as string) || 'GET'}\n onValueChange={(value) => updateLocalConfig({ ...localForm.config, httpMethod: value })}\n >\n <SelectTrigger style={{ height: 'var(--size-controlHeight-md)' }}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent position=\"popper\" side=\"bottom\" sideOffset={4}>\n <SelectItem value=\"GET\">GET</SelectItem>\n <SelectItem value=\"POST\">POST</SelectItem>\n <SelectItem value=\"PUT\">PUT</SelectItem>\n <SelectItem value=\"DELETE\">DELETE</SelectItem>\n </SelectContent>\n </Select>\n </div>\n\n {/* Headers */}\n <div className=\"space-y-2\">\n <Label>Headers (JSON)</Label>\n <Textarea\n value={(localForm.config?.headers as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, headers: e.target.value || undefined })\n }\n rows={3}\n placeholder='{\"Authorization\": \"Bearer token\", \"Content-Type\": \"application/json\"}'\n className=\"font-mono text-xs\"\n />\n </div>\n\n {/* Authentication Type */}\n <div className=\"space-y-2\">\n <Label>Authentication</Label>\n <Select\n value={(localForm.config?.authType as string) || 'none'}\n onValueChange={(value) => updateLocalConfig({ ...localForm.config, authType: value })}\n >\n <SelectTrigger style={{ height: 'var(--size-controlHeight-md)' }}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent position=\"popper\" side=\"bottom\" sideOffset={4}>\n <SelectItem value=\"none\">None</SelectItem>\n <SelectItem value=\"api_key\">API Key</SelectItem>\n <SelectItem value=\"bearer\">Bearer Token</SelectItem>\n <SelectItem value=\"basic\">Basic Auth</SelectItem>\n </SelectContent>\n </Select>\n </div>\n\n {/* Auth Value (conditional) */}\n {!!(localForm.config?.authType && localForm.config.authType !== 'none') && (\n <div className=\"space-y-2\">\n <Label>\n {String(localForm.config.authType) === 'basic' ? 'Credentials (user:pass)' : 'Token/Key'}\n </Label>\n <Input\n type=\"password\"\n value={(localForm.config?.authValue as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, authValue: e.target.value || undefined })\n }\n placeholder={\n localForm.config.authType === 'basic' ? 'username:password' : 'Enter token or API key'\n }\n />\n </div>\n )}\n\n {/* Request Body (for POST/PUT) */}\n {(localForm.config?.httpMethod === 'POST' || localForm.config?.httpMethod === 'PUT') && (\n <div className=\"space-y-2\">\n <Label>Request Body (JSON)</Label>\n <Textarea\n value={(localForm.config?.requestBody as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, requestBody: e.target.value || undefined })\n }\n rows={4}\n placeholder='{\"key\": \"value\"}'\n className=\"font-mono text-xs\"\n />\n </div>\n )}\n\n {/* Data Path */}\n <div className=\"space-y-2\">\n <Label>Data Path (optional)</Label>\n <Input\n value={(localForm.config?.dataPath as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, dataPath: e.target.value || undefined })\n }\n placeholder=\"$.data.items or .data.items\"\n />\n <p className=\"text-xs text-text-secondary\">\n JSONPath or dot notation to extract data from response\n </p>\n </div>\n </div>\n )}\n\n {localForm.config?.dataSourceType === 'GRAPHQL' && (\n <div className=\"space-y-3\">\n {/* GraphQL Endpoint */}\n <div className=\"space-y-2\">\n <Label>GraphQL Endpoint *</Label>\n <Input\n value={(localForm.config?.graphqlEndpoint as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, graphqlEndpoint: e.target.value || undefined })\n }\n placeholder=\"https://api.example.com/graphql\"\n />\n </div>\n\n {/* GraphQL Query */}\n <div className=\"space-y-2\">\n <Label>Query *</Label>\n <Textarea\n value={(localForm.config?.graphqlQuery as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, graphqlQuery: e.target.value || undefined })\n }\n rows={6}\n placeholder={`query GetData($limit: Int) {\n items(limit: $limit) {\n id\n name\n value\n }\n}`}\n className=\"font-mono text-xs\"\n />\n </div>\n\n {/* GraphQL Variables */}\n <div className=\"space-y-2\">\n <Label>Variables (JSON, optional)</Label>\n <Textarea\n value={(localForm.config?.graphqlVariables as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, graphqlVariables: e.target.value || undefined })\n }\n rows={3}\n placeholder='{\"limit\": 10, \"offset\": 0}'\n className=\"font-mono text-xs\"\n />\n </div>\n\n {/* Headers */}\n <div className=\"space-y-2\">\n <Label>Headers (JSON, optional)</Label>\n <Textarea\n value={(localForm.config?.headers as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, headers: e.target.value || undefined })\n }\n rows={2}\n placeholder='{\"Authorization\": \"Bearer token\"}'\n className=\"font-mono text-xs\"\n />\n </div>\n\n {/* Data Path */}\n <div className=\"space-y-2\">\n <Label>Data Path (optional)</Label>\n <Input\n value={(localForm.config?.dataPath as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, dataPath: e.target.value || undefined })\n }\n placeholder=\".data.items\"\n />\n <p className=\"text-xs text-text-secondary\">Path to extract data from GraphQL response</p>\n </div>\n </div>\n )}\n\n {localForm.config?.dataSourceType === 'MOCK' && (\n <div className=\"space-y-2\">\n <Label>Sample Data (JSON)</Label>\n <Textarea\n value={(localForm.config?.mockData as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, mockData: e.target.value || undefined })\n }\n rows={5}\n placeholder='{\"value\": 100}'\n className=\"font-mono text-sm\"\n />\n </div>\n )}\n </>\n )}\n </TabsContent>\n\n <TabsContent value=\"advanced\" className=\"mt-0 space-y-6\">\n {localForm && (\n <AdvancedSection\n renderer={localForm.renderer}\n rendererOptions={RENDERER_OPTIONS}\n onRendererChange={(renderer) => {\n updateLocalForm('renderer', renderer);\n if (renderer === 'BIGCONSOLE') updateLocalForm('template', undefined);\n }}\n templateEditor={\n localForm.renderer !== 'BIGCONSOLE' ? (\n <TemplateEditor\n widget={{ ...selectedWidget, template: localForm.template, renderer: localForm.renderer }}\n onSave={(template) => updateLocalForm('template', template)}\n />\n ) : undefined\n }\n />\n )}\n\n <section className=\"space-y-4 border-t border-border-default pt-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"text-sm font-medium\">Widget Actions</h3>\n <p className=\"text-xs text-text-secondary\">Configure buttons on this widget</p>\n </div>\n <Button size=\"sm\" onClick={handleAddAction}>\n <Plus className=\"size-4\" />\n Add\n </Button>\n </div>\n\n {actionsLoading ? (\n <div className=\"flex justify-center py-8\">\n <Spinner className=\"size-6\" />\n </div>\n ) : actions.length === 0 ? (\n <div className=\"py-8 text-center\">\n <Info className=\"size-10 mx-auto mb-2 text-text-secondary/50\" />\n <p className=\"text-sm text-text-secondary\">No actions configured</p>\n </div>\n ) : (\n <div className=\"space-y-2\">\n {[...actions]\n .sort((a, b) => a.order - b.order)\n .map((action, index) => (\n <Card key={action.id} className={action.disabled ? 'opacity-60' : ''}>\n <CardContent className=\"p-3 flex items-center gap-2\">\n <div className=\"flex flex-col gap-0.5\">\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n onClick={() => handleMoveActionUp(index)}\n disabled={index === 0}\n className=\"h-5 w-5\"\n >\n <ChevronUp className=\"size-3\" />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n onClick={() => handleMoveActionDown(index)}\n disabled={index === actions.length - 1}\n className=\"h-5 w-5\"\n >\n <ChevronDown className=\"size-3\" />\n </Button>\n </div>\n\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span\n className={`size-2 rounded-full ${ACTION_STYLE_COLORS[action.style] || 'bg-muted-foreground'}`}\n />\n <span className=\"text-sm font-medium truncate\">{action.label}</span>\n </div>\n <p className=\"text-xs text-text-secondary\">\n {action.name} • {action.type}\n </p>\n </div>\n\n <div className=\"flex gap-1\">\n <Button variant=\"ghost\" size=\"icon-sm\" onClick={() => handleEditAction(action)}>\n <Pencil className=\"size-4\" />\n </Button>\n <Button variant=\"ghost\" size=\"icon-sm\" onClick={() => handleDeleteAction(action.id)}>\n <Trash2 className=\"size-4\" />\n </Button>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n </section>\n\n <section className=\"space-y-3 border-t border-border-default pt-4\">\n <h3 className=\"text-sm font-semibold text-text-primary\">Drilldown</h3>\n <DrilldownConfigPanel widget={selectedWidget} onChange={handleDrilldownChange} />\n </section>\n\n <section className=\"space-y-3 border-t border-border-default pt-4\">\n <h3 className=\"text-sm font-semibold text-text-primary\">Webhooks</h3>\n <WebhookConfigPanel dashboardId={selectedWidget.dashboardId} widgetId={selectedWidget.id} />\n </section>\n\n <section className=\"space-y-3 border-t border-border-default pt-4\">\n <h3 className=\"text-sm font-semibold text-text-primary\">Events</h3>\n <EventLogViewer\n dashboardId={selectedWidget.dashboardId}\n widgetId={selectedWidget.id}\n maxHeight=\"calc(100vh - 350px)\"\n />\n </section>\n </TabsContent>\n\n <TabsContent value=\"appearance\" className=\"mt-0\">\n <AppearanceSection\n widgetType={selectedWidget.type}\n config={(selectedWidget.config as Record<string, unknown>) || {}}\n onChange={handleConfigChange}\n />\n </TabsContent>\n </div>\n </Tabs>\n ) : (\n <div className=\"flex-1 flex items-center justify-center p-4\">\n <div className=\"text-center\">\n <Info className=\"size-12 mx-auto mb-3 text-text-secondary\" />\n <p className=\"text-sm text-text-secondary\">Select a widget to edit</p>\n </div>\n </div>\n )}\n\n {/* Global Save/Discard Footer */}\n {selectedWidget && (\n <div\n style={{\n padding: 'var(--space-cardPadding)',\n borderTop: '1px solid var(--color-border)',\n backgroundColor: 'var(--color-bg-sunken)',\n flexShrink: 0,\n }}\n >\n {/* Status indicator */}\n {hasUnsavedChanges && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-iconGap)',\n marginBottom: 'var(--space-controlGap)',\n padding: 'var(--space-controlGap)',\n backgroundColor: 'var(--color-status-warning-bgSubtle, rgba(251, 191, 36, 0.1))',\n borderRadius: 'var(--radius-button)',\n border: '1px solid var(--color-status-warning-border, rgba(251, 191, 36, 0.3))',\n }}\n >\n <div\n style={{\n width: '8px',\n height: '8px',\n borderRadius: '50%',\n backgroundColor: 'var(--color-status-warning-bg)',\n flexShrink: 0,\n }}\n />\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-status-warning-text, #92400e)',\n fontWeight: 'var(--font-weight-medium)',\n }}\n >\n You have unsaved changes\n </span>\n </div>\n )}\n\n {saveStatus === 'saved' && !hasUnsavedChanges && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-iconGap)',\n marginBottom: 'var(--space-controlGap)',\n padding: 'var(--space-controlGap)',\n backgroundColor: 'var(--color-status-success-bgSubtle, rgba(34, 197, 94, 0.1))',\n borderRadius: 'var(--radius-button)',\n border: '1px solid var(--color-status-success-border, rgba(34, 197, 94, 0.3))',\n }}\n >\n <Check\n style={{\n width: 'var(--size-icon-sm)',\n height: 'var(--size-icon-sm)',\n color: 'var(--color-status-success-text)',\n flexShrink: 0,\n }}\n />\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-status-success-text)',\n fontWeight: 'var(--font-weight-medium)',\n }}\n >\n All changes saved\n </span>\n </div>\n )}\n\n {saveStatus === 'error' && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-iconGap)',\n marginBottom: 'var(--space-controlGap)',\n padding: 'var(--space-controlGap)',\n backgroundColor: 'var(--color-status-error-bgSubtle)',\n borderRadius: 'var(--radius-button)',\n border: '1px solid var(--color-status-error-border)',\n }}\n >\n <X\n style={{\n width: 'var(--size-icon-sm)',\n height: 'var(--size-icon-sm)',\n color: 'var(--color-status-error-text)',\n flexShrink: 0,\n }}\n />\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-status-error-text)',\n fontWeight: 'var(--font-weight-medium)',\n }}\n >\n Failed to save changes\n </span>\n </div>\n )}\n\n {/* Action buttons */}\n <div style={{ display: 'flex', gap: 'var(--space-controlGap)' }}>\n <Button\n onClick={handleSaveAll}\n disabled={saveStatus === 'saving' || !hasUnsavedChanges}\n style={{\n flex: 1,\n height: 'var(--size-controlHeight-md)',\n backgroundColor: hasUnsavedChanges ? 'var(--color-action-primary-bg)' : undefined,\n opacity: hasUnsavedChanges ? 1 : 0.5,\n }}\n >\n {saveStatus === 'saving' ? (\n <span style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <Spinner style={{ width: 'var(--size-icon-sm)', height: 'var(--size-icon-sm)' }} />\n Saving...\n </span>\n ) : (\n <span style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <Check style={{ width: 'var(--size-icon-sm)', height: 'var(--size-icon-sm)' }} />\n Save Changes\n </span>\n )}\n </Button>\n <Button\n variant=\"outline\"\n onClick={handleDiscardAll}\n disabled={saveStatus === 'saving' || !hasUnsavedChanges}\n style={{\n height: 'var(--size-controlHeight-md)',\n opacity: hasUnsavedChanges ? 1 : 0.5,\n }}\n >\n <X style={{ width: 'var(--size-icon-sm)', height: 'var(--size-icon-sm)' }} />\n Discard\n </Button>\n </div>\n </div>\n )}\n\n <ActionConfigDialog\n isOpen={isActionDialogOpen}\n action={editingAction}\n isLoading={actionSaving}\n onClose={() => {\n setIsActionDialogOpen(false);\n setEditingAction(undefined);\n }}\n onSave={handleSaveAction}\n />\n </SheetContent>\n </Sheet>\n );\n});\n\nexport default PropertiesPanel;\n"],"mappings":"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"}
1
+ {"version":3,"file":"PropertiesPanel.js","names":[],"sources":["../../../../src/bigconsole/components/widgets/PropertiesPanel.tsx"],"sourcesContent":["/**\n * PropertiesPanel Component\n *\n * Right-side panel for widget configuration.\n * v2.0: Added Actions tab for managing widget actions.\n * Uses fe-libs shared components for consistent styling.\n */\n\nimport React, { type FC, memo, useCallback, useState, useEffect, useRef } from 'react';\nimport { Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription } from '@burdenoff/fe-libs/ui';\nimport { Tabs, TabsList, TabsTrigger, TabsContent } from '@burdenoff/fe-libs/ui';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { Textarea } from '@burdenoff/fe-libs/ui';\nimport { Label } from '@burdenoff/fe-libs/ui';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@burdenoff/fe-libs/ui';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { Card, CardContent } from '@burdenoff/fe-libs/ui';\nimport { Plus, ChevronUp, ChevronDown, Pencil, Trash2, ExternalLink, Check, X, Info } from 'lucide-react';\nimport type { Widget, DataSourceType, RendererType } from '../../types';\nimport { useWidgetStore } from '../../store';\nimport { useWidgetOperations, useDrilldownOperations } from '../../hooks';\nimport {\n useWidgetActions,\n type WidgetAction,\n type CreateWidgetActionInput,\n type UpdateWidgetActionInput,\n} from '../../hooks/useWidgetActions';\nimport { getWidgetDefinition } from './WidgetRegistry';\nimport { ActionConfigDialog } from './ActionConfigDialog';\nimport { WebhookConfigPanel } from './webhook-config';\nimport { EventLogViewer } from './event-logs';\nimport { DrilldownConfigPanel, type DrilldownConfig } from './DrilldownConfigPanel';\n// Data Source selectors\nimport { useDataSinkOperations } from '../../hooks/useDataSinkOperations';\nimport { useParserOperations } from '../../hooks/useParserOperations';\nimport { AdvancedSection, AppearanceSection, DataBindingSection, GeneralSection } from '../builder/inspector';\nimport { getWidgetBinding, getWidgetBindingStatus, serializeWidgetBinding } from '../../utils/widgetBinding';\n\n// ============================================================================\n// v2.0: Renderer Options\n// ============================================================================\n\nconst RENDERER_OPTIONS: { value: RendererType; label: string; description: string }[] = [\n { value: 'BIGCONSOLE', label: 'BigConsole Native', description: 'Full-featured native widgets' },\n { value: 'ADAPTIVE_CARD', label: 'Adaptive Cards', description: 'Microsoft Teams/Outlook format' },\n { value: 'BLOCKKIT', label: 'Block Kit', description: 'Slack format' },\n { value: 'CUSTOM', label: 'Custom', description: 'Custom React component' },\n];\n\n// ============================================================================\n// Data Source Constants\n// ============================================================================\n\nconst DATA_SOURCE_TYPES: { value: DataSourceType; label: string; description: string }[] = [\n { value: 'DATASINK', label: 'DataSink', description: 'Use data from BigConsole DataSinks' },\n { value: 'REST_API', label: 'REST API', description: 'Fetch data from REST endpoints' },\n { value: 'GRAPHQL', label: 'GraphQL', description: 'Query data using GraphQL' },\n { value: 'SQL', label: 'SQL Database', description: 'Query SQL databases directly' },\n { value: 'WEBSOCKET', label: 'WebSocket', description: 'Real-time data streaming' },\n { value: 'MOCK', label: 'Sample JSON', description: 'Manually enter sample JSON data' },\n];\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface PropertiesPanelProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\ntype TabId = 'general' | 'data' | 'appearance' | 'advanced';\n\n// Action style colors\nconst ACTION_STYLE_COLORS: Record<string, string> = {\n PRIMARY: 'bg-action-primary',\n SECONDARY: 'bg-muted-foreground',\n SUCCESS: 'bg-state-success',\n WARNING: 'bg-state-warning',\n DANGER: 'bg-state-error',\n};\n\n// ============================================================================\n// Config Component Map\n// ============================================================================\n\n/**\n * Detects field names from parser output and returns suggested labelField and valueField\n * @param output - The parser execution output\n * @returns Object with suggested labelField and valueField\n */\nfunction detectFieldsFromParserOutput(output: unknown): {\n labelField?: string;\n valueField?: string;\n xAxisField?: string;\n} {\n if (!output) return {};\n\n // If output is an array, look at the first item\n const sampleItem = Array.isArray(output) ? output[0] : output;\n\n if (!sampleItem || typeof sampleItem !== 'object') return {};\n\n const keys = Object.keys(sampleItem as Record<string, unknown>);\n\n // Common label field names (in order of priority)\n const labelFieldCandidates = [\n 'name',\n 'label',\n 'category',\n 'title',\n 'key',\n 'id',\n 'month',\n 'date',\n 'region',\n 'product',\n ];\n // Common value field names (in order of priority)\n const valueFieldCandidates = ['value', 'amount', 'count', 'total', 'revenue', 'sales', 'quantity', 'orders', 'sum'];\n\n let labelField: string | undefined;\n let valueField: string | undefined;\n\n // Find the best label field\n for (const candidate of labelFieldCandidates) {\n if (keys.includes(candidate)) {\n labelField = candidate;\n break;\n }\n }\n\n // Find the best value field\n for (const candidate of valueFieldCandidates) {\n if (keys.includes(candidate)) {\n valueField = candidate;\n break;\n }\n }\n\n // If no standard names found, use heuristics:\n // - First string field as label\n // - First number field as value\n if (!labelField || !valueField) {\n for (const key of keys) {\n const val = (sampleItem as Record<string, unknown>)[key];\n if (!labelField && typeof val === 'string') {\n labelField = key;\n }\n if (!valueField && typeof val === 'number') {\n valueField = key;\n }\n if (labelField && valueField) break;\n }\n }\n\n return {\n labelField,\n valueField,\n xAxisField: labelField, // For line/bar charts, xAxisField is usually the same as labelField\n };\n}\n\n// ============================================================================\n// Template Editor Component\n// ============================================================================\n\ninterface TemplateEditorProps {\n widget: Widget;\n onSave: (template: Record<string, unknown>) => void;\n}\n\nconst TemplateEditor: FC<TemplateEditorProps> = memo(function TemplateEditor({ widget, onSave }) {\n const [localValue, setLocalValue] = useState<string>('');\n const [jsonError, setJsonError] = useState<string | null>(null);\n const initializedRef = useRef(false);\n\n // Initialize from widget.template only once per widget\n useEffect(() => {\n try {\n const templateStr =\n widget.template && typeof widget.template === 'object' ? JSON.stringify(widget.template, null, 2) : '';\n setLocalValue(templateStr);\n setJsonError(null);\n initializedRef.current = true;\n } catch {\n setLocalValue('');\n }\n }, [widget.id, widget.template]);\n\n const handleChange = useCallback(\n (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n const value = e.target.value;\n setLocalValue(value);\n\n if (value.trim() === '') {\n setJsonError(null);\n // Empty template is valid - notify parent\n onSave({});\n } else {\n try {\n const parsed = JSON.parse(value);\n setJsonError(null);\n // Valid JSON - immediately notify parent so main Save button becomes active\n onSave(parsed);\n } catch (err) {\n setJsonError((err as Error).message);\n // Don't call onSave for invalid JSON\n }\n }\n },\n [onSave]\n );\n\n const handleFormat = useCallback(() => {\n try {\n const parsed = JSON.parse(localValue);\n const formatted = JSON.stringify(parsed, null, 2);\n setLocalValue(formatted);\n setJsonError(null);\n onSave(parsed);\n } catch (err) {\n setJsonError((err as Error).message);\n }\n }, [localValue, onSave]);\n\n return (\n <div\n style={{\n paddingTop: 'var(--space-formGap)',\n borderTop: '1px solid var(--color-border)',\n }}\n >\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n <label\n style={{\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n }}\n >\n Template (JSON)\n </label>\n {jsonError && (\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-status-error-text)',\n fontWeight: 'var(--font-weight-medium)',\n }}\n >\n Invalid JSON\n </span>\n )}\n </div>\n\n <Textarea\n value={localValue}\n onChange={handleChange}\n spellCheck={false}\n placeholder={`Enter ${widget.renderer} template JSON...`}\n style={{\n fontFamily: 'var(--font-family-mono)',\n fontSize: 'var(--font-size-body-sm)',\n minHeight: '180px',\n borderColor: jsonError ? 'var(--color-status-error-border)' : undefined,\n resize: 'vertical',\n }}\n />\n\n {jsonError && (\n <p\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-status-error-text)',\n backgroundColor: 'var(--color-status-error-bgSubtle)',\n padding: 'var(--space-controlGap)',\n borderRadius: 'var(--radius-button)',\n marginTop: 'var(--space-controlGap)',\n }}\n >\n {jsonError}\n </p>\n )}\n\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n marginTop: 'var(--space-controlGap)',\n }}\n >\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleFormat}\n disabled={!!jsonError || localValue.trim() === ''}\n style={{ height: 'var(--size-controlHeight-sm)', fontWeight: 'var(--font-weight-semibold)' }}\n >\n Format\n </Button>\n {!jsonError && localValue.trim() !== '' && (\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-status-success-text)',\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n }}\n >\n <Check style={{ width: '12px', height: '12px' }} />\n Valid JSON\n </span>\n )}\n </div>\n\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-muted)',\n marginTop: 'var(--space-controlGap)',\n paddingTop: 'var(--space-controlGap)',\n borderTop: '1px solid var(--color-border)',\n }}\n >\n <span style={{ fontWeight: 'var(--font-weight-medium)' }}>Ctrl+S to save</span>\n {widget.renderer === 'ADAPTIVE_CARD' && (\n <a\n href=\"https://adaptivecards.io/designer/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n color: 'var(--color-text-link)',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n textDecoration: 'none',\n }}\n >\n Designer\n <ExternalLink style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n </a>\n )}\n {widget.renderer === 'BLOCKKIT' && (\n <a\n href=\"https://app.slack.com/block-kit-builder\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n color: 'var(--color-text-link)',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n textDecoration: 'none',\n }}\n >\n Block Kit Builder\n <ExternalLink style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n </a>\n )}\n </div>\n </div>\n );\n});\n\n// ============================================================================\n// Local Form State Type\n// ============================================================================\n\ninterface LocalFormState {\n title: string;\n description: string;\n refreshInterval: number | undefined;\n renderer: RendererType;\n template: Record<string, unknown> | undefined;\n // v2.0: Data source fields (DataSink → Parser → Widget)\n dataSinkId: string | undefined;\n datasetId: string | undefined;\n parserId: string | undefined;\n parserRules: string | undefined;\n config: Record<string, unknown>;\n // Drilldown configuration\n drilldownConfig: DrilldownConfig | undefined;\n}\n\nfunction createLocalFormStateFromWidget(widget: Widget): LocalFormState {\n const widgetFields = widget as unknown as Record<string, string | undefined>;\n const binding = getWidgetBinding({\n dataSinkId: widgetFields.dataSinkId,\n parserId: widgetFields.parserId,\n config: (widget.config as Record<string, unknown>) || {},\n });\n\n return {\n title: widget.title || '',\n description: widget.description || '',\n refreshInterval: widget.refreshInterval ?? undefined,\n renderer: (widget.renderer as RendererType) || 'BIGCONSOLE',\n template: widget.template as Record<string, unknown> | undefined,\n // v2.0: Data source fields (DataSink → Parser → Widget)\n dataSinkId: binding.source.kind === 'DATASINK' ? binding.source.ref : undefined,\n datasetId: widgetFields.datasetId ?? undefined,\n parserId: binding.parserId,\n parserRules: widgetFields.parserRules ?? undefined,\n config: (widget.config as Record<string, unknown>) || {},\n // Drilldown configuration\n drilldownConfig: widget.drilldown\n ? {\n enabled: widget.drilldown.enabled ?? false,\n targetDashboardId: widget.drilldown.targetDashboardId ?? '',\n navigationMode: widget.drilldown.navigationMode ?? 'MODAL',\n parameterMapping: (widget.drilldown.parameterMapping as Record<string, string>) ?? {},\n passGlobalFilters: widget.drilldown.passGlobalFilters ?? true,\n maxDepth: widget.drilldown.maxDepth ?? 3,\n openIn: widget.drilldown.openIn ?? 'same',\n }\n : undefined,\n };\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const PropertiesPanel: FC<PropertiesPanelProps> = memo(function PropertiesPanel({ isOpen, onClose }) {\n const [activeTab, setActiveTab] = useState<TabId>('general');\n const [saveStatus, setSaveStatus] = useState<'idle' | 'saving' | 'saved' | 'error'>('idle');\n const [localForm, setLocalForm] = useState<LocalFormState | null>(null);\n const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);\n\n const selectedWidgetId = useWidgetStore((state) => state.selectedWidgetId);\n const widgets = useWidgetStore((state) => state.widgets);\n const updateWidgetInStore = useWidgetStore((state) => state.updateWidget);\n\n const selectedWidget = selectedWidgetId ? widgets.get(selectedWidgetId) : undefined;\n const previousSelectedWidgetIdRef = useRef<string | null>(null);\n\n useEffect(() => {\n if (!selectedWidgetId) {\n previousSelectedWidgetIdRef.current = null;\n setLocalForm(null);\n setHasUnsavedChanges(false);\n setSaveStatus('idle');\n return;\n }\n\n const widgetSwitched = previousSelectedWidgetIdRef.current !== selectedWidgetId;\n previousSelectedWidgetIdRef.current = selectedWidgetId;\n\n if (selectedWidget) {\n if (hasUnsavedChanges && !widgetSwitched) return;\n\n setLocalForm(createLocalFormStateFromWidget(selectedWidget));\n setHasUnsavedChanges(false);\n setSaveStatus('idle');\n } else {\n setLocalForm(null);\n setHasUnsavedChanges(false);\n setSaveStatus('idle');\n }\n }, [selectedWidgetId, selectedWidget, hasUnsavedChanges]);\n\n const { updateWidget: updateWidgetApi } = useWidgetOperations(selectedWidget?.pageId, selectedWidget?.dashboardId, {\n skipFetch: true,\n });\n\n // Drilldown operations\n const { createDrilldown, updateDrilldown, deleteDrilldown } = useDrilldownOperations();\n\n // DataSink operations - for looking up DataSink by key\n const { dataSinks } = useDataSinkOperations({ skipFetch: false });\n\n // Track selected DataSink key for filtering parsers\n const [selectedDataSinkKey, setSelectedDataSinkKey] = useState<string | null>(null);\n\n // Parser operations - for executing parser to detect fields\n const { executeParser } = useParserOperations({\n consoleId: selectedWidget?.dashboardId,\n skipFetch: true,\n });\n\n // Track if we're auto-detecting fields\n const [isDetectingFields, setIsDetectingFields] = useState(false);\n const [bindingPreview, setBindingPreview] = useState<unknown>(undefined);\n const [bindingPreviewComplete, setBindingPreviewComplete] = useState(false);\n const [bindingPreviewError, setBindingPreviewError] = useState<string | null>(null);\n\n useEffect(() => {\n setBindingPreview(undefined);\n setBindingPreviewComplete(false);\n setBindingPreviewError(null);\n setIsDetectingFields(false);\n }, [selectedWidgetId]);\n\n const {\n actions,\n loading: actionsLoading,\n createAction,\n updateAction,\n deleteAction,\n reorderActions,\n } = useWidgetActions(selectedWidgetId || undefined);\n\n const [isActionDialogOpen, setIsActionDialogOpen] = useState(false);\n const [editingAction, setEditingAction] = useState<WidgetAction | undefined>(undefined);\n const [actionSaving, setActionSaving] = useState(false);\n\n const handleAddAction = useCallback(() => {\n setEditingAction(undefined);\n setIsActionDialogOpen(true);\n }, []);\n\n const handleEditAction = useCallback((action: WidgetAction) => {\n setEditingAction(action);\n setIsActionDialogOpen(true);\n }, []);\n\n const handleSaveAction = useCallback(\n async (data: Omit<CreateWidgetActionInput, 'widgetId'> | UpdateWidgetActionInput) => {\n if (!selectedWidgetId) return;\n\n setActionSaving(true);\n try {\n let newAction: WidgetAction | null = null;\n if ('id' in data) {\n newAction = await updateAction(data);\n } else {\n newAction = await createAction(data);\n }\n\n // Immediately sync to widget store after successful save\n // This ensures the widget displays the action right away\n if (newAction) {\n const currentActions = [...actions];\n if ('id' in data) {\n // Update existing action\n const idx = currentActions.findIndex((a) => a.id === data.id);\n if (idx >= 0) {\n currentActions[idx] = newAction;\n }\n } else {\n // Add new action\n currentActions.push(newAction);\n }\n // Sort by order and update store\n const sortedActions = currentActions.sort((a, b) => a.order - b.order);\n updateWidgetInStore(selectedWidgetId, { actions: sortedActions });\n }\n\n setIsActionDialogOpen(false);\n setEditingAction(undefined);\n } catch (err) {\n } finally {\n setActionSaving(false);\n }\n },\n [selectedWidgetId, actions, createAction, updateAction, updateWidgetInStore]\n );\n\n const handleDeleteAction = useCallback(\n async (actionId: string) => {\n if (!selectedWidgetId) return;\n\n if (window.confirm('Are you sure you want to delete this action?')) {\n const success = await deleteAction(actionId);\n if (success) {\n // Immediately sync to widget store after deletion\n const updatedActions = actions.filter((a) => a.id !== actionId);\n updateWidgetInStore(selectedWidgetId, { actions: updatedActions });\n }\n }\n },\n [selectedWidgetId, actions, deleteAction, updateWidgetInStore]\n );\n\n const handleMoveActionUp = useCallback(\n async (index: number) => {\n if (!selectedWidgetId || index === 0) return;\n const sortedActions = [...actions].sort((a, b) => a.order - b.order);\n const newOrder = sortedActions.map((a) => a.id);\n [newOrder[index - 1], newOrder[index]] = [newOrder[index], newOrder[index - 1]];\n const success = await reorderActions(newOrder);\n if (success) {\n // Immediately update local order for UI responsiveness\n const reordered = sortedActions\n .map((a, _i) => ({\n ...a,\n order: newOrder.indexOf(a.id),\n }))\n .sort((a, b) => a.order - b.order);\n updateWidgetInStore(selectedWidgetId, { actions: reordered });\n }\n },\n [selectedWidgetId, actions, reorderActions, updateWidgetInStore]\n );\n\n const handleMoveActionDown = useCallback(\n async (index: number) => {\n if (!selectedWidgetId) return;\n const sortedActions = [...actions].sort((a, b) => a.order - b.order);\n if (index === sortedActions.length - 1) return;\n const newOrder = sortedActions.map((a) => a.id);\n [newOrder[index], newOrder[index + 1]] = [newOrder[index + 1], newOrder[index]];\n const success = await reorderActions(newOrder);\n if (success) {\n // Immediately update local order for UI responsiveness\n const reordered = sortedActions\n .map((a, _i) => ({\n ...a,\n order: newOrder.indexOf(a.id),\n }))\n .sort((a, b) => a.order - b.order);\n updateWidgetInStore(selectedWidgetId, { actions: reordered });\n }\n },\n [selectedWidgetId, actions, reorderActions, updateWidgetInStore]\n );\n\n useEffect(() => {\n if (selectedWidgetId && actions.length >= 0 && !actionsLoading) {\n updateWidgetInStore(selectedWidgetId, { actions });\n }\n }, [selectedWidgetId, actions, actionsLoading, updateWidgetInStore]);\n\n const updateLocalForm = useCallback(<K extends keyof LocalFormState>(key: K, value: LocalFormState[K]) => {\n setLocalForm((prev) => (prev ? { ...prev, [key]: value } : prev));\n setHasUnsavedChanges(true);\n }, []);\n\n const updateLocalConfig = useCallback((newConfig: Record<string, unknown>) => {\n setLocalForm((prev) => (prev ? { ...prev, config: newConfig } : prev));\n setHasUnsavedChanges(true);\n }, []);\n\n // Initialize selectedDataSinkKey from widget's dataSinkId\n useEffect(() => {\n if (localForm?.dataSinkId && dataSinks.length > 0) {\n const ds = dataSinks.find((d) => d.id === localForm.dataSinkId);\n if (ds) {\n setSelectedDataSinkKey(ds.key);\n }\n } else {\n setSelectedDataSinkKey(null);\n }\n }, [localForm?.dataSinkId, dataSinks]);\n\n // Handle DataSink selection - looks up ID from key and updates form\n const handleDataSinkChange = useCallback(\n (key: string | null) => {\n setBindingPreview(undefined);\n setBindingPreviewComplete(false);\n setBindingPreviewError(null);\n setSelectedDataSinkKey(key);\n if (key) {\n const ds = dataSinks.find((d) => d.key === key);\n if (ds) {\n updateLocalForm('dataSinkId', ds.id);\n // Also update config.dataSinkKey for backward compatibility\n setLocalForm((prev) =>\n prev\n ? {\n ...prev,\n config: { ...prev.config, dataSinkKey: key },\n }\n : prev\n );\n setHasUnsavedChanges(true);\n }\n } else {\n updateLocalForm('dataSinkId', undefined);\n setLocalForm((prev) =>\n prev\n ? {\n ...prev,\n config: { ...prev.config, dataSinkKey: undefined },\n parserId: undefined, // Clear parser when DataSink is cleared\n }\n : prev\n );\n setHasUnsavedChanges(true);\n }\n },\n [dataSinks, updateLocalForm]\n );\n\n // Handle Parser selection - with auto-detection of field mappings\n const handleParserChange = useCallback(\n async (parserId: string | null) => {\n updateLocalForm('parserId', parserId || undefined);\n setBindingPreview(undefined);\n setBindingPreviewComplete(false);\n setBindingPreviewError(null);\n\n // If a parser is selected, execute it to detect field structure\n if (parserId && selectedWidget) {\n setIsDetectingFields(true);\n try {\n const result = await executeParser(parserId);\n\n if (result?.success) {\n setBindingPreview(result.output);\n setBindingPreviewComplete(true);\n const detectedFields = detectFieldsFromParserOutput(result.output);\n\n // Only auto-populate if fields were detected and not already set\n if (detectedFields.labelField || detectedFields.valueField) {\n setLocalForm((prev) => {\n if (!prev) return prev;\n\n const currentConfig = prev.config || {};\n const newConfig = { ...currentConfig };\n\n // Auto-populate labelField if not already set\n if (detectedFields.labelField && !currentConfig.labelField) {\n newConfig.labelField = detectedFields.labelField;\n }\n\n // Auto-populate valueField if not already set\n if (detectedFields.valueField && !currentConfig.valueField) {\n newConfig.valueField = detectedFields.valueField;\n }\n\n // Auto-populate xAxisField for line/bar/area charts if not already set\n if (detectedFields.xAxisField && !currentConfig.xAxisField) {\n newConfig.xAxisField = detectedFields.xAxisField;\n }\n\n return { ...prev, config: newConfig };\n });\n setHasUnsavedChanges(true);\n }\n } else {\n setBindingPreviewComplete(true);\n setBindingPreviewError(result?.error || 'The parser could not produce a preview.');\n }\n } catch (err) {\n setBindingPreviewComplete(true);\n setBindingPreviewError(err instanceof Error ? err.message : 'The parser could not produce a preview.');\n console.warn('Failed to auto-detect parser fields:', err);\n } finally {\n setIsDetectingFields(false);\n }\n }\n },\n [updateLocalForm, executeParser, selectedWidget]\n );\n\n const handleSaveAll = useCallback(async () => {\n if (!selectedWidget || !localForm) return;\n\n setSaveStatus('saving');\n\n try {\n const metadata = { ...(selectedWidget.metadata || {}), description: localForm.description || '' };\n const bindingDraft = getWidgetBinding({\n dataSinkId: localForm.dataSinkId,\n parserId: localForm.parserId,\n config: { ...localForm.config, binding: undefined },\n });\n const bindingWrite = serializeWidgetBinding(bindingDraft, localForm.config);\n\n const result = await updateWidgetApi({\n id: selectedWidget.id,\n title: localForm.title,\n renderer: localForm.renderer,\n template: localForm.template,\n config: bindingWrite.config,\n refreshInterval: localForm.refreshInterval,\n // v2.0: Data source fields (DataSink → Parser → Widget)\n dataSinkId: bindingWrite.dataSinkId,\n datasetId: localForm.datasetId,\n parserId: bindingWrite.parserId,\n parserRules: localForm.parserRules,\n metadata,\n });\n\n // Save drilldown configuration to backend\n let savedDrilldown = selectedWidget.drilldown;\n if (localForm.drilldownConfig) {\n const { enabled, targetDashboardId, navigationMode, parameterMapping, passGlobalFilters, maxDepth, openIn } =\n localForm.drilldownConfig;\n\n if (selectedWidget.drilldown?.id) {\n // Update existing drilldown\n const drilldownResult = await updateDrilldown({\n id: selectedWidget.drilldown.id,\n targetDashboardId,\n parameterMapping,\n navigationMode,\n enabled,\n passGlobalFilters,\n maxDepth,\n openIn,\n });\n if (drilldownResult) {\n savedDrilldown = drilldownResult;\n }\n } else if (targetDashboardId) {\n // Create new drilldown (only if targetDashboardId is set)\n const drilldownResult = await createDrilldown({\n sourceWidgetId: selectedWidget.id,\n targetDashboardId,\n parameterMapping: parameterMapping || {},\n navigationMode,\n passGlobalFilters,\n maxDepth,\n openIn,\n });\n if (drilldownResult) {\n savedDrilldown = { ...drilldownResult, enabled };\n }\n }\n } else if (selectedWidget.drilldown?.id && !localForm.drilldownConfig) {\n // Delete drilldown if it existed but was removed\n await deleteDrilldown(selectedWidget.drilldown.id);\n savedDrilldown = undefined;\n }\n\n if (result) {\n updateWidgetInStore(selectedWidget.id, {\n title: localForm.title,\n description: localForm.description,\n renderer: localForm.renderer,\n template: localForm.template,\n config: bindingWrite.config,\n refreshInterval: localForm.refreshInterval,\n // v2.0: Data source fields\n dataSinkId: bindingWrite.dataSinkId,\n datasetId: localForm.datasetId,\n parserId: bindingWrite.parserId,\n parserRules: localForm.parserRules,\n // Drilldown configuration from backend\n drilldown: savedDrilldown,\n // Update timestamp to trigger WidgetWrapper re-render (fixes drilldown mode change bug)\n updatedAt: new Date().toISOString(),\n } as Partial<Widget>);\n\n setSaveStatus('saved');\n setHasUnsavedChanges(false);\n setTimeout(() => setSaveStatus('idle'), 2000);\n } else {\n setSaveStatus('error');\n }\n } catch (err) {\n setSaveStatus('error');\n }\n }, [\n selectedWidget,\n localForm,\n updateWidgetApi,\n updateWidgetInStore,\n createDrilldown,\n updateDrilldown,\n deleteDrilldown,\n ]);\n\n const handleDiscardAll = useCallback(() => {\n if (!selectedWidget) return;\n\n setLocalForm(createLocalFormStateFromWidget(selectedWidget));\n setHasUnsavedChanges(false);\n setSaveStatus('idle');\n }, [selectedWidget]);\n\n const handleConfigChange = useCallback(\n (newConfig: Record<string, unknown>) => {\n updateLocalConfig(newConfig);\n },\n [updateLocalConfig]\n );\n\n const handleDrilldownChange = useCallback((config: DrilldownConfig) => {\n setLocalForm((prev) => (prev ? { ...prev, drilldownConfig: config } : prev));\n setHasUnsavedChanges(true);\n }, []);\n\n const definition = selectedWidget ? getWidgetDefinition(selectedWidget.type) : null;\n\n return (\n <Sheet open={isOpen} onOpenChange={(open) => !open && onClose()} modal={false}>\n <SheetContent\n style={{\n width: '420px',\n maxWidth: '90vw',\n padding: 0,\n display: 'flex',\n flexDirection: 'column',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n <SheetHeader\n style={{\n padding: 'var(--space-cardPadding)',\n borderBottom: '1px solid var(--color-border)',\n backgroundColor: 'var(--color-bg-surface)',\n flexShrink: 0,\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-controlGap)' }}>\n <div\n style={{\n display: 'flex',\n height: 'var(--size-controlHeight-lg)',\n width: 'var(--size-controlHeight-lg)',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 'var(--radius-card)',\n backgroundColor: 'var(--color-action-primary-bg)',\n boxShadow: 'var(--shadow-elevation-2)',\n flexShrink: 0,\n }}\n >\n <Info\n style={{\n height: 'var(--size-icon-md)',\n width: 'var(--size-icon-md)',\n color: 'var(--color-action-primary-text)',\n }}\n />\n </div>\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <SheetTitle\n style={{\n fontSize: 'var(--font-size-body-md)',\n fontWeight: 'var(--font-weight-bold)',\n color: 'var(--color-text-primary)',\n margin: 0,\n }}\n >\n {selectedWidget ? 'Widget Properties' : 'Properties'}\n </SheetTitle>\n {saveStatus === 'saving' && (\n <Spinner style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n )}\n {saveStatus === 'saved' && (\n <Check\n style={{\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n color: 'var(--color-status-success-bg)',\n }}\n />\n )}\n {saveStatus === 'error' && (\n <X\n style={{\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n color: 'var(--color-status-error-bg)',\n }}\n />\n )}\n </div>\n {definition && (\n <SheetDescription\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-secondary)',\n margin: 'var(--space-controlGap) 0 0 0',\n fontWeight: 'var(--font-weight-medium)',\n }}\n >\n {definition.name}\n </SheetDescription>\n )}\n </div>\n </div>\n </SheetHeader>\n\n {selectedWidget ? (\n <Tabs\n value={activeTab}\n onValueChange={(v) => setActiveTab(v as TabId)}\n style={{ flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0, overflow: 'hidden' }}\n >\n <TabsList\n style={{\n width: '100%',\n display: 'flex',\n justifyContent: 'flex-start',\n borderRadius: 0,\n borderBottom: '1px solid var(--color-border)',\n padding: '0 8px',\n backgroundColor: 'var(--color-bg-sunken)',\n height: 'var(--size-controlHeight-lg)',\n flexShrink: 0,\n gap: '2px',\n overflowX: 'auto',\n }}\n >\n <TabsTrigger\n value=\"general\"\n style={{\n fontWeight: 'var(--font-weight-semibold)',\n fontSize: '12px',\n padding: '6px 8px',\n flexShrink: 0,\n }}\n >\n General\n </TabsTrigger>\n <TabsTrigger\n value=\"data\"\n style={{\n fontWeight: 'var(--font-weight-semibold)',\n fontSize: '12px',\n padding: '6px 8px',\n flexShrink: 0,\n }}\n >\n Data\n </TabsTrigger>\n <TabsTrigger\n value=\"advanced\"\n style={{\n fontWeight: 'var(--font-weight-semibold)',\n fontSize: '12px',\n padding: '6px 8px',\n flexShrink: 0,\n }}\n >\n Advanced\n </TabsTrigger>\n <TabsTrigger\n value=\"appearance\"\n style={{\n fontWeight: 'var(--font-weight-semibold)',\n fontSize: '12px',\n padding: '6px 8px',\n flexShrink: 0,\n }}\n >\n Style\n </TabsTrigger>\n </TabsList>\n\n <div style={{ flex: 1, overflow: 'auto', padding: 'var(--space-cardPadding)', minHeight: 0 }}>\n <TabsContent value=\"general\" className=\"mt-0\">\n {localForm && (\n <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-formGap)' }}>\n <GeneralSection\n title={localForm.title}\n description={localForm.description}\n refreshInterval={localForm.refreshInterval}\n onTitleChange={(title) => updateLocalForm('title', title)}\n onDescriptionChange={(description) => updateLocalForm('description', description)}\n onRefreshIntervalChange={(refreshInterval) => updateLocalForm('refreshInterval', refreshInterval)}\n />\n </div>\n )}\n </TabsContent>\n\n <TabsContent value=\"data\" className=\"mt-0 space-y-4\">\n {localForm && (\n <>\n {(() => {\n const binding = getWidgetBinding({\n dataSinkId: localForm.dataSinkId,\n parserId: localForm.parserId,\n config: { ...localForm.config, binding: undefined },\n });\n const validation = getWidgetBindingStatus({\n binding,\n loading: isDetectingFields,\n error: bindingPreviewError,\n preview: bindingPreview,\n previewComplete: bindingPreviewComplete,\n });\n\n return (\n <DataBindingSection\n consoleId={selectedWidget?.dashboardId || ''}\n binding={binding}\n dataSinkKey={selectedDataSinkKey}\n dataPath={\n typeof localForm.config.dataPath === 'string' ? localForm.config.dataPath : undefined\n }\n status={validation.status}\n missingFields={validation.missingFields}\n preview={bindingPreview}\n error={bindingPreviewError}\n onDataSinkChange={handleDataSinkChange}\n onParserChange={handleParserChange}\n onDataPathChange={(dataPath) => updateLocalConfig({ ...localForm.config, dataPath })}\n />\n );\n })()}\n\n {/* Divider */}\n <div className=\"border-t border-border-subtle pt-4\">\n <Label className=\"text-xs text-text-secondary uppercase tracking-wide\">\n Alternative Data Sources\n </Label>\n </div>\n\n {/* Data Source Type Selector */}\n <div className=\"space-y-2\">\n <Label>Data Source Type</Label>\n <Select\n value={(localForm.config?.dataSourceType as string) || ''}\n onValueChange={(value) =>\n updateLocalConfig({ ...localForm.config, dataSourceType: value || undefined })\n }\n >\n <SelectTrigger\n style={{ height: 'var(--size-controlHeight-md)', fontSize: 'var(--font-size-body-sm)' }}\n >\n <SelectValue placeholder=\"Select type...\" />\n </SelectTrigger>\n <SelectContent\n position=\"popper\"\n side=\"bottom\"\n sideOffset={4}\n align=\"start\"\n style={{\n zIndex: 9999,\n maxHeight: '200px',\n backgroundColor: 'var(--color-overlay-popoverBg, var(--color-bg-surface, #ffffff))',\n border: '1px solid var(--color-border)',\n boxShadow: 'var(--shadow-elevation-3)',\n borderRadius: 'var(--radius-button)',\n }}\n >\n {DATA_SOURCE_TYPES.map((type) => (\n <SelectItem key={type.value} value={type.value}>\n {type.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {localForm.config?.dataSourceType === 'REST_API' && (\n <div className=\"space-y-3\">\n {/* Endpoint URL */}\n <div className=\"space-y-2\">\n <Label>Endpoint URL *</Label>\n <Input\n value={(localForm.config?.endpointUrl as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, endpointUrl: e.target.value || undefined })\n }\n placeholder=\"https://api.example.com/data\"\n />\n </div>\n\n {/* HTTP Method */}\n <div className=\"space-y-2\">\n <Label>HTTP Method</Label>\n <Select\n value={(localForm.config?.httpMethod as string) || 'GET'}\n onValueChange={(value) => updateLocalConfig({ ...localForm.config, httpMethod: value })}\n >\n <SelectTrigger style={{ height: 'var(--size-controlHeight-md)' }}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent position=\"popper\" side=\"bottom\" sideOffset={4}>\n <SelectItem value=\"GET\">GET</SelectItem>\n <SelectItem value=\"POST\">POST</SelectItem>\n <SelectItem value=\"PUT\">PUT</SelectItem>\n <SelectItem value=\"DELETE\">DELETE</SelectItem>\n </SelectContent>\n </Select>\n </div>\n\n {/* Headers */}\n <div className=\"space-y-2\">\n <Label>Headers (JSON)</Label>\n <Textarea\n value={(localForm.config?.headers as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, headers: e.target.value || undefined })\n }\n rows={3}\n placeholder='{\"Authorization\": \"Bearer token\", \"Content-Type\": \"application/json\"}'\n className=\"font-mono text-xs\"\n />\n </div>\n\n {/* Authentication Type */}\n <div className=\"space-y-2\">\n <Label>Authentication</Label>\n <Select\n value={(localForm.config?.authType as string) || 'none'}\n onValueChange={(value) => updateLocalConfig({ ...localForm.config, authType: value })}\n >\n <SelectTrigger style={{ height: 'var(--size-controlHeight-md)' }}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent position=\"popper\" side=\"bottom\" sideOffset={4}>\n <SelectItem value=\"none\">None</SelectItem>\n <SelectItem value=\"api_key\">API Key</SelectItem>\n <SelectItem value=\"bearer\">Bearer Token</SelectItem>\n <SelectItem value=\"basic\">Basic Auth</SelectItem>\n </SelectContent>\n </Select>\n </div>\n\n {/* Auth Value (conditional) */}\n {!!(localForm.config?.authType && localForm.config.authType !== 'none') && (\n <div className=\"space-y-2\">\n <Label>\n {String(localForm.config.authType) === 'basic' ? 'Credentials (user:pass)' : 'Token/Key'}\n </Label>\n <Input\n type=\"password\"\n value={(localForm.config?.authValue as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, authValue: e.target.value || undefined })\n }\n placeholder={\n localForm.config.authType === 'basic' ? 'username:password' : 'Enter token or API key'\n }\n />\n </div>\n )}\n\n {/* Request Body (for POST/PUT) */}\n {(localForm.config?.httpMethod === 'POST' || localForm.config?.httpMethod === 'PUT') && (\n <div className=\"space-y-2\">\n <Label>Request Body (JSON)</Label>\n <Textarea\n value={(localForm.config?.requestBody as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, requestBody: e.target.value || undefined })\n }\n rows={4}\n placeholder='{\"key\": \"value\"}'\n className=\"font-mono text-xs\"\n />\n </div>\n )}\n\n {/* Data Path */}\n <div className=\"space-y-2\">\n <Label>Data Path (optional)</Label>\n <Input\n value={(localForm.config?.dataPath as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, dataPath: e.target.value || undefined })\n }\n placeholder=\"$.data.items or .data.items\"\n />\n <p className=\"text-xs text-text-secondary\">\n JSONPath or dot notation to extract data from response\n </p>\n </div>\n </div>\n )}\n\n {localForm.config?.dataSourceType === 'GRAPHQL' && (\n <div className=\"space-y-3\">\n {/* GraphQL Endpoint */}\n <div className=\"space-y-2\">\n <Label>GraphQL Endpoint *</Label>\n <Input\n value={(localForm.config?.graphqlEndpoint as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, graphqlEndpoint: e.target.value || undefined })\n }\n placeholder=\"https://api.example.com/graphql\"\n />\n </div>\n\n {/* GraphQL Query */}\n <div className=\"space-y-2\">\n <Label>Query *</Label>\n <Textarea\n value={(localForm.config?.graphqlQuery as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, graphqlQuery: e.target.value || undefined })\n }\n rows={6}\n placeholder={`query GetData($limit: Int) {\n items(limit: $limit) {\n id\n name\n value\n }\n}`}\n className=\"font-mono text-xs\"\n />\n </div>\n\n {/* GraphQL Variables */}\n <div className=\"space-y-2\">\n <Label>Variables (JSON, optional)</Label>\n <Textarea\n value={(localForm.config?.graphqlVariables as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, graphqlVariables: e.target.value || undefined })\n }\n rows={3}\n placeholder='{\"limit\": 10, \"offset\": 0}'\n className=\"font-mono text-xs\"\n />\n </div>\n\n {/* Headers */}\n <div className=\"space-y-2\">\n <Label>Headers (JSON, optional)</Label>\n <Textarea\n value={(localForm.config?.headers as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, headers: e.target.value || undefined })\n }\n rows={2}\n placeholder='{\"Authorization\": \"Bearer token\"}'\n className=\"font-mono text-xs\"\n />\n </div>\n\n {/* Data Path */}\n <div className=\"space-y-2\">\n <Label>Data Path (optional)</Label>\n <Input\n value={(localForm.config?.dataPath as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, dataPath: e.target.value || undefined })\n }\n placeholder=\".data.items\"\n />\n <p className=\"text-xs text-text-secondary\">Path to extract data from GraphQL response</p>\n </div>\n </div>\n )}\n\n {localForm.config?.dataSourceType === 'MOCK' && (\n <div className=\"space-y-2\">\n <Label>Sample Data (JSON)</Label>\n <Textarea\n value={(localForm.config?.mockData as string) || ''}\n onChange={(e) =>\n updateLocalConfig({ ...localForm.config, mockData: e.target.value || undefined })\n }\n rows={5}\n placeholder='{\"value\": 100}'\n className=\"font-mono text-sm\"\n />\n </div>\n )}\n </>\n )}\n </TabsContent>\n\n <TabsContent value=\"advanced\" className=\"mt-0 space-y-6\">\n {localForm && (\n <AdvancedSection\n renderer={localForm.renderer}\n rendererOptions={RENDERER_OPTIONS}\n onRendererChange={(renderer) => {\n updateLocalForm('renderer', renderer);\n if (renderer === 'BIGCONSOLE') updateLocalForm('template', undefined);\n }}\n templateEditor={\n localForm.renderer !== 'BIGCONSOLE' ? (\n <TemplateEditor\n widget={{ ...selectedWidget, template: localForm.template, renderer: localForm.renderer }}\n onSave={(template) => updateLocalForm('template', template)}\n />\n ) : undefined\n }\n />\n )}\n\n <section className=\"space-y-4 border-t border-border-default pt-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"text-sm font-medium\">Widget Actions</h3>\n <p className=\"text-xs text-text-secondary\">Configure buttons on this widget</p>\n </div>\n <Button size=\"sm\" onClick={handleAddAction}>\n <Plus className=\"size-4\" />\n Add\n </Button>\n </div>\n\n {actionsLoading ? (\n <div className=\"flex justify-center py-8\">\n <Spinner className=\"size-6\" />\n </div>\n ) : actions.length === 0 ? (\n <div className=\"py-8 text-center\">\n <Info className=\"size-10 mx-auto mb-2 text-text-secondary/50\" />\n <p className=\"text-sm text-text-secondary\">No actions configured</p>\n </div>\n ) : (\n <div className=\"space-y-2\">\n {[...actions]\n .sort((a, b) => a.order - b.order)\n .map((action, index) => (\n <Card key={action.id} className={action.disabled ? 'opacity-60' : ''}>\n <CardContent className=\"p-3 flex items-center gap-2\">\n <div className=\"flex flex-col gap-0.5\">\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n onClick={() => handleMoveActionUp(index)}\n disabled={index === 0}\n className=\"h-5 w-5\"\n >\n <ChevronUp className=\"size-3\" />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n onClick={() => handleMoveActionDown(index)}\n disabled={index === actions.length - 1}\n className=\"h-5 w-5\"\n >\n <ChevronDown className=\"size-3\" />\n </Button>\n </div>\n\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span\n className={`size-2 rounded-full ${ACTION_STYLE_COLORS[action.style] || 'bg-muted-foreground'}`}\n />\n <span className=\"text-sm font-medium truncate\">{action.label}</span>\n </div>\n <p className=\"text-xs text-text-secondary\">\n {action.name} • {action.type}\n </p>\n </div>\n\n <div className=\"flex gap-1\">\n <Button variant=\"ghost\" size=\"icon-sm\" onClick={() => handleEditAction(action)}>\n <Pencil className=\"size-4\" />\n </Button>\n <Button variant=\"ghost\" size=\"icon-sm\" onClick={() => handleDeleteAction(action.id)}>\n <Trash2 className=\"size-4\" />\n </Button>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n </section>\n\n <section className=\"space-y-3 border-t border-border-default pt-4\">\n <h3 className=\"text-sm font-semibold text-text-primary\">Drilldown</h3>\n <DrilldownConfigPanel widget={selectedWidget} onChange={handleDrilldownChange} />\n </section>\n\n <section className=\"space-y-3 border-t border-border-default pt-4\">\n <h3 className=\"text-sm font-semibold text-text-primary\">Webhooks</h3>\n <WebhookConfigPanel dashboardId={selectedWidget.dashboardId} widgetId={selectedWidget.id} />\n </section>\n\n <section className=\"space-y-3 border-t border-border-default pt-4\">\n <h3 className=\"text-sm font-semibold text-text-primary\">Events</h3>\n <EventLogViewer\n dashboardId={selectedWidget.dashboardId}\n widgetId={selectedWidget.id}\n maxHeight=\"calc(100vh - 350px)\"\n />\n </section>\n </TabsContent>\n\n <TabsContent value=\"appearance\" className=\"mt-0\">\n {localForm && (\n <AppearanceSection\n widgetType={selectedWidget.type}\n config={localForm.config || {}}\n onChange={handleConfigChange}\n />\n )}\n </TabsContent>\n </div>\n </Tabs>\n ) : (\n <div className=\"flex-1 flex items-center justify-center p-4\">\n <div className=\"text-center\">\n <Info className=\"size-12 mx-auto mb-3 text-text-secondary\" />\n <p className=\"text-sm text-text-secondary\">Select a widget to edit</p>\n </div>\n </div>\n )}\n\n {/* Global Save/Discard Footer */}\n {selectedWidget && (\n <div\n style={{\n padding: 'var(--space-cardPadding)',\n borderTop: '1px solid var(--color-border)',\n backgroundColor: 'var(--color-bg-sunken)',\n flexShrink: 0,\n }}\n >\n {/* Status indicator */}\n {hasUnsavedChanges && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-iconGap)',\n marginBottom: 'var(--space-controlGap)',\n padding: 'var(--space-controlGap)',\n backgroundColor: 'var(--color-status-warning-bgSubtle, rgba(251, 191, 36, 0.1))',\n borderRadius: 'var(--radius-button)',\n border: '1px solid var(--color-status-warning-border, rgba(251, 191, 36, 0.3))',\n }}\n >\n <div\n style={{\n width: '8px',\n height: '8px',\n borderRadius: '50%',\n backgroundColor: 'var(--color-status-warning-bg)',\n flexShrink: 0,\n }}\n />\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-status-warning-text, #92400e)',\n fontWeight: 'var(--font-weight-medium)',\n }}\n >\n You have unsaved changes\n </span>\n </div>\n )}\n\n {saveStatus === 'saved' && !hasUnsavedChanges && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-iconGap)',\n marginBottom: 'var(--space-controlGap)',\n padding: 'var(--space-controlGap)',\n backgroundColor: 'var(--color-status-success-bgSubtle, rgba(34, 197, 94, 0.1))',\n borderRadius: 'var(--radius-button)',\n border: '1px solid var(--color-status-success-border, rgba(34, 197, 94, 0.3))',\n }}\n >\n <Check\n style={{\n width: 'var(--size-icon-sm)',\n height: 'var(--size-icon-sm)',\n color: 'var(--color-status-success-text)',\n flexShrink: 0,\n }}\n />\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-status-success-text)',\n fontWeight: 'var(--font-weight-medium)',\n }}\n >\n All changes saved\n </span>\n </div>\n )}\n\n {saveStatus === 'error' && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-iconGap)',\n marginBottom: 'var(--space-controlGap)',\n padding: 'var(--space-controlGap)',\n backgroundColor: 'var(--color-status-error-bgSubtle)',\n borderRadius: 'var(--radius-button)',\n border: '1px solid var(--color-status-error-border)',\n }}\n >\n <X\n style={{\n width: 'var(--size-icon-sm)',\n height: 'var(--size-icon-sm)',\n color: 'var(--color-status-error-text)',\n flexShrink: 0,\n }}\n />\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-status-error-text)',\n fontWeight: 'var(--font-weight-medium)',\n }}\n >\n Failed to save changes\n </span>\n </div>\n )}\n\n {/* Action buttons */}\n <div style={{ display: 'flex', gap: 'var(--space-controlGap)' }}>\n <Button\n onClick={handleSaveAll}\n disabled={saveStatus === 'saving' || !hasUnsavedChanges}\n style={{\n flex: 1,\n height: 'var(--size-controlHeight-md)',\n backgroundColor: hasUnsavedChanges ? 'var(--color-action-primary-bg)' : undefined,\n opacity: hasUnsavedChanges ? 1 : 0.5,\n }}\n >\n {saveStatus === 'saving' ? (\n <span style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <Spinner style={{ width: 'var(--size-icon-sm)', height: 'var(--size-icon-sm)' }} />\n Saving...\n </span>\n ) : (\n <span style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <Check style={{ width: 'var(--size-icon-sm)', height: 'var(--size-icon-sm)' }} />\n Save Changes\n </span>\n )}\n </Button>\n <Button\n variant=\"outline\"\n onClick={handleDiscardAll}\n disabled={saveStatus === 'saving' || !hasUnsavedChanges}\n style={{\n height: 'var(--size-controlHeight-md)',\n opacity: hasUnsavedChanges ? 1 : 0.5,\n }}\n >\n <X style={{ width: 'var(--size-icon-sm)', height: 'var(--size-icon-sm)' }} />\n Discard\n </Button>\n </div>\n </div>\n )}\n\n <ActionConfigDialog\n isOpen={isActionDialogOpen}\n action={editingAction}\n isLoading={actionSaving}\n onClose={() => {\n setIsActionDialogOpen(false);\n setEditingAction(undefined);\n }}\n onSave={handleSaveAction}\n />\n </SheetContent>\n </Sheet>\n );\n});\n\nexport default PropertiesPanel;\n"],"mappings":"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"}
@@ -142,6 +142,7 @@ var e = {
142
142
  category: "Visualization",
143
143
  component: null,
144
144
  defaultConfig: {
145
+ chartType: "funnel",
145
146
  showLabels: !0,
146
147
  showValues: !0,
147
148
  showPercentages: !0,