@burdenoff/microfe-bigconsole 2026.729.1 → 2026.729.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/dist/bigconsole/components/DrilldownDashboardRenderer.js +1 -1
  2. package/dist/bigconsole/components/DrilldownDashboardRenderer.js.map +1 -1
  3. package/dist/bigconsole/components/builder/inspector/DataBindingSection.js +4 -4
  4. package/dist/bigconsole/components/builder/inspector/DataBindingSection.js.map +1 -1
  5. package/dist/bigconsole/components/datasink/CacheTTLSelector.js +5 -5
  6. package/dist/bigconsole/components/datasink/CacheTTLSelector.js.map +1 -1
  7. package/dist/bigconsole/components/datasink/DataSinkCard.js +3 -3
  8. package/dist/bigconsole/components/datasink/DataSinkCard.js.map +1 -1
  9. package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js +4 -4
  10. package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js.map +1 -1
  11. package/dist/bigconsole/components/datasink/DataSinkStatusBadge.js +6 -6
  12. package/dist/bigconsole/components/datasink/DataSinkStatusBadge.js.map +1 -1
  13. package/dist/bigconsole/components/datasink/LinkedWorkflowsPanel.js +9 -9
  14. package/dist/bigconsole/components/datasink/LinkedWorkflowsPanel.js.map +1 -1
  15. package/dist/bigconsole/components/datasink/RefreshTypeSelector.js +2 -2
  16. package/dist/bigconsole/components/datasink/RefreshTypeSelector.js.map +1 -1
  17. package/dist/bigconsole/components/datasink/SetupStateBadge.js +8 -8
  18. package/dist/bigconsole/components/datasink/SetupStateBadge.js.map +1 -1
  19. package/dist/bigconsole/components/datasink/WorkflowStatusPanel.js +13 -13
  20. package/dist/bigconsole/components/datasink/WorkflowStatusPanel.js.map +1 -1
  21. package/dist/bigconsole/components/parser/DataSinkSelector.js +2 -2
  22. package/dist/bigconsole/components/parser/DataSinkSelector.js.map +1 -1
  23. package/dist/bigconsole/components/parser/ExpressionEditor.js +1 -1
  24. package/dist/bigconsole/components/parser/ExpressionEditor.js.map +1 -1
  25. package/dist/bigconsole/components/parser/ParserCard.js +1 -1
  26. package/dist/bigconsole/components/parser/ParserCard.js.map +1 -1
  27. package/dist/bigconsole/components/parser/ParserSelector.js +2 -2
  28. package/dist/bigconsole/components/parser/ParserSelector.js.map +1 -1
  29. package/dist/bigconsole/components/parser/ParserStatusBadge.js +2 -2
  30. package/dist/bigconsole/components/parser/ParserStatusBadge.js.map +1 -1
  31. package/dist/bigconsole/components/pipeline/PipelineCard.js +2 -2
  32. package/dist/bigconsole/components/pipeline/PipelineCard.js.map +1 -1
  33. package/dist/bigconsole/components/pipeline/PipelineDeleteDialog.js +5 -5
  34. package/dist/bigconsole/components/pipeline/PipelineDeleteDialog.js.map +1 -1
  35. package/dist/bigconsole/components/pipeline/PipelineStatusBadge.js +3 -3
  36. package/dist/bigconsole/components/pipeline/PipelineStatusBadge.js.map +1 -1
  37. package/dist/bigconsole/components/widgets/ActionConfigDialog.js +412 -305
  38. package/dist/bigconsole/components/widgets/ActionConfigDialog.js.map +1 -1
  39. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js +1 -1
  40. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js.map +1 -1
  41. package/dist/bigconsole/components/widgets/PropertiesPanel.js +484 -423
  42. package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
  43. package/dist/bigconsole/components/widgets/WidgetErrorBoundary.js +2 -2
  44. package/dist/bigconsole/components/widgets/WidgetErrorBoundary.js.map +1 -1
  45. package/dist/bigconsole/components/widgets/WidgetMenu.js +1 -1
  46. package/dist/bigconsole/components/widgets/WidgetMenu.js.map +1 -1
  47. package/dist/bigconsole/components/widgets/adaptive-card/AdaptiveCardWidget.js +3 -3
  48. package/dist/bigconsole/components/widgets/adaptive-card/AdaptiveCardWidget.js.map +1 -1
  49. package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js +1 -1
  50. package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js.map +1 -1
  51. package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js +3 -3
  52. package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js.map +1 -1
  53. package/dist/bigconsole/components/widgets/heatmap/HeatmapWidget.js +52 -32
  54. package/dist/bigconsole/components/widgets/heatmap/HeatmapWidget.js.map +1 -1
  55. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +3 -3
  56. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js.map +1 -1
  57. package/dist/bigconsole/components/widgets/kpi/KPIWidget.js +1 -1
  58. package/dist/bigconsole/components/widgets/kpi/KPIWidget.js.map +1 -1
  59. package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js +2 -2
  60. package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js.map +1 -1
  61. package/dist/bigconsole/components/widgets/list/ListItem.js +3 -3
  62. package/dist/bigconsole/components/widgets/list/ListItem.js.map +1 -1
  63. package/dist/bigconsole/components/widgets/metric-card/ComparisonBadge.js +1 -1
  64. package/dist/bigconsole/components/widgets/metric-card/ComparisonBadge.js.map +1 -1
  65. package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js +1 -1
  66. package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js.map +1 -1
  67. package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js +6 -6
  68. package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js.map +1 -1
  69. package/dist/bigconsole/components/widgets/metric-card/TrendIndicator.js +1 -1
  70. package/dist/bigconsole/components/widgets/metric-card/TrendIndicator.js.map +1 -1
  71. package/dist/bigconsole/components/widgets/progress/ProgressBar.js +4 -4
  72. package/dist/bigconsole/components/widgets/progress/ProgressBar.js.map +1 -1
  73. package/dist/bigconsole/components/widgets/progress/ProgressConfig.js +1 -1
  74. package/dist/bigconsole/components/widgets/progress/ProgressConfig.js.map +1 -1
  75. package/dist/bigconsole/components/widgets/progress/ProgressWidget.js +1 -1
  76. package/dist/bigconsole/components/widgets/progress/ProgressWidget.js.map +1 -1
  77. package/dist/bigconsole/components/widgets/retention/RetentionWidget.js +2 -2
  78. package/dist/bigconsole/components/widgets/retention/RetentionWidget.js.map +1 -1
  79. package/dist/bigconsole/components/widgets/states/ErrorState.js +2 -2
  80. package/dist/bigconsole/components/widgets/states/ErrorState.js.map +1 -1
  81. package/dist/bigconsole/components/widgets/table/TableConfig.js +2 -2
  82. package/dist/bigconsole/components/widgets/table/TableConfig.js.map +1 -1
  83. package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js +1 -1
  84. package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js.map +1 -1
  85. package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js +6 -6
  86. package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js.map +1 -1
  87. package/dist/bigconsole/components/workflow/WorkflowCard.js +1 -1
  88. package/dist/bigconsole/components/workflow/WorkflowCard.js.map +1 -1
  89. package/dist/bigconsole/components/workflow/WorkflowDeleteDialog.js +5 -5
  90. package/dist/bigconsole/components/workflow/WorkflowDeleteDialog.js.map +1 -1
  91. package/dist/bigconsole/components/workflow/WorkflowStatusBadge.js +6 -6
  92. package/dist/bigconsole/components/workflow/WorkflowStatusBadge.js.map +1 -1
  93. package/dist/bigconsole/hooks/useEventWebhooks.js +6 -2
  94. package/dist/bigconsole/hooks/useEventWebhooks.js.map +1 -1
  95. package/dist/bigconsole/pages/DataSinkBuilderPage.js +17 -17
  96. package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
  97. package/dist/bigconsole/pages/DataSinkViewPage.js +2 -2
  98. package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
  99. package/dist/bigconsole/pages/ParserBuilderPage.js +24 -24
  100. package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
  101. package/dist/bigconsole/pages/ParserViewPage.js +8 -8
  102. package/dist/bigconsole/pages/ParserViewPage.js.map +1 -1
  103. package/dist/bigconsole/pages/PipelineBuilderPage.js +9 -9
  104. package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
  105. package/dist/bigconsole/pages/PipelineViewPage.js +12 -12
  106. package/dist/bigconsole/pages/PipelineViewPage.js.map +1 -1
  107. package/dist/bigconsole/pages/WorkflowViewPage.js +6 -6
  108. package/dist/bigconsole/pages/WorkflowViewPage.js.map +1 -1
  109. package/dist/bigconsole/renderers/adapters/AdaptiveCardRenderer.js +1 -1
  110. package/dist/bigconsole/renderers/adapters/AdaptiveCardRenderer.js.map +1 -1
  111. package/dist/bigconsole/renderers/adapters/BlockKitRenderer.js +2 -2
  112. package/dist/bigconsole/renderers/adapters/BlockKitRenderer.js.map +1 -1
  113. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ActionConfigDialog.js","names":[],"sources":["../../../../src/bigconsole/components/widgets/ActionConfigDialog.tsx"],"sourcesContent":["/**\n * ActionConfigDialog Component (v2.0)\n *\n * Modal dialog for creating/editing widget actions.\n * Uses fe-libs shared UI components and semantic tokens for consistent styling.\n */\n\nimport { type FC, memo, useState, useCallback, useEffect, useRef } from 'react';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} 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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@burdenoff/fe-libs/ui';\nimport { Checkbox } from '@burdenoff/fe-libs/ui';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { Zap, Plus, Pencil } from 'lucide-react';\nimport type {\n WidgetAction,\n ActionType,\n ActionStyle,\n ActionConfirmation,\n CreateWidgetActionInput,\n UpdateWidgetActionInput,\n} from '../../hooks/useWidgetActions';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ActionConfigDialogProps {\n isOpen: boolean;\n action?: WidgetAction;\n isLoading?: boolean;\n onClose: () => void;\n onSave: (data: Omit<CreateWidgetActionInput, 'widgetId'> | UpdateWidgetActionInput) => void;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst ACTION_TYPES: { value: ActionType; label: string }[] = [\n { value: 'BUTTON', label: 'Button' },\n { value: 'LINK', label: 'Link' },\n { value: 'EMIT_EVENT', label: 'Emit Event' },\n { value: 'CUSTOM', label: 'Custom' },\n];\n\nconst ACTION_STYLES: { value: ActionStyle; label: string; color: string }[] = [\n { value: 'PRIMARY', label: 'Primary', color: 'var(--color-action-primary-bg)' },\n { value: 'SECONDARY', label: 'Secondary', color: 'var(--color-action-secondary-bg)' },\n { value: 'SUCCESS', label: 'Success', color: 'var(--color-status-success-bg)' },\n { value: 'WARNING', label: 'Warning', color: 'var(--color-status-warning-bg)' },\n { value: 'DANGER', label: 'Danger', color: 'var(--color-action-danger-bg)' },\n];\n\nconst ICON_OPTIONS = [\n { value: '', label: 'No icon' },\n { value: 'refresh', label: 'Refresh' },\n { value: 'download', label: 'Download' },\n { value: 'upload', label: 'Upload' },\n { value: 'trash', label: 'Trash' },\n { value: 'edit', label: 'Edit' },\n { value: 'plus', label: 'Plus' },\n { value: 'check', label: 'Check' },\n { value: 'eye', label: 'View' },\n { value: 'copy', label: 'Copy' },\n { value: 'share', label: 'Share' },\n { value: 'settings', label: 'Settings' },\n { value: 'filter', label: 'Filter' },\n { value: 'search', label: 'Search' },\n];\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const ActionConfigDialog: FC<ActionConfigDialogProps> = memo(function ActionConfigDialog({\n isOpen,\n action,\n isLoading = false,\n onClose,\n onSave,\n}) {\n const isEditMode = !!action;\n const nameInputRef = useRef<HTMLInputElement>(null);\n\n // Form state\n const [name, setName] = useState('');\n const [label, setLabel] = useState('');\n const [type, setType] = useState<ActionType>('BUTTON');\n const [style, setStyle] = useState<ActionStyle>('PRIMARY');\n const [icon, setIcon] = useState('');\n const [disabled, setDisabled] = useState(false);\n const [hidden, setHidden] = useState(false);\n const [hasConfirmation, setHasConfirmation] = useState(false);\n const [confirmTitle, setConfirmTitle] = useState('Confirm Action');\n const [confirmMessage, setConfirmMessage] = useState('Are you sure you want to proceed?');\n const [confirmLabel, setConfirmLabel] = useState('Confirm');\n const [cancelLabel, setCancelLabel] = useState('Cancel');\n const [error, setError] = useState<string | null>(null);\n\n // Reset form when dialog opens or action changes\n useEffect(() => {\n if (isOpen) {\n if (action) {\n setName(action.name);\n setLabel(action.label);\n setType(action.type);\n setStyle(action.style);\n setIcon(action.icon || '');\n setDisabled(action.disabled);\n setHidden(action.hidden);\n setHasConfirmation(!!action.confirmation);\n if (action.confirmation) {\n setConfirmTitle(action.confirmation.title);\n setConfirmMessage(action.confirmation.message);\n setConfirmLabel(action.confirmation.confirmLabel || 'Confirm');\n setCancelLabel(action.confirmation.cancelLabel || 'Cancel');\n }\n } else {\n setName('');\n setLabel('');\n setType('BUTTON');\n setStyle('PRIMARY');\n setIcon('');\n setDisabled(false);\n setHidden(false);\n setHasConfirmation(false);\n setConfirmTitle('Confirm Action');\n setConfirmMessage('Are you sure you want to proceed?');\n setConfirmLabel('Confirm');\n setCancelLabel('Cancel');\n }\n setError(null);\n setTimeout(() => nameInputRef.current?.focus(), 100);\n }\n }, [isOpen, action]);\n\n // Handle form submission\n const handleSubmit = useCallback(\n (e: React.FormEvent) => {\n e.preventDefault();\n\n const trimmedName = name.trim();\n const trimmedLabel = label.trim();\n\n if (!trimmedName) {\n setError('Action name is required');\n nameInputRef.current?.focus();\n return;\n }\n\n if (!trimmedLabel) {\n setError('Action label is required');\n return;\n }\n\n const confirmation: ActionConfirmation | undefined = hasConfirmation\n ? {\n title: confirmTitle.trim() || 'Confirm Action',\n message: confirmMessage.trim() || 'Are you sure?',\n confirmLabel: confirmLabel.trim() || 'Confirm',\n cancelLabel: cancelLabel.trim() || 'Cancel',\n }\n : undefined;\n\n if (isEditMode && action) {\n const updateData: UpdateWidgetActionInput = {\n id: action.id,\n name: trimmedName,\n label: trimmedLabel,\n type,\n style,\n icon: icon || undefined,\n confirmation: hasConfirmation ? confirmation : null,\n disabled,\n hidden,\n };\n onSave(updateData);\n } else {\n const createData: Omit<CreateWidgetActionInput, 'widgetId'> = {\n name: trimmedName,\n label: trimmedLabel,\n type,\n style,\n icon: icon || undefined,\n confirmation,\n disabled,\n hidden,\n };\n onSave(createData);\n }\n },\n [\n name,\n label,\n type,\n style,\n icon,\n disabled,\n hidden,\n hasConfirmation,\n confirmTitle,\n confirmMessage,\n confirmLabel,\n cancelLabel,\n isEditMode,\n action,\n onSave,\n ]\n );\n\n const getStyleColor = (s: ActionStyle) => {\n return ACTION_STYLES.find((as) => as.value === s)?.color || 'var(--color-action-primary-bg)';\n };\n\n return (\n <Dialog open={isOpen} onOpenChange={(open) => !open && !isLoading && onClose()}>\n <DialogContent style={{ maxWidth: '500px', padding: 0 }}>\n {/* Header */}\n <DialogHeader style={{ padding: 'var(--space-pagePadding) var(--space-pagePadding) 0' }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-formGap)' }}>\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 }}\n >\n {isEditMode ? (\n <Pencil\n style={{\n height: 'var(--size-icon-lg)',\n width: 'var(--size-icon-lg)',\n color: 'var(--color-action-primary-text)',\n }}\n />\n ) : (\n <Zap\n style={{\n height: 'var(--size-icon-lg)',\n width: 'var(--size-icon-lg)',\n color: 'var(--color-action-primary-text)',\n }}\n />\n )}\n </div>\n <div>\n <DialogTitle\n style={{\n fontSize: 'var(--font-size-heading-h4)',\n fontWeight: 'var(--font-weight-bold)',\n color: 'var(--color-text-primary)',\n margin: 0,\n }}\n >\n {isEditMode ? 'Edit Action' : 'Add Action'}\n </DialogTitle>\n <DialogDescription\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-secondary)',\n margin: 'var(--space-controlGap) 0 0 0',\n }}\n >\n {isEditMode ? 'Update the action configuration' : 'Configure a new widget action'}\n </DialogDescription>\n </div>\n </div>\n </DialogHeader>\n\n <form onSubmit={handleSubmit}>\n {/* Form Content */}\n <div style={{ padding: 'var(--space-pagePadding)', maxHeight: '60vh', overflowY: 'auto' }}>\n {/* Error Display */}\n {error && (\n <div\n style={{\n padding: 'var(--space-controlGap)',\n backgroundColor: 'var(--color-status-error-bgSubtle)',\n border: '1px solid var(--color-status-error-border)',\n borderRadius: 'var(--radius-button)',\n marginBottom: 'var(--space-formGap)',\n }}\n >\n <p style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-status-error-text)', margin: 0 }}>\n {error}\n </p>\n </div>\n )}\n\n {/* Name Field */}\n <div style={{ marginBottom: 'var(--space-formGap)' }}>\n <label\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n Name <span style={{ color: 'var(--color-status-error-text)' }}>*</span>\n </label>\n <Input\n ref={nameInputRef}\n value={name}\n onChange={(e) => {\n setName(e.target.value);\n if (error) setError(null);\n }}\n placeholder=\"e.g., refresh, export, delete\"\n disabled={isLoading}\n style={{ height: 'var(--size-controlHeight-md)', fontSize: 'var(--font-size-body-sm)' }}\n />\n <p\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-muted)',\n marginTop: 'var(--space-controlGap)',\n }}\n >\n Unique identifier for this action (used in events)\n </p>\n </div>\n\n {/* Label Field */}\n <div style={{ marginBottom: 'var(--space-formGap)' }}>\n <label\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n Label <span style={{ color: 'var(--color-status-error-text)' }}>*</span>\n </label>\n <Input\n value={label}\n onChange={(e) => setLabel(e.target.value)}\n placeholder=\"e.g., Refresh Data, Export CSV\"\n disabled={isLoading}\n style={{ height: 'var(--size-controlHeight-md)', fontSize: 'var(--font-size-body-sm)' }}\n />\n <p\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-muted)',\n marginTop: 'var(--space-controlGap)',\n }}\n >\n Display text shown on the button\n </p>\n </div>\n\n {/* Type and Style Row */}\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: '1fr 1fr',\n gap: 'var(--space-formGap)',\n marginBottom: 'var(--space-formGap)',\n }}\n >\n {/* Type */}\n <div>\n <label\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n Type\n </label>\n <Select value={type} onValueChange={(v) => setType(v as ActionType)} disabled={isLoading}>\n <SelectTrigger\n style={{ height: 'var(--size-controlHeight-md)', fontSize: 'var(--font-size-body-sm)' }}\n >\n <SelectValue />\n </SelectTrigger>\n <SelectContent\n style={{\n zIndex: 9999,\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 {ACTION_TYPES.map((t) => (\n <SelectItem key={t.value} value={t.value}>\n {t.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {/* Style */}\n <div>\n <label\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n Style\n </label>\n <Select value={style} onValueChange={(v) => setStyle(v as ActionStyle)} disabled={isLoading}>\n <SelectTrigger\n style={{ height: 'var(--size-controlHeight-md)', fontSize: 'var(--font-size-body-sm)' }}\n >\n <SelectValue />\n </SelectTrigger>\n <SelectContent\n style={{\n zIndex: 9999,\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 {ACTION_STYLES.map((s) => (\n <SelectItem key={s.value} value={s.value}>\n {s.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n {/* Style Preview */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n marginBottom: 'var(--space-formGap)',\n padding: 'var(--space-controlGap)',\n backgroundColor: 'var(--color-bg-sunken)',\n borderRadius: 'var(--radius-button)',\n }}\n >\n <span style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-muted)' }}>Preview:</span>\n <button\n type=\"button\"\n style={{\n padding: 'var(--space-controlGap) var(--space-formGap)',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n borderRadius: 'var(--radius-button)',\n backgroundColor: getStyleColor(style),\n color: 'var(--color-action-primary-text)',\n border: 'none',\n cursor: 'default',\n }}\n >\n {label || 'Button'}\n </button>\n </div>\n\n {/* Icon */}\n <div style={{ marginBottom: 'var(--space-formGap)' }}>\n <label\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n Icon\n </label>\n <Select value={icon} onValueChange={setIcon} disabled={isLoading}>\n <SelectTrigger style={{ height: 'var(--size-controlHeight-md)', fontSize: 'var(--font-size-body-sm)' }}>\n <SelectValue placeholder=\"No icon\" />\n </SelectTrigger>\n <SelectContent\n style={{\n zIndex: 9999,\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 maxHeight: '200px',\n }}\n >\n {ICON_OPTIONS.map((i) => (\n <SelectItem key={i.value || 'none'} value={i.value || 'none'}>\n {i.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {/* Visibility Options */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-sectionGap)',\n marginBottom: 'var(--space-formGap)',\n }}\n >\n <label\n style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-controlGap)', cursor: 'pointer' }}\n >\n <Checkbox checked={disabled} onCheckedChange={(c) => setDisabled(c === true)} disabled={isLoading} />\n <span style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-primary)' }}>\n Disabled\n </span>\n </label>\n <label\n style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-controlGap)', cursor: 'pointer' }}\n >\n <Checkbox checked={hidden} onCheckedChange={(c) => setHidden(c === true)} disabled={isLoading} />\n <span style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-primary)' }}>Hidden</span>\n </label>\n </div>\n\n {/* Confirmation Section */}\n <div style={{ paddingTop: 'var(--space-formGap)', borderTop: '1px solid var(--color-border)' }}>\n <label\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n cursor: 'pointer',\n marginBottom: 'var(--space-formGap)',\n }}\n >\n <Checkbox\n checked={hasConfirmation}\n onCheckedChange={(c) => setHasConfirmation(c === true)}\n disabled={isLoading}\n />\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n }}\n >\n Require confirmation\n </span>\n </label>\n\n {hasConfirmation && (\n <div\n style={{\n paddingLeft: 'var(--space-formGap)',\n borderLeft: '2px solid var(--color-border)',\n display: 'flex',\n flexDirection: 'column',\n gap: 'var(--space-controlGap)',\n }}\n >\n <div>\n <label\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n Dialog Title\n </label>\n <Input\n value={confirmTitle}\n onChange={(e) => setConfirmTitle(e.target.value)}\n disabled={isLoading}\n style={{ height: 'var(--size-controlHeight-sm)', fontSize: 'var(--font-size-body-sm)' }}\n />\n </div>\n <div>\n <label\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n Message\n </label>\n <Textarea\n value={confirmMessage}\n onChange={(e) => setConfirmMessage(e.target.value)}\n rows={2}\n disabled={isLoading}\n style={{ fontSize: 'var(--font-size-body-sm)', resize: 'none' }}\n />\n </div>\n <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 'var(--space-controlGap)' }}>\n <div>\n <label\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n Confirm Button\n </label>\n <Input\n value={confirmLabel}\n onChange={(e) => setConfirmLabel(e.target.value)}\n disabled={isLoading}\n style={{ height: 'var(--size-controlHeight-sm)', fontSize: 'var(--font-size-body-sm)' }}\n />\n </div>\n <div>\n <label\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n Cancel Button\n </label>\n <Input\n value={cancelLabel}\n onChange={(e) => setCancelLabel(e.target.value)}\n disabled={isLoading}\n style={{ height: 'var(--size-controlHeight-sm)', fontSize: 'var(--font-size-body-sm)' }}\n />\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Footer */}\n <DialogFooter\n style={{\n padding: 'var(--space-formGap) var(--space-pagePadding)',\n borderTop: '1px solid var(--color-border)',\n backgroundColor: 'var(--color-bg-sunken)',\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 'var(--space-controlGap)',\n }}\n >\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={onClose}\n disabled={isLoading}\n style={{ height: 'var(--size-controlHeight-md)' }}\n >\n Cancel\n </Button>\n <Button\n type=\"submit\"\n disabled={isLoading || !name.trim() || !label.trim()}\n style={{ height: 'var(--size-controlHeight-md)', backgroundColor: 'var(--color-action-primary-bg)' }}\n >\n {isLoading ? (\n <span style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <Spinner style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n Saving...\n </span>\n ) : (\n <span style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n {isEditMode ? (\n <Pencil style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n ) : (\n <Plus style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n )}\n {isEditMode ? 'Update Action' : 'Add Action'}\n </span>\n )}\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n );\n});\n\nexport default ActionConfigDialog;\n"],"mappings":"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"}
1
+ {"version":3,"file":"ActionConfigDialog.js","names":[],"sources":["../../../../src/bigconsole/components/widgets/ActionConfigDialog.tsx"],"sourcesContent":["/**\n * ActionConfigDialog Component (v2.1)\n *\n * Modal dialog for creating/editing widget actions.\n *\n * v2.1 (BOFF-5659): reframed around the *outcome* — \"When clicked, do this\" —\n * instead of the abstract action Type. A button always emits\n * `widget:<name>:clicked`; the dialog now lets the user attach the behaviour\n * inline. Today the two shippable outcomes are:\n * - \"Call a webhook / my API\" → captures a URL + method; the parent pairs the\n * action with an EventWebhookMapping bound to that event (no backend change).\n * - \"Just emit an event\" → the raw emit, for callers wiring their own\n * consumers.\n * The action `name` (the event id) is auto-derived from the label and tucked\n * under Advanced so there is a single required field.\n *\n * Uses fe-libs shared UI components and semantic tokens for consistent styling.\n */\n\nimport { type FC, memo, useState, useCallback, useEffect, useRef } from 'react';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} 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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@burdenoff/fe-libs/ui';\nimport { Checkbox } from '@burdenoff/fe-libs/ui';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { Zap, Plus, Pencil, ChevronDown, ChevronRight } from 'lucide-react';\nimport type {\n WidgetAction,\n ActionStyle,\n ActionConfirmation,\n CreateWidgetActionInput,\n UpdateWidgetActionInput,\n} from '../../hooks/useWidgetActions';\nimport type { HttpMethod } from '../../hooks/useEventWebhooks';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** What should happen when the button is clicked. */\nexport type ActionOutcome = 'WEBHOOK' | 'EMIT';\n\n/** Webhook binding drafted in the dialog and reconciled by the parent. */\nexport interface ActionWebhookDraft {\n url: string;\n method: HttpMethod;\n}\n\n/**\n * The action fields passed to the create/update mutation. The webhook binding\n * is passed as a SEPARATE onSave argument (never embedded here) so it can never\n * leak into the GraphQL input.\n */\nexport type ActionSaveData = Omit<CreateWidgetActionInput, 'widgetId'> | UpdateWidgetActionInput;\n\nexport interface ActionConfigDialogProps {\n isOpen: boolean;\n action?: WidgetAction;\n /** Existing webhook binding for the edited action (prefills the URL field). */\n initialWebhook?: ActionWebhookDraft | null;\n isLoading?: boolean;\n /** A save failure from the parent (action or webhook mutation) to surface inline. */\n saveError?: string | null;\n onClose: () => void;\n /** `webhook` is the paired binding, or `null` to remove any existing one. */\n onSave: (data: ActionSaveData, webhook: ActionWebhookDraft | null) => void;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst OUTCOMES: { value: ActionOutcome; label: string; hint: string }[] = [\n {\n value: 'WEBHOOK',\n label: 'Call a webhook / my API',\n hint: 'Sends an HTTP request to the URL below every time the button is clicked.',\n },\n {\n value: 'EMIT',\n label: 'Just emit an event (advanced)',\n hint: 'Emits widget:<name>:clicked. Wire it up yourself in the Webhooks/Events section.',\n },\n];\n\nconst HTTP_METHODS: HttpMethod[] = ['POST', 'GET', 'PUT', 'PATCH', 'DELETE'];\n\nconst ACTION_STYLES: { value: ActionStyle; label: string; color: string }[] = [\n { value: 'PRIMARY', label: 'Primary', color: 'var(--color-action-primary-bg)' },\n { value: 'SECONDARY', label: 'Secondary', color: 'var(--color-action-secondary-bg)' },\n { value: 'SUCCESS', label: 'Success', color: 'var(--color-status-success-bg)' },\n { value: 'WARNING', label: 'Warning', color: 'var(--color-status-warning-bg)' },\n { value: 'DANGER', label: 'Danger', color: 'var(--color-action-danger-bg)' },\n];\n\nconst ICON_OPTIONS = [\n { value: '', label: 'No icon' },\n { value: 'refresh', label: 'Refresh' },\n { value: 'download', label: 'Download' },\n { value: 'upload', label: 'Upload' },\n { value: 'trash', label: 'Trash' },\n { value: 'edit', label: 'Edit' },\n { value: 'plus', label: 'Plus' },\n { value: 'check', label: 'Check' },\n { value: 'eye', label: 'View' },\n { value: 'copy', label: 'Copy' },\n { value: 'share', label: 'Share' },\n { value: 'settings', label: 'Settings' },\n { value: 'filter', label: 'Filter' },\n { value: 'search', label: 'Search' },\n];\n\n// Derive the event-id (action name) from a human label: \"Refresh Data\" -> \"refresh_data\".\nfunction slugifyName(label: string): string {\n return label\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '_')\n .replace(/^_+|_+$/g, '');\n}\n\nconst labelStyle: React.CSSProperties = {\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n marginBottom: 'var(--space-controlGap)',\n};\n\nconst hintStyle: React.CSSProperties = {\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-muted)',\n marginTop: 'var(--space-controlGap)',\n};\n\nconst selectContentStyle: React.CSSProperties = {\n zIndex: 9999,\n backgroundColor: 'var(--color-overlay-popoverBg, var(--color-bg-surface))',\n border: '1px solid var(--color-border)',\n boxShadow: 'var(--shadow-elevation-3)',\n borderRadius: 'var(--radius-button)',\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const ActionConfigDialog: FC<ActionConfigDialogProps> = memo(function ActionConfigDialog({\n isOpen,\n action,\n initialWebhook,\n isLoading = false,\n saveError,\n onClose,\n onSave,\n}) {\n const isEditMode = !!action;\n const labelInputRef = useRef<HTMLInputElement>(null);\n // True once the user touches the webhook fields, so a late-arriving\n // `initialWebhook` fetch can seed the form without clobbering in-progress edits.\n const webhookTouchedRef = useRef(false);\n\n // Form state\n const [label, setLabel] = useState('');\n const [name, setName] = useState('');\n const [nameEdited, setNameEdited] = useState(false);\n const [style, setStyle] = useState<ActionStyle>('PRIMARY');\n const [icon, setIcon] = useState('');\n const [outcome, setOutcome] = useState<ActionOutcome>('WEBHOOK');\n const [webhookUrl, setWebhookUrl] = useState('');\n const [webhookMethod, setWebhookMethod] = useState<HttpMethod>('POST');\n const [disabled, setDisabled] = useState(false);\n const [hidden, setHidden] = useState(false);\n const [showAdvanced, setShowAdvanced] = useState(false);\n const [hasConfirmation, setHasConfirmation] = useState(false);\n const [confirmTitle, setConfirmTitle] = useState('Confirm Action');\n const [confirmMessage, setConfirmMessage] = useState('Are you sure you want to proceed?');\n const [confirmLabel, setConfirmLabel] = useState('Confirm');\n const [cancelLabel, setCancelLabel] = useState('Cancel');\n const [error, setError] = useState<string | null>(null);\n\n // Reset form when the dialog opens or the edited action changes. Deliberately\n // does NOT depend on `initialWebhook` — that fetch can settle after the dialog\n // is open, and re-running this would wipe the user's in-progress edits (#6).\n // The webhook fields are seeded by the separate effect below.\n useEffect(() => {\n if (!isOpen) return;\n\n webhookTouchedRef.current = false;\n setWebhookUrl('');\n setWebhookMethod('POST');\n\n if (action) {\n setLabel(action.label);\n setName(action.name);\n setNameEdited(false);\n setStyle(action.style);\n setIcon(action.icon || '');\n setDisabled(action.disabled);\n setHidden(action.hidden);\n // Default to \"emit\"; the seed effect flips to WEBHOOK if a mapping exists.\n setOutcome('EMIT');\n setHasConfirmation(!!action.confirmation);\n if (action.confirmation) {\n setConfirmTitle(action.confirmation.title);\n setConfirmMessage(action.confirmation.message);\n setConfirmLabel(action.confirmation.confirmLabel || 'Confirm');\n setCancelLabel(action.confirmation.cancelLabel || 'Cancel');\n } else {\n setConfirmTitle('Confirm Action');\n setConfirmMessage('Are you sure you want to proceed?');\n setConfirmLabel('Confirm');\n setCancelLabel('Cancel');\n }\n } else {\n setLabel('');\n setName('');\n setNameEdited(false);\n setStyle('PRIMARY');\n setIcon('');\n setOutcome('WEBHOOK');\n setDisabled(false);\n setHidden(false);\n setHasConfirmation(false);\n setConfirmTitle('Confirm Action');\n setConfirmMessage('Are you sure you want to proceed?');\n setConfirmLabel('Confirm');\n setCancelLabel('Cancel');\n }\n setShowAdvanced(false);\n setError(null);\n // Focus the label after the dialog paints — a double rAF is more reliable than\n // a magic setTimeout delay and doesn't race the open animation.\n const raf = requestAnimationFrame(() => requestAnimationFrame(() => labelInputRef.current?.focus()));\n return () => cancelAnimationFrame(raf);\n }, [isOpen, action]);\n\n // Seed the webhook fields from the (possibly late-arriving) mapping fetch,\n // unless the user has already started editing them.\n useEffect(() => {\n if (!isOpen || !initialWebhook || webhookTouchedRef.current) return;\n setOutcome('WEBHOOK');\n setWebhookUrl(initialWebhook.url);\n setWebhookMethod(initialWebhook.method);\n }, [isOpen, initialWebhook]);\n\n // Keep the auto-derived name in sync with the label until the user overrides it.\n const handleLabelChange = useCallback(\n (value: string) => {\n setLabel(value);\n if (!nameEdited) setName(slugifyName(value));\n if (error) setError(null);\n },\n [nameEdited, error]\n );\n\n const handleSubmit = useCallback(\n (e: React.FormEvent) => {\n e.preventDefault();\n\n const trimmedLabel = label.trim();\n if (!trimmedLabel) {\n setError('Button label is required');\n labelInputRef.current?.focus();\n return;\n }\n\n // The action name is the event id (webhook contract). It is set once at\n // creation and never rewritten on edit — re-slugifying a stored name like\n // `refresh-v2` would silently change `widget:refresh-v2:clicked` and break\n // existing bindings/consumers (#1).\n const finalName =\n isEditMode && action ? action.name : slugifyName(nameEdited ? name : label) || slugifyName(label);\n if (!finalName) {\n setError('Enter a label using letters or numbers');\n return;\n }\n\n if (outcome === 'WEBHOOK') {\n const url = webhookUrl.trim();\n if (!url) {\n setError('Enter the URL to call when the button is clicked');\n return;\n }\n if (!/^https?:\\/\\//i.test(url)) {\n setError('Webhook URL must start with http:// or https://');\n return;\n }\n }\n\n const confirmation: ActionConfirmation | undefined = hasConfirmation\n ? {\n title: confirmTitle.trim() || 'Confirm Action',\n message: confirmMessage.trim() || 'Are you sure?',\n confirmLabel: confirmLabel.trim() || 'Confirm',\n cancelLabel: cancelLabel.trim() || 'Cancel',\n }\n : undefined;\n\n const webhook: ActionWebhookDraft | null =\n outcome === 'WEBHOOK' ? { url: webhookUrl.trim(), method: webhookMethod } : null;\n\n if (isEditMode && action) {\n const updateData: ActionSaveData = {\n id: action.id,\n name: finalName,\n label: trimmedLabel,\n // Webhook/emit outcomes must be a BUTTON so the click runs onAction and\n // emits the event. Saving a stale LINK type would render an <a> that\n // bypasses onAction, so the webhook would never fire (#3).\n type: 'BUTTON',\n style,\n icon: icon || undefined,\n confirmation: hasConfirmation ? confirmation : null,\n disabled,\n hidden,\n };\n onSave(updateData, webhook);\n } else {\n const createData: ActionSaveData = {\n name: finalName,\n label: trimmedLabel,\n // Webhook/emit outcomes must be a BUTTON so the click runs onAction and\n // emits the event. Saving a stale LINK type would render an <a> that\n // bypasses onAction, so the webhook would never fire (#3).\n type: 'BUTTON',\n style,\n icon: icon || undefined,\n confirmation,\n disabled,\n hidden,\n };\n onSave(createData, webhook);\n }\n },\n [\n label,\n name,\n nameEdited,\n outcome,\n webhookUrl,\n webhookMethod,\n style,\n icon,\n disabled,\n hidden,\n hasConfirmation,\n confirmTitle,\n confirmMessage,\n confirmLabel,\n cancelLabel,\n isEditMode,\n action,\n onSave,\n ]\n );\n\n const getStyleColor = (s: ActionStyle) =>\n ACTION_STYLES.find((as) => as.value === s)?.color || 'var(--color-action-primary-bg)';\n\n const activeOutcome = OUTCOMES.find((o) => o.value === outcome);\n\n return (\n <Dialog open={isOpen} onOpenChange={(open) => !open && !isLoading && onClose()}>\n <DialogContent style={{ maxWidth: '500px', padding: 0 }}>\n {/* Header */}\n <DialogHeader style={{ padding: 'var(--space-pagePadding) var(--space-pagePadding) 0' }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-formGap)' }}>\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 }}\n >\n {isEditMode ? (\n <Pencil\n style={{\n height: 'var(--size-icon-lg)',\n width: 'var(--size-icon-lg)',\n color: 'var(--color-action-primary-text)',\n }}\n />\n ) : (\n <Zap\n style={{\n height: 'var(--size-icon-lg)',\n width: 'var(--size-icon-lg)',\n color: 'var(--color-action-primary-text)',\n }}\n />\n )}\n </div>\n <div>\n <DialogTitle\n style={{\n fontSize: 'var(--font-size-heading-h4)',\n fontWeight: 'var(--font-weight-bold)',\n color: 'var(--color-text-primary)',\n margin: 0,\n }}\n >\n {isEditMode ? 'Edit Button' : 'Add Button'}\n </DialogTitle>\n <DialogDescription\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-secondary)',\n margin: 'var(--space-controlGap) 0 0 0',\n }}\n >\n {isEditMode ? 'Update the button and what it does' : 'Add a button and choose what it does'}\n </DialogDescription>\n </div>\n </div>\n </DialogHeader>\n\n <form onSubmit={handleSubmit}>\n {/* Form Content */}\n <div style={{ padding: 'var(--space-pagePadding)', maxHeight: '60vh', overflowY: 'auto' }}>\n {/* Error Display — local validation error or a save failure from the parent. */}\n {(error || saveError) && (\n <div\n style={{\n padding: 'var(--space-controlGap)',\n backgroundColor: 'var(--color-status-error-bgSubtle)',\n border: '1px solid var(--color-status-error-border)',\n borderRadius: 'var(--radius-button)',\n marginBottom: 'var(--space-formGap)',\n }}\n >\n <p style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-status-error-text)', margin: 0 }}>\n {error || saveError}\n </p>\n </div>\n )}\n\n {/* Label Field */}\n <div style={{ marginBottom: 'var(--space-formGap)' }}>\n <label style={labelStyle}>\n Button label <span style={{ color: 'var(--color-status-error-text)' }}>*</span>\n </label>\n <Input\n ref={labelInputRef}\n value={label}\n onChange={(e) => handleLabelChange(e.target.value)}\n placeholder=\"e.g., Refresh Data, Export CSV\"\n disabled={isLoading}\n style={{ height: 'var(--size-controlHeight-md)', fontSize: 'var(--font-size-body-sm)' }}\n />\n <p style={hintStyle}>Text shown on the button</p>\n </div>\n\n {/* Style + Icon Row */}\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: '1fr 1fr',\n gap: 'var(--space-formGap)',\n marginBottom: 'var(--space-formGap)',\n }}\n >\n <div>\n <label style={labelStyle}>Style</label>\n <Select value={style} onValueChange={(v) => setStyle(v as ActionStyle)} disabled={isLoading}>\n <SelectTrigger\n style={{ height: 'var(--size-controlHeight-md)', fontSize: 'var(--font-size-body-sm)' }}\n >\n <SelectValue />\n </SelectTrigger>\n <SelectContent style={selectContentStyle}>\n {ACTION_STYLES.map((s) => (\n <SelectItem key={s.value} value={s.value}>\n {s.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div>\n <label style={labelStyle}>Icon</label>\n <Select value={icon} onValueChange={setIcon} disabled={isLoading}>\n <SelectTrigger\n style={{ height: 'var(--size-controlHeight-md)', fontSize: 'var(--font-size-body-sm)' }}\n >\n <SelectValue placeholder=\"No icon\" />\n </SelectTrigger>\n <SelectContent style={{ ...selectContentStyle, maxHeight: '200px' }}>\n {ICON_OPTIONS.map((i) => (\n <SelectItem key={i.value || 'none'} value={i.value || 'none'}>\n {i.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n {/* Style Preview */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n marginBottom: 'var(--space-formGap)',\n padding: 'var(--space-controlGap)',\n backgroundColor: 'var(--color-bg-sunken)',\n borderRadius: 'var(--radius-button)',\n }}\n >\n <span style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-muted)' }}>Preview:</span>\n <button\n type=\"button\"\n style={{\n padding: 'var(--space-controlGap) var(--space-formGap)',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n borderRadius: 'var(--radius-button)',\n backgroundColor: getStyleColor(style),\n color: 'var(--color-action-primary-text)',\n border: 'none',\n cursor: 'default',\n }}\n >\n {label || 'Button'}\n </button>\n </div>\n\n {/* When clicked (outcome) */}\n <div style={{ marginBottom: 'var(--space-formGap)' }}>\n <label style={labelStyle}>When clicked</label>\n <Select\n value={outcome}\n onValueChange={(v) => {\n webhookTouchedRef.current = true;\n setOutcome(v as ActionOutcome);\n }}\n disabled={isLoading}\n >\n <SelectTrigger style={{ height: 'var(--size-controlHeight-md)', fontSize: 'var(--font-size-body-sm)' }}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent style={selectContentStyle}>\n {OUTCOMES.map((o) => (\n <SelectItem key={o.value} value={o.value}>\n {o.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {activeOutcome && <p style={hintStyle}>{activeOutcome.hint}</p>}\n </div>\n\n {/* Webhook config (only for the WEBHOOK outcome) */}\n {outcome === 'WEBHOOK' && (\n <div\n style={{\n marginBottom: 'var(--space-formGap)',\n paddingLeft: 'var(--space-formGap)',\n borderLeft: '2px solid var(--color-border)',\n display: 'flex',\n flexDirection: 'column',\n gap: 'var(--space-controlGap)',\n }}\n >\n <div>\n <label style={labelStyle}>\n URL <span style={{ color: 'var(--color-status-error-text)' }}>*</span>\n </label>\n <Input\n value={webhookUrl}\n onChange={(e) => {\n webhookTouchedRef.current = true;\n setWebhookUrl(e.target.value);\n if (error) setError(null);\n }}\n placeholder=\"https://your-service.com/hook\"\n disabled={isLoading}\n style={{ height: 'var(--size-controlHeight-md)', fontSize: 'var(--font-size-body-sm)' }}\n />\n </div>\n <div style={{ maxWidth: '160px' }}>\n <label style={labelStyle}>Method</label>\n <Select\n value={webhookMethod}\n onValueChange={(v) => {\n webhookTouchedRef.current = true;\n setWebhookMethod(v as HttpMethod);\n }}\n disabled={isLoading}\n >\n <SelectTrigger\n style={{ height: 'var(--size-controlHeight-md)', fontSize: 'var(--font-size-body-sm)' }}\n >\n <SelectValue />\n </SelectTrigger>\n <SelectContent style={selectContentStyle}>\n {HTTP_METHODS.map((m) => (\n <SelectItem key={m} value={m}>\n {m}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <p style={hintStyle}>The widget&apos;s current data is sent as the request payload.</p>\n {/^http:\\/\\//i.test(webhookUrl.trim()) && (\n <p style={{ ...hintStyle, color: 'var(--color-status-warning-text)' }}>\n Warning: <code>http://</code> is unencrypted — the widget&apos;s data will be sent in plaintext. Use{' '}\n <code>https://</code> if it may contain anything sensitive.\n </p>\n )}\n </div>\n )}\n\n {/* Confirmation Section */}\n <div style={{ paddingTop: 'var(--space-formGap)', borderTop: '1px solid var(--color-border)' }}>\n <label\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n cursor: 'pointer',\n marginBottom: 'var(--space-formGap)',\n }}\n >\n <Checkbox\n checked={hasConfirmation}\n onCheckedChange={(c) => setHasConfirmation(c === true)}\n disabled={isLoading}\n />\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n }}\n >\n Ask for confirmation first\n </span>\n </label>\n\n {hasConfirmation && (\n <div\n style={{\n paddingLeft: 'var(--space-formGap)',\n borderLeft: '2px solid var(--color-border)',\n display: 'flex',\n flexDirection: 'column',\n gap: 'var(--space-controlGap)',\n }}\n >\n <div>\n <label\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n Dialog Title\n </label>\n <Input\n value={confirmTitle}\n onChange={(e) => setConfirmTitle(e.target.value)}\n disabled={isLoading}\n style={{ height: 'var(--size-controlHeight-sm)', fontSize: 'var(--font-size-body-sm)' }}\n />\n </div>\n <div>\n <label\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n Message\n </label>\n <Textarea\n value={confirmMessage}\n onChange={(e) => setConfirmMessage(e.target.value)}\n rows={2}\n disabled={isLoading}\n style={{ fontSize: 'var(--font-size-body-sm)', resize: 'none' }}\n />\n </div>\n <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 'var(--space-controlGap)' }}>\n <div>\n <label\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n Confirm Button\n </label>\n <Input\n value={confirmLabel}\n onChange={(e) => setConfirmLabel(e.target.value)}\n disabled={isLoading}\n style={{ height: 'var(--size-controlHeight-sm)', fontSize: 'var(--font-size-body-sm)' }}\n />\n </div>\n <div>\n <label\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n Cancel Button\n </label>\n <Input\n value={cancelLabel}\n onChange={(e) => setCancelLabel(e.target.value)}\n disabled={isLoading}\n style={{ height: 'var(--size-controlHeight-sm)', fontSize: 'var(--font-size-body-sm)' }}\n />\n </div>\n </div>\n </div>\n )}\n </div>\n\n {/* Advanced disclosure — event name + visibility */}\n <div style={{ paddingTop: 'var(--space-formGap)', borderTop: '1px solid var(--color-border)' }}>\n <button\n type=\"button\"\n onClick={() => setShowAdvanced((v) => !v)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n background: 'none',\n border: 'none',\n padding: 0,\n cursor: 'pointer',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n }}\n >\n {showAdvanced ? (\n <ChevronDown style={{ height: '14px', width: '14px' }} />\n ) : (\n <ChevronRight style={{ height: '14px', width: '14px' }} />\n )}\n Advanced\n </button>\n\n {showAdvanced && (\n <div\n style={{\n marginTop: 'var(--space-formGap)',\n display: 'flex',\n flexDirection: 'column',\n gap: 'var(--space-formGap)',\n }}\n >\n <div>\n <label style={labelStyle}>Event name (id)</label>\n <Input\n value={isEditMode && action ? action.name : name}\n onChange={(e) => {\n setName(e.target.value);\n setNameEdited(true);\n }}\n placeholder=\"auto from label\"\n // The event id is the webhook/consumer contract; it is fixed\n // once the action exists and cannot be changed on edit (#1).\n disabled={isLoading || isEditMode}\n style={{\n height: 'var(--size-controlHeight-md)',\n fontSize: 'var(--font-size-body-sm)',\n fontFamily: 'var(--font-family-mono)',\n }}\n />\n <p style={hintStyle}>\n Emits{' '}\n <code>\n widget:{isEditMode && action ? action.name : slugifyName(name || label) || '<name>'}:clicked\n </code>\n . {isEditMode ? 'Fixed once created.' : 'Auto-derived from the label.'}\n </p>\n </div>\n\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-sectionGap)' }}>\n <label\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n cursor: 'pointer',\n }}\n >\n <Checkbox\n checked={disabled}\n onCheckedChange={(c) => setDisabled(c === true)}\n disabled={isLoading}\n />\n <span style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-primary)' }}>\n Disabled\n </span>\n </label>\n <label\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n cursor: 'pointer',\n }}\n >\n <Checkbox checked={hidden} onCheckedChange={(c) => setHidden(c === true)} disabled={isLoading} />\n <span style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-primary)' }}>\n Hidden\n </span>\n </label>\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Footer */}\n <DialogFooter\n style={{\n padding: 'var(--space-formGap) var(--space-pagePadding)',\n borderTop: '1px solid var(--color-border)',\n backgroundColor: 'var(--color-bg-sunken)',\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 'var(--space-controlGap)',\n }}\n >\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={onClose}\n disabled={isLoading}\n style={{ height: 'var(--size-controlHeight-md)' }}\n >\n Cancel\n </Button>\n <Button\n type=\"submit\"\n disabled={isLoading || !label.trim()}\n style={{ height: 'var(--size-controlHeight-md)', backgroundColor: 'var(--color-action-primary-bg)' }}\n >\n {isLoading ? (\n <span style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <Spinner style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n Saving...\n </span>\n ) : (\n <span style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n {isEditMode ? (\n <Pencil style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n ) : (\n <Plus style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n )}\n {isEditMode ? 'Update Button' : 'Add Button'}\n </span>\n )}\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n );\n});\n\nexport default ActionConfigDialog;\n"],"mappings":"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"}
@@ -231,7 +231,7 @@ var d = t(function({ widget: t, onChange: d, widgetData: f }) {
231
231
  E.length > 1 && /* @__PURE__ */ c("button", {
232
232
  type: "button",
233
233
  onClick: () => L(t),
234
- className: "p-1 text-text-tertiary hover:text-state-error",
234
+ className: "p-1 text-text-tertiary hover:text-status-error-text",
235
235
  children: /* @__PURE__ */ c("svg", {
236
236
  className: "w-4 h-4",
237
237
  fill: "none",
@@ -1 +1 @@
1
- {"version":3,"file":"DrilldownConfigPanel.js","names":[],"sources":["../../../../src/bigconsole/components/widgets/DrilldownConfigPanel.tsx"],"sourcesContent":["/**\n * DrilldownConfigPanel Component\n *\n * UI for configuring widget drilldown settings.\n * Allows selecting target dashboard, navigation mode, and parameter mappings.\n *\n * v2.0 Features:\n * - passGlobalFilters: Pass current dashboard filters to target\n * - maxDepth: Limit drilldown depth (default: 3)\n * - openIn: Open in same tab or new tab\n * - Field suggestions based on widget data\n */\n\nimport { type FC, memo, useState, useEffect, useCallback, useMemo } from 'react';\nimport { useApolloClient } from '@apollo/client/react';\nimport type { Widget, NavigationMode } from '../../types';\nimport { ListDashboardsDocument } from '../../../generated/wspace-operations';\nimport { DEFAULT_MAX_DEPTH } from '../../hooks/useDrilldown';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface DrilldownConfigPanelProps {\n /** Widget to configure drilldown for */\n widget: Widget;\n /** Callback when drilldown settings change (for tracking unsaved changes) */\n onChange?: (config: DrilldownConfig) => void;\n /** Sample widget data for field suggestions */\n widgetData?: Record<string, unknown>;\n}\n\nexport interface DrilldownConfig {\n enabled: boolean;\n targetDashboardId: string;\n navigationMode: NavigationMode;\n parameterMapping: Record<string, string>;\n /** Whether to pass global filters to target dashboard */\n passGlobalFilters: boolean;\n /** Maximum drilldown depth (default: 3) */\n maxDepth: number;\n /** Open in same tab or new tab (for SAME_WINDOW mode) */\n openIn: 'same' | 'new';\n}\n\ninterface DashboardOption {\n id: string;\n name: string;\n}\n\ninterface ParameterMapping {\n key: string;\n value: string;\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Extract available fields from widget data for field suggestions\n */\nfunction extractFieldPaths(obj: unknown, prefix = ''): string[] {\n if (!obj || typeof obj !== 'object') return [];\n\n const paths: string[] = [];\n\n // Handle arrays - use first element as template\n if (Array.isArray(obj)) {\n if (obj.length > 0 && typeof obj[0] === 'object') {\n return extractFieldPaths(obj[0], prefix);\n }\n return [];\n }\n\n // Handle objects\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n const path = prefix ? `${prefix}.${key}` : key;\n paths.push(path);\n\n // Recurse into nested objects (but not too deep)\n if (value && typeof value === 'object' && !Array.isArray(value) && prefix.split('.').length < 2) {\n paths.push(...extractFieldPaths(value, path));\n }\n }\n\n return paths;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const DrilldownConfigPanel: FC<DrilldownConfigPanelProps> = memo(function DrilldownConfigPanel({\n widget,\n onChange,\n widgetData,\n}) {\n const apolloClient = useApolloClient();\n\n // State\n const [enabled, setEnabled] = useState(widget.drilldown?.enabled ?? false);\n const [targetDashboardId, setTargetDashboardId] = useState(widget.drilldown?.targetDashboardId ?? '');\n const [navigationMode, setNavigationMode] = useState<NavigationMode>(widget.drilldown?.navigationMode ?? 'MODAL');\n const [passGlobalFilters, setPassGlobalFilters] = useState(widget.drilldown?.passGlobalFilters ?? true);\n const [maxDepth, setMaxDepth] = useState(widget.drilldown?.maxDepth ?? DEFAULT_MAX_DEPTH);\n const [openIn, setOpenIn] = useState<'same' | 'new'>(widget.drilldown?.openIn ?? 'same');\n const [parameterMappings, setParameterMappings] = useState<ParameterMapping[]>(() => {\n const mapping = widget.drilldown?.parameterMapping as Record<string, string> | undefined;\n if (mapping) {\n return Object.entries(mapping).map(([key, value]) => ({ key, value }));\n }\n return [{ key: '', value: '' }];\n });\n\n const [dashboards, setDashboards] = useState<DashboardOption[]>([]);\n const [loading, setLoading] = useState(false);\n const [showFieldSuggestions, setShowFieldSuggestions] = useState<number | null>(null);\n\n // Extract available field paths from widget data\n const availableFields = useMemo(() => {\n if (!widgetData) return [];\n\n // Common prefixes for different widget types\n const prefixes = ['row', 'item', 'point', 'selectedData'];\n const fields = extractFieldPaths(widgetData);\n\n // Generate mustache-style suggestions\n const suggestions: string[] = [];\n for (const field of fields) {\n for (const prefix of prefixes) {\n suggestions.push(`{{${prefix}.${field}}}`);\n }\n }\n\n // Add common widget data fields\n suggestions.push('{{widget.value}}', '{{widget.title}}', '{{widget.id}}');\n suggestions.push('{{globals.vars.dateFrom}}', '{{globals.vars.dateTo}}');\n\n return [...new Set(suggestions)];\n }, [widgetData]);\n\n // Notify parent of changes\n const notifyChange = useCallback(() => {\n const parameterMapping: Record<string, string> = {};\n for (const { key, value } of parameterMappings) {\n if (key.trim() && value.trim()) {\n parameterMapping[key.trim()] = value.trim();\n }\n }\n onChange?.({\n enabled,\n targetDashboardId,\n navigationMode,\n parameterMapping,\n passGlobalFilters,\n maxDepth,\n openIn,\n });\n }, [enabled, targetDashboardId, navigationMode, parameterMappings, passGlobalFilters, maxDepth, openIn, onChange]);\n\n // Call notifyChange when any value changes\n useEffect(() => {\n notifyChange();\n }, [\n enabled,\n targetDashboardId,\n navigationMode,\n parameterMappings,\n passGlobalFilters,\n maxDepth,\n openIn,\n notifyChange,\n ]);\n\n // Fetch available dashboards\n useEffect(() => {\n async function fetchDashboards() {\n setLoading(true);\n try {\n const result = await apolloClient.query<{ listDashboards: { edges: Record<string, unknown>[] } }>({\n query: ListDashboardsDocument,\n variables: { first: 100 },\n fetchPolicy: 'cache-first',\n });\n\n const edges = result.data?.listDashboards?.edges || [];\n setDashboards(\n edges.map((edge: Record<string, unknown>) => {\n const node = edge.node as Record<string, unknown>;\n return {\n id: node.id as string,\n name: node.name as string,\n };\n })\n );\n } catch (err) {\n } finally {\n setLoading(false);\n }\n }\n\n fetchDashboards();\n }, [apolloClient]);\n\n // Add parameter mapping row\n const addParameterMapping = useCallback(() => {\n setParameterMappings((prev) => [...prev, { key: '', value: '' }]);\n }, []);\n\n // Remove parameter mapping row\n const removeParameterMapping = useCallback((index: number) => {\n setParameterMappings((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n // Update parameter mapping\n const updateParameterMapping = useCallback((index: number, field: 'key' | 'value', newValue: string) => {\n setParameterMappings((prev) => prev.map((item, i) => (i === index ? { ...item, [field]: newValue } : item)));\n }, []);\n\n return (\n <div className=\"space-y-4 pb-8\">\n {/* Enable Toggle */}\n <div className=\"flex items-center justify-between p-3 rounded-lg border border-border-default bg-bg-surface\">\n <label className=\"text-sm font-medium text-text-primary\">Enable Drilldown</label>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={enabled}\n onClick={() => setEnabled(!enabled)}\n className={`\n relative inline-flex h-6 w-11 items-center rounded-full transition-colors cursor-pointer border\n ${enabled ? 'bg-action-primary-bg border-action-primary-bg' : 'bg-gray-300 border-gray-400'}\n `}\n >\n <span\n className={`\n inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform\n ${enabled ? 'translate-x-6' : 'translate-x-1'}\n `}\n />\n </button>\n </div>\n\n {enabled && (\n <>\n {/* Target Dashboard */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Target Dashboard</label>\n <select\n value={targetDashboardId}\n onChange={(e) => setTargetDashboardId(e.target.value)}\n disabled={loading}\n className=\"w-full px-3 py-2 rounded-md border border-border-default bg-bg-surface text-text-primary text-sm focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n <option value=\"\">Select a dashboard...</option>\n {dashboards\n .filter((d) => d.id !== widget.dashboardId) // Exclude current dashboard\n .map((dashboard) => (\n <option key={dashboard.id} value={dashboard.id}>\n {dashboard.name}\n </option>\n ))}\n </select>\n </div>\n\n {/* Navigation Mode */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Navigation Mode</label>\n <div className=\"flex gap-2\">\n {(['MODAL', 'NEW_TAB', 'SAME_WINDOW'] as NavigationMode[]).map((mode) => (\n <button\n key={mode}\n type=\"button\"\n onClick={() => setNavigationMode(mode)}\n className={`\n flex-1 px-3 py-2 rounded-md text-sm font-medium transition-colors\n ${\n navigationMode === mode\n ? 'bg-action-primary-bg text-white'\n : 'bg-bg-sunken text-text-secondary hover:bg-bg-sunken/80'\n }\n `}\n >\n {mode === 'MODAL' && 'Modal'}\n {mode === 'NEW_TAB' && 'New Tab'}\n {mode === 'SAME_WINDOW' && 'Same Window'}\n </button>\n ))}\n </div>\n <p className=\"text-xs text-text-tertiary mt-1\">\n {navigationMode === 'MODAL' && 'Opens target dashboard in a modal overlay'}\n {navigationMode === 'NEW_TAB' && 'Opens target dashboard in a new browser tab'}\n {navigationMode === 'SAME_WINDOW' && 'Navigates to target dashboard in current window'}\n </p>\n </div>\n\n {/* Parameter Mappings */}\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <label className=\"text-sm font-medium text-text-primary\">Parameter Mappings</label>\n <button\n type=\"button\"\n onClick={addParameterMapping}\n className=\"text-xs text-action-primary-text hover:underline\"\n >\n + Add Parameter\n </button>\n </div>\n\n <div className=\"space-y-2\">\n {parameterMappings.map((mapping, index) => (\n <div key={index} className=\"relative\">\n <div className=\"flex gap-2 items-center\">\n <input\n type=\"text\"\n value={mapping.key}\n onChange={(e) => updateParameterMapping(index, 'key', e.target.value)}\n placeholder=\"Parameter name\"\n className=\"flex-1 px-2 py-1.5 rounded border border-border-default bg-bg-surface text-text-primary text-sm focus:outline-none focus:ring-1 focus:ring-action-primary-bg\"\n />\n <span className=\"text-text-tertiary\">=</span>\n <div className=\"flex-1 relative\">\n <input\n type=\"text\"\n value={mapping.value}\n onChange={(e) => updateParameterMapping(index, 'value', e.target.value)}\n onFocus={() => setShowFieldSuggestions(index)}\n onBlur={() => setTimeout(() => setShowFieldSuggestions(null), 200)}\n placeholder=\"{{row.field}} or static\"\n className=\"w-full px-2 py-1.5 rounded border border-border-default bg-bg-surface text-text-primary text-sm focus:outline-none focus:ring-1 focus:ring-action-primary-bg\"\n />\n {/* Field suggestions dropdown */}\n {showFieldSuggestions === index && availableFields.length > 0 && (\n <div className=\"absolute z-10 top-full left-0 right-0 mt-1 max-h-40 overflow-y-auto bg-bg-surface border border-border-default rounded-md shadow-lg\">\n {availableFields.slice(0, 10).map((field) => (\n <button\n key={field}\n type=\"button\"\n onClick={() => {\n updateParameterMapping(index, 'value', field);\n setShowFieldSuggestions(null);\n }}\n className=\"w-full px-3 py-1.5 text-left text-xs text-text-primary hover:bg-bg-sunken font-mono\"\n >\n {field}\n </button>\n ))}\n </div>\n )}\n </div>\n {parameterMappings.length > 1 && (\n <button\n type=\"button\"\n onClick={() => removeParameterMapping(index)}\n className=\"p-1 text-text-tertiary hover:text-state-error\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n )}\n </div>\n </div>\n ))}\n </div>\n\n <p className=\"text-xs text-text-tertiary mt-2\">\n Use <code className=\"px-1 bg-bg-sunken rounded\">{'{{row.field}}'}</code> for dynamic values or enter\n static text.\n <br />\n Examples: <code className=\"px-1 bg-bg-sunken rounded\">{'{{row.category}}'}</code>,{' '}\n <code className=\"px-1 bg-bg-sunken rounded\">{'{{item.id}}'}</code>,{' '}\n <code className=\"px-1 bg-bg-sunken rounded\">{'{{globals.vars.dateFrom}}'}</code>\n </p>\n </div>\n\n {/* Advanced Options */}\n <div className=\"border-t border-border-default pt-4 mt-4\">\n <h4 className=\"text-sm font-medium text-text-primary mb-3\">Advanced Options</h4>\n\n {/* Pass Global Filters */}\n <div className=\"flex items-center justify-between p-2 rounded bg-bg-sunken mb-3\">\n <div>\n <label className=\"text-sm text-text-primary\">Pass Global Filters</label>\n <p className=\"text-xs text-text-tertiary\">Include current dashboard filters in drilldown</p>\n </div>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={passGlobalFilters}\n onClick={() => setPassGlobalFilters(!passGlobalFilters)}\n className={`\n relative inline-flex h-5 w-9 items-center rounded-full transition-colors cursor-pointer border\n ${passGlobalFilters ? 'bg-action-primary-bg border-action-primary-bg' : 'bg-gray-300 border-gray-400'}\n `}\n >\n <span\n className={`\n inline-block h-3 w-3 transform rounded-full bg-white shadow transition-transform\n ${passGlobalFilters ? 'translate-x-5' : 'translate-x-1'}\n `}\n />\n </button>\n </div>\n\n {/* Max Depth */}\n <div className=\"flex items-center justify-between p-2 rounded bg-bg-sunken mb-3\">\n <div>\n <label className=\"text-sm text-text-primary\">Max Drilldown Depth</label>\n <p className=\"text-xs text-text-tertiary\">Limit nested drilldown levels</p>\n </div>\n <select\n value={maxDepth}\n onChange={(e) => setMaxDepth(Number(e.target.value))}\n className=\"w-16 px-2 py-1 rounded border border-border-default bg-bg-surface text-text-primary text-sm\"\n >\n {[1, 2, 3, 4, 5].map((n) => (\n <option key={n} value={n}>\n {n}\n </option>\n ))}\n </select>\n </div>\n\n {/* Open In (only for SAME_WINDOW mode) */}\n {navigationMode === 'SAME_WINDOW' && (\n <div className=\"flex items-center justify-between p-2 rounded bg-bg-sunken\">\n <div>\n <label className=\"text-sm text-text-primary\">Open In</label>\n <p className=\"text-xs text-text-tertiary\">Tab behavior for navigation</p>\n </div>\n <div className=\"flex gap-1\">\n <button\n type=\"button\"\n onClick={() => setOpenIn('same')}\n className={`\n px-2 py-1 rounded text-xs font-medium transition-colors\n ${\n openIn === 'same'\n ? 'bg-action-primary-bg text-white'\n : 'bg-bg-surface text-text-secondary hover:bg-bg-sunken/80 border border-border-default'\n }\n `}\n >\n Same Tab\n </button>\n <button\n type=\"button\"\n onClick={() => setOpenIn('new')}\n className={`\n px-2 py-1 rounded text-xs font-medium transition-colors\n ${\n openIn === 'new'\n ? 'bg-action-primary-bg text-white'\n : 'bg-bg-surface text-text-secondary hover:bg-bg-sunken/80 border border-border-default'\n }\n `}\n >\n New Tab\n </button>\n </div>\n </div>\n )}\n </div>\n </>\n )}\n\n {/* Info when drilldown will be removed */}\n {!enabled && widget.drilldown?.id && (\n <div className=\"p-2 rounded bg-amber-100 text-amber-800 text-sm\">\n Drilldown will be removed when you save changes.\n </div>\n )}\n </div>\n );\n});\n\nexport default DrilldownConfigPanel;\n"],"mappings":";;;;;;AA8DA,SAAS,EAAkB,GAAc,IAAS,IAAc;AAC9D,KAAI,CAAC,KAAO,OAAO,KAAQ,SAAU,QAAO,EAAE;CAE9C,IAAM,IAAkB,EAAE;AAG1B,KAAI,MAAM,QAAQ,EAAI,CAIpB,QAHI,EAAI,SAAS,KAAK,OAAO,EAAI,MAAO,WAC/B,EAAkB,EAAI,IAAI,EAAO,GAEnC,EAAE;AAIX,MAAK,IAAM,CAAC,GAAK,MAAU,OAAO,QAAQ,EAA+B,EAAE;EACzE,IAAM,IAAO,IAAS,GAAG,EAAO,GAAG,MAAQ;AAI3C,EAHA,EAAM,KAAK,EAAK,EAGZ,KAAS,OAAO,KAAU,YAAY,CAAC,MAAM,QAAQ,EAAM,IAAI,EAAO,MAAM,IAAI,CAAC,SAAS,KAC5F,EAAM,KAAK,GAAG,EAAkB,GAAO,EAAK,CAAC;;AAIjD,QAAO;;AAOT,IAAa,IAAsD,EAAK,SAA8B,EACpG,WACA,aACA,iBACC;CACD,IAAM,IAAe,GAAiB,EAGhC,CAAC,GAAS,KAAc,EAAS,EAAO,WAAW,WAAW,GAAM,EACpE,CAAC,GAAmB,KAAwB,EAAS,EAAO,WAAW,qBAAqB,GAAG,EAC/F,CAAC,GAAgB,KAAqB,EAAyB,EAAO,WAAW,kBAAkB,QAAQ,EAC3G,CAAC,GAAmB,KAAwB,EAAS,EAAO,WAAW,qBAAqB,GAAK,EACjG,CAAC,GAAU,KAAe,EAAS,EAAO,WAAW,YAAA,EAA8B,EACnF,CAAC,GAAQ,KAAa,EAAyB,EAAO,WAAW,UAAU,OAAO,EAClF,CAAC,GAAmB,KAAwB,QAAmC;EACnF,IAAM,IAAU,EAAO,WAAW;AAIlC,SAHI,IACK,OAAO,QAAQ,EAAQ,CAAC,KAAK,CAAC,GAAK,QAAY;GAAE;GAAK;GAAO,EAAE,GAEjE,CAAC;GAAE,KAAK;GAAI,OAAO;GAAI,CAAC;GAC/B,EAEI,CAAC,GAAY,KAAiB,EAA4B,EAAE,CAAC,EAC7D,CAAC,GAAS,KAAc,EAAS,GAAM,EACvC,CAAC,GAAsB,KAA2B,EAAwB,KAAK,EAG/E,IAAkB,QAAc;AACpC,MAAI,CAAC,EAAY,QAAO,EAAE;EAG1B,IAAM,IAAW;GAAC;GAAO;GAAQ;GAAS;GAAe,EACnD,IAAS,EAAkB,EAAW,EAGtC,IAAwB,EAAE;AAChC,OAAK,IAAM,KAAS,EAClB,MAAK,IAAM,KAAU,EACnB,GAAY,KAAK,KAAK,EAAO,GAAG,EAAM,IAAI;AAQ9C,SAHA,EAAY,KAAK,oBAAoB,oBAAoB,gBAAgB,EACzE,EAAY,KAAK,6BAA6B,0BAA0B,EAEjE,CAAC,GAAG,IAAI,IAAI,EAAY,CAAC;IAC/B,CAAC,EAAW,CAAC,EAGV,IAAe,QAAkB;EACrC,IAAM,IAA2C,EAAE;AACnD,OAAK,IAAM,EAAE,QAAK,cAAW,EAC3B,CAAI,EAAI,MAAM,IAAI,EAAM,MAAM,KAC5B,EAAiB,EAAI,MAAM,IAAI,EAAM,MAAM;AAG/C,MAAW;GACT;GACA;GACA;GACA;GACA;GACA;GACA;GACD,CAAC;IACD;EAAC;EAAS;EAAmB;EAAgB;EAAmB;EAAmB;EAAU;EAAQ;EAAS,CAAC;AAiBlH,CAdA,QAAgB;AACd,KAAc;IACb;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,EAGF,QAAgB;EACd,eAAe,IAAkB;AAC/B,KAAW,GAAK;AAChB,OAAI;AAQF,QAPe,MAAM,EAAa,MAAgE;KAChG,OAAO;KACP,WAAW,EAAE,OAAO,KAAK;KACzB,aAAa;KACd,CAAC,EAEmB,MAAM,gBAAgB,SAAS,EAAE,EAE9C,KAAK,MAAkC;KAC3C,IAAM,IAAO,EAAK;AAClB,YAAO;MACL,IAAI,EAAK;MACT,MAAM,EAAK;MACZ;MACD,CACH;WACW,WACJ;AACR,MAAW,GAAM;;;AAIrB,KAAiB;IAChB,CAAC,EAAa,CAAC;CAGlB,IAAM,IAAsB,QAAkB;AAC5C,KAAsB,MAAS,CAAC,GAAG,GAAM;GAAE,KAAK;GAAI,OAAO;GAAI,CAAC,CAAC;IAChE,EAAE,CAAC,EAGA,IAAyB,GAAa,MAAkB;AAC5D,KAAsB,MAAS,EAAK,QAAQ,GAAG,MAAM,MAAM,EAAM,CAAC;IACjE,EAAE,CAAC,EAGA,IAAyB,GAAa,GAAe,GAAwB,MAAqB;AACtG,KAAsB,MAAS,EAAK,KAAK,GAAM,MAAO,MAAM,IAAQ;GAAE,GAAG;IAAO,IAAQ;GAAU,GAAG,EAAM,CAAC;IAC3G,EAAE,CAAC;AAEN,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,SAAD;KAAO,WAAU;eAAwC;KAAwB,CAAA,EACjF,kBAAC,UAAD;KACE,MAAK;KACL,MAAK;KACL,gBAAc;KACd,eAAe,EAAW,CAAC,EAAQ;KACnC,WAAW;;gBAEL,IAAU,kDAAkD,8BAA8B;;eAGhG,kBAAC,QAAD,EACE,WAAW;;kBAEL,IAAU,kBAAkB,gBAAgB;iBAElD,CAAA;KACK,CAAA,CACL;;GAEL,KACC,kBAAA,GAAA,EAAA,UAAA;IAEE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;KAAO,WAAU;eAAmD;KAAwB,CAAA,EAC5F,kBAAC,UAAD;KACE,OAAO;KACP,WAAW,MAAM,EAAqB,EAAE,OAAO,MAAM;KACrD,UAAU;KACV,WAAU;eAJZ,CAME,kBAAC,UAAD;MAAQ,OAAM;gBAAG;MAA8B,CAAA,EAC9C,EACE,QAAQ,MAAM,EAAE,OAAO,EAAO,YAAY,CAC1C,KAAK,MACJ,kBAAC,UAAD;MAA2B,OAAO,EAAU;gBACzC,EAAU;MACJ,EAFI,EAAU,GAEd,CACT,CACG;OACL,EAAA,CAAA;IAGN,kBAAC,OAAD,EAAA,UAAA;KACE,kBAAC,SAAD;MAAO,WAAU;gBAAmD;MAAuB,CAAA;KAC3F,kBAAC,OAAD;MAAK,WAAU;gBACX;OAAC;OAAS;OAAW;OAAc,CAAsB,KAAK,MAC9D,kBAAC,UAAD;OAEE,MAAK;OACL,eAAe,EAAkB,EAAK;OACtC,WAAW;;wBAGL,MAAmB,IACf,oCACA,yDACL;;iBAVP;QAaG,MAAS,WAAW;QACpB,MAAS,aAAa;QACtB,MAAS,iBAAiB;QACpB;SAfF,EAeE,CACT;MACE,CAAA;KACN,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACG,MAAmB,WAAW;OAC9B,MAAmB,aAAa;OAChC,MAAmB,iBAAiB;OACnC;;KACA,EAAA,CAAA;IAGN,kBAAC,OAAD,EAAA,UAAA;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,SAAD;OAAO,WAAU;iBAAwC;OAA0B,CAAA,EACnF,kBAAC,UAAD;OACE,MAAK;OACL,SAAS;OACT,WAAU;iBACX;OAEQ,CAAA,CACL;;KAEN,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAkB,KAAK,GAAS,MAC/B,kBAAC,OAAD;OAAiB,WAAU;iBACzB,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,SAAD;UACE,MAAK;UACL,OAAO,EAAQ;UACf,WAAW,MAAM,EAAuB,GAAO,OAAO,EAAE,OAAO,MAAM;UACrE,aAAY;UACZ,WAAU;UACV,CAAA;SACF,kBAAC,QAAD;UAAM,WAAU;oBAAqB;UAAQ,CAAA;SAC7C,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,SAAD;WACE,MAAK;WACL,OAAO,EAAQ;WACf,WAAW,MAAM,EAAuB,GAAO,SAAS,EAAE,OAAO,MAAM;WACvE,eAAe,EAAwB,EAAM;WAC7C,cAAc,iBAAiB,EAAwB,KAAK,EAAE,IAAI;WAClE,aAAY;WACZ,WAAU;WACV,CAAA,EAED,MAAyB,KAAS,EAAgB,SAAS,KAC1D,kBAAC,OAAD;WAAK,WAAU;qBACZ,EAAgB,MAAM,GAAG,GAAG,CAAC,KAAK,MACjC,kBAAC,UAAD;YAEE,MAAK;YACL,eAAe;AAEb,aADA,EAAuB,GAAO,SAAS,EAAM,EAC7C,EAAwB,KAAK;;YAE/B,WAAU;sBAET;YACM,EATF,EASE,CACT;WACE,CAAA,CAEJ;;SACL,EAAkB,SAAS,KAC1B,kBAAC,UAAD;UACE,MAAK;UACL,eAAe,EAAuB,EAAM;UAC5C,WAAU;oBAEV,kBAAC,OAAD;WAAK,WAAU;WAAU,MAAK;WAAO,QAAO;WAAe,SAAQ;qBACjE,kBAAC,QAAD;YAAM,eAAc;YAAQ,gBAAe;YAAQ,aAAa;YAAG,GAAE;YAAyB,CAAA;WAC1F,CAAA;UACC,CAAA;SAEP;;OACF,EAnDI,EAmDJ,CACN;MACE,CAAA;KAEN,kBAAC,KAAD;MAAG,WAAU;gBAAb;OAA+C;OACzC,kBAAC,QAAD;QAAM,WAAU;kBAA6B;QAAuB,CAAA;;OAExE,kBAAC,MAAD,EAAM,CAAA;;OACI,kBAAC,QAAD;QAAM,WAAU;kBAA6B;QAA0B,CAAA;;OAAE;OACnF,kBAAC,QAAD;QAAM,WAAU;kBAA6B;QAAqB,CAAA;;OAAE;OACpE,kBAAC,QAAD;QAAM,WAAU;kBAA6B;QAAmC,CAAA;OAC9E;;KACA,EAAA,CAAA;IAGN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,MAAD;OAAI,WAAU;iBAA6C;OAAqB,CAAA;MAGhF,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,WAAU;kBAA4B;QAA2B,CAAA,EACxE,kBAAC,KAAD;QAAG,WAAU;kBAA6B;QAAkD,CAAA,CACxF,EAAA,CAAA,EACN,kBAAC,UAAD;QACE,MAAK;QACL,MAAK;QACL,gBAAc;QACd,eAAe,EAAqB,CAAC,EAAkB;QACvD,WAAW;;sBAEL,IAAoB,kDAAkD,8BAA8B;;kBAG1G,kBAAC,QAAD,EACE,WAAW;;wBAEL,IAAoB,kBAAkB,gBAAgB;uBAE5D,CAAA;QACK,CAAA,CACL;;MAGN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,WAAU;kBAA4B;QAA2B,CAAA,EACxE,kBAAC,KAAD;QAAG,WAAU;kBAA6B;QAAiC,CAAA,CACvE,EAAA,CAAA,EACN,kBAAC,UAAD;QACE,OAAO;QACP,WAAW,MAAM,EAAY,OAAO,EAAE,OAAO,MAAM,CAAC;QACpD,WAAU;kBAET;SAAC;SAAG;SAAG;SAAG;SAAG;SAAE,CAAC,KAAK,MACpB,kBAAC,UAAD;SAAgB,OAAO;mBACpB;SACM,EAFI,EAEJ,CACT;QACK,CAAA,CACL;;MAGL,MAAmB,iBAClB,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,WAAU;kBAA4B;QAAe,CAAA,EAC5D,kBAAC,KAAD;QAAG,WAAU;kBAA6B;QAA+B,CAAA,CACrE,EAAA,CAAA,EACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,EAAU,OAAO;SAChC,WAAW;;0BAGL,MAAW,SACP,oCACA,uFACL;;mBAEN;SAEQ,CAAA,EACT,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,EAAU,MAAM;SAC/B,WAAW;;0BAGL,MAAW,QACP,oCACA,uFACL;;mBAEN;SAEQ,CAAA,CACL;UACF;;MAEJ;;IACL,EAAA,CAAA;GAIJ,CAAC,KAAW,EAAO,WAAW,MAC7B,kBAAC,OAAD;IAAK,WAAU;cAAkD;IAE3D,CAAA;GAEJ;;EAER"}
1
+ {"version":3,"file":"DrilldownConfigPanel.js","names":[],"sources":["../../../../src/bigconsole/components/widgets/DrilldownConfigPanel.tsx"],"sourcesContent":["/**\n * DrilldownConfigPanel Component\n *\n * UI for configuring widget drilldown settings.\n * Allows selecting target dashboard, navigation mode, and parameter mappings.\n *\n * v2.0 Features:\n * - passGlobalFilters: Pass current dashboard filters to target\n * - maxDepth: Limit drilldown depth (default: 3)\n * - openIn: Open in same tab or new tab\n * - Field suggestions based on widget data\n */\n\nimport { type FC, memo, useState, useEffect, useCallback, useMemo } from 'react';\nimport { useApolloClient } from '@apollo/client/react';\nimport type { Widget, NavigationMode } from '../../types';\nimport { ListDashboardsDocument } from '../../../generated/wspace-operations';\nimport { DEFAULT_MAX_DEPTH } from '../../hooks/useDrilldown';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface DrilldownConfigPanelProps {\n /** Widget to configure drilldown for */\n widget: Widget;\n /** Callback when drilldown settings change (for tracking unsaved changes) */\n onChange?: (config: DrilldownConfig) => void;\n /** Sample widget data for field suggestions */\n widgetData?: Record<string, unknown>;\n}\n\nexport interface DrilldownConfig {\n enabled: boolean;\n targetDashboardId: string;\n navigationMode: NavigationMode;\n parameterMapping: Record<string, string>;\n /** Whether to pass global filters to target dashboard */\n passGlobalFilters: boolean;\n /** Maximum drilldown depth (default: 3) */\n maxDepth: number;\n /** Open in same tab or new tab (for SAME_WINDOW mode) */\n openIn: 'same' | 'new';\n}\n\ninterface DashboardOption {\n id: string;\n name: string;\n}\n\ninterface ParameterMapping {\n key: string;\n value: string;\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Extract available fields from widget data for field suggestions\n */\nfunction extractFieldPaths(obj: unknown, prefix = ''): string[] {\n if (!obj || typeof obj !== 'object') return [];\n\n const paths: string[] = [];\n\n // Handle arrays - use first element as template\n if (Array.isArray(obj)) {\n if (obj.length > 0 && typeof obj[0] === 'object') {\n return extractFieldPaths(obj[0], prefix);\n }\n return [];\n }\n\n // Handle objects\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n const path = prefix ? `${prefix}.${key}` : key;\n paths.push(path);\n\n // Recurse into nested objects (but not too deep)\n if (value && typeof value === 'object' && !Array.isArray(value) && prefix.split('.').length < 2) {\n paths.push(...extractFieldPaths(value, path));\n }\n }\n\n return paths;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const DrilldownConfigPanel: FC<DrilldownConfigPanelProps> = memo(function DrilldownConfigPanel({\n widget,\n onChange,\n widgetData,\n}) {\n const apolloClient = useApolloClient();\n\n // State\n const [enabled, setEnabled] = useState(widget.drilldown?.enabled ?? false);\n const [targetDashboardId, setTargetDashboardId] = useState(widget.drilldown?.targetDashboardId ?? '');\n const [navigationMode, setNavigationMode] = useState<NavigationMode>(widget.drilldown?.navigationMode ?? 'MODAL');\n const [passGlobalFilters, setPassGlobalFilters] = useState(widget.drilldown?.passGlobalFilters ?? true);\n const [maxDepth, setMaxDepth] = useState(widget.drilldown?.maxDepth ?? DEFAULT_MAX_DEPTH);\n const [openIn, setOpenIn] = useState<'same' | 'new'>(widget.drilldown?.openIn ?? 'same');\n const [parameterMappings, setParameterMappings] = useState<ParameterMapping[]>(() => {\n const mapping = widget.drilldown?.parameterMapping as Record<string, string> | undefined;\n if (mapping) {\n return Object.entries(mapping).map(([key, value]) => ({ key, value }));\n }\n return [{ key: '', value: '' }];\n });\n\n const [dashboards, setDashboards] = useState<DashboardOption[]>([]);\n const [loading, setLoading] = useState(false);\n const [showFieldSuggestions, setShowFieldSuggestions] = useState<number | null>(null);\n\n // Extract available field paths from widget data\n const availableFields = useMemo(() => {\n if (!widgetData) return [];\n\n // Common prefixes for different widget types\n const prefixes = ['row', 'item', 'point', 'selectedData'];\n const fields = extractFieldPaths(widgetData);\n\n // Generate mustache-style suggestions\n const suggestions: string[] = [];\n for (const field of fields) {\n for (const prefix of prefixes) {\n suggestions.push(`{{${prefix}.${field}}}`);\n }\n }\n\n // Add common widget data fields\n suggestions.push('{{widget.value}}', '{{widget.title}}', '{{widget.id}}');\n suggestions.push('{{globals.vars.dateFrom}}', '{{globals.vars.dateTo}}');\n\n return [...new Set(suggestions)];\n }, [widgetData]);\n\n // Notify parent of changes\n const notifyChange = useCallback(() => {\n const parameterMapping: Record<string, string> = {};\n for (const { key, value } of parameterMappings) {\n if (key.trim() && value.trim()) {\n parameterMapping[key.trim()] = value.trim();\n }\n }\n onChange?.({\n enabled,\n targetDashboardId,\n navigationMode,\n parameterMapping,\n passGlobalFilters,\n maxDepth,\n openIn,\n });\n }, [enabled, targetDashboardId, navigationMode, parameterMappings, passGlobalFilters, maxDepth, openIn, onChange]);\n\n // Call notifyChange when any value changes\n useEffect(() => {\n notifyChange();\n }, [\n enabled,\n targetDashboardId,\n navigationMode,\n parameterMappings,\n passGlobalFilters,\n maxDepth,\n openIn,\n notifyChange,\n ]);\n\n // Fetch available dashboards\n useEffect(() => {\n async function fetchDashboards() {\n setLoading(true);\n try {\n const result = await apolloClient.query<{ listDashboards: { edges: Record<string, unknown>[] } }>({\n query: ListDashboardsDocument,\n variables: { first: 100 },\n fetchPolicy: 'cache-first',\n });\n\n const edges = result.data?.listDashboards?.edges || [];\n setDashboards(\n edges.map((edge: Record<string, unknown>) => {\n const node = edge.node as Record<string, unknown>;\n return {\n id: node.id as string,\n name: node.name as string,\n };\n })\n );\n } catch (err) {\n } finally {\n setLoading(false);\n }\n }\n\n fetchDashboards();\n }, [apolloClient]);\n\n // Add parameter mapping row\n const addParameterMapping = useCallback(() => {\n setParameterMappings((prev) => [...prev, { key: '', value: '' }]);\n }, []);\n\n // Remove parameter mapping row\n const removeParameterMapping = useCallback((index: number) => {\n setParameterMappings((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n // Update parameter mapping\n const updateParameterMapping = useCallback((index: number, field: 'key' | 'value', newValue: string) => {\n setParameterMappings((prev) => prev.map((item, i) => (i === index ? { ...item, [field]: newValue } : item)));\n }, []);\n\n return (\n <div className=\"space-y-4 pb-8\">\n {/* Enable Toggle */}\n <div className=\"flex items-center justify-between p-3 rounded-lg border border-border-default bg-bg-surface\">\n <label className=\"text-sm font-medium text-text-primary\">Enable Drilldown</label>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={enabled}\n onClick={() => setEnabled(!enabled)}\n className={`\n relative inline-flex h-6 w-11 items-center rounded-full transition-colors cursor-pointer border\n ${enabled ? 'bg-action-primary-bg border-action-primary-bg' : 'bg-gray-300 border-gray-400'}\n `}\n >\n <span\n className={`\n inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform\n ${enabled ? 'translate-x-6' : 'translate-x-1'}\n `}\n />\n </button>\n </div>\n\n {enabled && (\n <>\n {/* Target Dashboard */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Target Dashboard</label>\n <select\n value={targetDashboardId}\n onChange={(e) => setTargetDashboardId(e.target.value)}\n disabled={loading}\n className=\"w-full px-3 py-2 rounded-md border border-border-default bg-bg-surface text-text-primary text-sm focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n <option value=\"\">Select a dashboard...</option>\n {dashboards\n .filter((d) => d.id !== widget.dashboardId) // Exclude current dashboard\n .map((dashboard) => (\n <option key={dashboard.id} value={dashboard.id}>\n {dashboard.name}\n </option>\n ))}\n </select>\n </div>\n\n {/* Navigation Mode */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Navigation Mode</label>\n <div className=\"flex gap-2\">\n {(['MODAL', 'NEW_TAB', 'SAME_WINDOW'] as NavigationMode[]).map((mode) => (\n <button\n key={mode}\n type=\"button\"\n onClick={() => setNavigationMode(mode)}\n className={`\n flex-1 px-3 py-2 rounded-md text-sm font-medium transition-colors\n ${\n navigationMode === mode\n ? 'bg-action-primary-bg text-white'\n : 'bg-bg-sunken text-text-secondary hover:bg-bg-sunken/80'\n }\n `}\n >\n {mode === 'MODAL' && 'Modal'}\n {mode === 'NEW_TAB' && 'New Tab'}\n {mode === 'SAME_WINDOW' && 'Same Window'}\n </button>\n ))}\n </div>\n <p className=\"text-xs text-text-tertiary mt-1\">\n {navigationMode === 'MODAL' && 'Opens target dashboard in a modal overlay'}\n {navigationMode === 'NEW_TAB' && 'Opens target dashboard in a new browser tab'}\n {navigationMode === 'SAME_WINDOW' && 'Navigates to target dashboard in current window'}\n </p>\n </div>\n\n {/* Parameter Mappings */}\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <label className=\"text-sm font-medium text-text-primary\">Parameter Mappings</label>\n <button\n type=\"button\"\n onClick={addParameterMapping}\n className=\"text-xs text-action-primary-text hover:underline\"\n >\n + Add Parameter\n </button>\n </div>\n\n <div className=\"space-y-2\">\n {parameterMappings.map((mapping, index) => (\n <div key={index} className=\"relative\">\n <div className=\"flex gap-2 items-center\">\n <input\n type=\"text\"\n value={mapping.key}\n onChange={(e) => updateParameterMapping(index, 'key', e.target.value)}\n placeholder=\"Parameter name\"\n className=\"flex-1 px-2 py-1.5 rounded border border-border-default bg-bg-surface text-text-primary text-sm focus:outline-none focus:ring-1 focus:ring-action-primary-bg\"\n />\n <span className=\"text-text-tertiary\">=</span>\n <div className=\"flex-1 relative\">\n <input\n type=\"text\"\n value={mapping.value}\n onChange={(e) => updateParameterMapping(index, 'value', e.target.value)}\n onFocus={() => setShowFieldSuggestions(index)}\n onBlur={() => setTimeout(() => setShowFieldSuggestions(null), 200)}\n placeholder=\"{{row.field}} or static\"\n className=\"w-full px-2 py-1.5 rounded border border-border-default bg-bg-surface text-text-primary text-sm focus:outline-none focus:ring-1 focus:ring-action-primary-bg\"\n />\n {/* Field suggestions dropdown */}\n {showFieldSuggestions === index && availableFields.length > 0 && (\n <div className=\"absolute z-10 top-full left-0 right-0 mt-1 max-h-40 overflow-y-auto bg-bg-surface border border-border-default rounded-md shadow-lg\">\n {availableFields.slice(0, 10).map((field) => (\n <button\n key={field}\n type=\"button\"\n onClick={() => {\n updateParameterMapping(index, 'value', field);\n setShowFieldSuggestions(null);\n }}\n className=\"w-full px-3 py-1.5 text-left text-xs text-text-primary hover:bg-bg-sunken font-mono\"\n >\n {field}\n </button>\n ))}\n </div>\n )}\n </div>\n {parameterMappings.length > 1 && (\n <button\n type=\"button\"\n onClick={() => removeParameterMapping(index)}\n className=\"p-1 text-text-tertiary hover:text-status-error-text\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n )}\n </div>\n </div>\n ))}\n </div>\n\n <p className=\"text-xs text-text-tertiary mt-2\">\n Use <code className=\"px-1 bg-bg-sunken rounded\">{'{{row.field}}'}</code> for dynamic values or enter\n static text.\n <br />\n Examples: <code className=\"px-1 bg-bg-sunken rounded\">{'{{row.category}}'}</code>,{' '}\n <code className=\"px-1 bg-bg-sunken rounded\">{'{{item.id}}'}</code>,{' '}\n <code className=\"px-1 bg-bg-sunken rounded\">{'{{globals.vars.dateFrom}}'}</code>\n </p>\n </div>\n\n {/* Advanced Options */}\n <div className=\"border-t border-border-default pt-4 mt-4\">\n <h4 className=\"text-sm font-medium text-text-primary mb-3\">Advanced Options</h4>\n\n {/* Pass Global Filters */}\n <div className=\"flex items-center justify-between p-2 rounded bg-bg-sunken mb-3\">\n <div>\n <label className=\"text-sm text-text-primary\">Pass Global Filters</label>\n <p className=\"text-xs text-text-tertiary\">Include current dashboard filters in drilldown</p>\n </div>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={passGlobalFilters}\n onClick={() => setPassGlobalFilters(!passGlobalFilters)}\n className={`\n relative inline-flex h-5 w-9 items-center rounded-full transition-colors cursor-pointer border\n ${passGlobalFilters ? 'bg-action-primary-bg border-action-primary-bg' : 'bg-gray-300 border-gray-400'}\n `}\n >\n <span\n className={`\n inline-block h-3 w-3 transform rounded-full bg-white shadow transition-transform\n ${passGlobalFilters ? 'translate-x-5' : 'translate-x-1'}\n `}\n />\n </button>\n </div>\n\n {/* Max Depth */}\n <div className=\"flex items-center justify-between p-2 rounded bg-bg-sunken mb-3\">\n <div>\n <label className=\"text-sm text-text-primary\">Max Drilldown Depth</label>\n <p className=\"text-xs text-text-tertiary\">Limit nested drilldown levels</p>\n </div>\n <select\n value={maxDepth}\n onChange={(e) => setMaxDepth(Number(e.target.value))}\n className=\"w-16 px-2 py-1 rounded border border-border-default bg-bg-surface text-text-primary text-sm\"\n >\n {[1, 2, 3, 4, 5].map((n) => (\n <option key={n} value={n}>\n {n}\n </option>\n ))}\n </select>\n </div>\n\n {/* Open In (only for SAME_WINDOW mode) */}\n {navigationMode === 'SAME_WINDOW' && (\n <div className=\"flex items-center justify-between p-2 rounded bg-bg-sunken\">\n <div>\n <label className=\"text-sm text-text-primary\">Open In</label>\n <p className=\"text-xs text-text-tertiary\">Tab behavior for navigation</p>\n </div>\n <div className=\"flex gap-1\">\n <button\n type=\"button\"\n onClick={() => setOpenIn('same')}\n className={`\n px-2 py-1 rounded text-xs font-medium transition-colors\n ${\n openIn === 'same'\n ? 'bg-action-primary-bg text-white'\n : 'bg-bg-surface text-text-secondary hover:bg-bg-sunken/80 border border-border-default'\n }\n `}\n >\n Same Tab\n </button>\n <button\n type=\"button\"\n onClick={() => setOpenIn('new')}\n className={`\n px-2 py-1 rounded text-xs font-medium transition-colors\n ${\n openIn === 'new'\n ? 'bg-action-primary-bg text-white'\n : 'bg-bg-surface text-text-secondary hover:bg-bg-sunken/80 border border-border-default'\n }\n `}\n >\n New Tab\n </button>\n </div>\n </div>\n )}\n </div>\n </>\n )}\n\n {/* Info when drilldown will be removed */}\n {!enabled && widget.drilldown?.id && (\n <div className=\"p-2 rounded bg-amber-100 text-amber-800 text-sm\">\n Drilldown will be removed when you save changes.\n </div>\n )}\n </div>\n );\n});\n\nexport default DrilldownConfigPanel;\n"],"mappings":";;;;;;AA8DA,SAAS,EAAkB,GAAc,IAAS,IAAc;AAC9D,KAAI,CAAC,KAAO,OAAO,KAAQ,SAAU,QAAO,EAAE;CAE9C,IAAM,IAAkB,EAAE;AAG1B,KAAI,MAAM,QAAQ,EAAI,CAIpB,QAHI,EAAI,SAAS,KAAK,OAAO,EAAI,MAAO,WAC/B,EAAkB,EAAI,IAAI,EAAO,GAEnC,EAAE;AAIX,MAAK,IAAM,CAAC,GAAK,MAAU,OAAO,QAAQ,EAA+B,EAAE;EACzE,IAAM,IAAO,IAAS,GAAG,EAAO,GAAG,MAAQ;AAI3C,EAHA,EAAM,KAAK,EAAK,EAGZ,KAAS,OAAO,KAAU,YAAY,CAAC,MAAM,QAAQ,EAAM,IAAI,EAAO,MAAM,IAAI,CAAC,SAAS,KAC5F,EAAM,KAAK,GAAG,EAAkB,GAAO,EAAK,CAAC;;AAIjD,QAAO;;AAOT,IAAa,IAAsD,EAAK,SAA8B,EACpG,WACA,aACA,iBACC;CACD,IAAM,IAAe,GAAiB,EAGhC,CAAC,GAAS,KAAc,EAAS,EAAO,WAAW,WAAW,GAAM,EACpE,CAAC,GAAmB,KAAwB,EAAS,EAAO,WAAW,qBAAqB,GAAG,EAC/F,CAAC,GAAgB,KAAqB,EAAyB,EAAO,WAAW,kBAAkB,QAAQ,EAC3G,CAAC,GAAmB,KAAwB,EAAS,EAAO,WAAW,qBAAqB,GAAK,EACjG,CAAC,GAAU,KAAe,EAAS,EAAO,WAAW,YAAA,EAA8B,EACnF,CAAC,GAAQ,KAAa,EAAyB,EAAO,WAAW,UAAU,OAAO,EAClF,CAAC,GAAmB,KAAwB,QAAmC;EACnF,IAAM,IAAU,EAAO,WAAW;AAIlC,SAHI,IACK,OAAO,QAAQ,EAAQ,CAAC,KAAK,CAAC,GAAK,QAAY;GAAE;GAAK;GAAO,EAAE,GAEjE,CAAC;GAAE,KAAK;GAAI,OAAO;GAAI,CAAC;GAC/B,EAEI,CAAC,GAAY,KAAiB,EAA4B,EAAE,CAAC,EAC7D,CAAC,GAAS,KAAc,EAAS,GAAM,EACvC,CAAC,GAAsB,KAA2B,EAAwB,KAAK,EAG/E,IAAkB,QAAc;AACpC,MAAI,CAAC,EAAY,QAAO,EAAE;EAG1B,IAAM,IAAW;GAAC;GAAO;GAAQ;GAAS;GAAe,EACnD,IAAS,EAAkB,EAAW,EAGtC,IAAwB,EAAE;AAChC,OAAK,IAAM,KAAS,EAClB,MAAK,IAAM,KAAU,EACnB,GAAY,KAAK,KAAK,EAAO,GAAG,EAAM,IAAI;AAQ9C,SAHA,EAAY,KAAK,oBAAoB,oBAAoB,gBAAgB,EACzE,EAAY,KAAK,6BAA6B,0BAA0B,EAEjE,CAAC,GAAG,IAAI,IAAI,EAAY,CAAC;IAC/B,CAAC,EAAW,CAAC,EAGV,IAAe,QAAkB;EACrC,IAAM,IAA2C,EAAE;AACnD,OAAK,IAAM,EAAE,QAAK,cAAW,EAC3B,CAAI,EAAI,MAAM,IAAI,EAAM,MAAM,KAC5B,EAAiB,EAAI,MAAM,IAAI,EAAM,MAAM;AAG/C,MAAW;GACT;GACA;GACA;GACA;GACA;GACA;GACA;GACD,CAAC;IACD;EAAC;EAAS;EAAmB;EAAgB;EAAmB;EAAmB;EAAU;EAAQ;EAAS,CAAC;AAiBlH,CAdA,QAAgB;AACd,KAAc;IACb;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,EAGF,QAAgB;EACd,eAAe,IAAkB;AAC/B,KAAW,GAAK;AAChB,OAAI;AAQF,QAPe,MAAM,EAAa,MAAgE;KAChG,OAAO;KACP,WAAW,EAAE,OAAO,KAAK;KACzB,aAAa;KACd,CAAC,EAEmB,MAAM,gBAAgB,SAAS,EAAE,EAE9C,KAAK,MAAkC;KAC3C,IAAM,IAAO,EAAK;AAClB,YAAO;MACL,IAAI,EAAK;MACT,MAAM,EAAK;MACZ;MACD,CACH;WACW,WACJ;AACR,MAAW,GAAM;;;AAIrB,KAAiB;IAChB,CAAC,EAAa,CAAC;CAGlB,IAAM,IAAsB,QAAkB;AAC5C,KAAsB,MAAS,CAAC,GAAG,GAAM;GAAE,KAAK;GAAI,OAAO;GAAI,CAAC,CAAC;IAChE,EAAE,CAAC,EAGA,IAAyB,GAAa,MAAkB;AAC5D,KAAsB,MAAS,EAAK,QAAQ,GAAG,MAAM,MAAM,EAAM,CAAC;IACjE,EAAE,CAAC,EAGA,IAAyB,GAAa,GAAe,GAAwB,MAAqB;AACtG,KAAsB,MAAS,EAAK,KAAK,GAAM,MAAO,MAAM,IAAQ;GAAE,GAAG;IAAO,IAAQ;GAAU,GAAG,EAAM,CAAC;IAC3G,EAAE,CAAC;AAEN,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,SAAD;KAAO,WAAU;eAAwC;KAAwB,CAAA,EACjF,kBAAC,UAAD;KACE,MAAK;KACL,MAAK;KACL,gBAAc;KACd,eAAe,EAAW,CAAC,EAAQ;KACnC,WAAW;;gBAEL,IAAU,kDAAkD,8BAA8B;;eAGhG,kBAAC,QAAD,EACE,WAAW;;kBAEL,IAAU,kBAAkB,gBAAgB;iBAElD,CAAA;KACK,CAAA,CACL;;GAEL,KACC,kBAAA,GAAA,EAAA,UAAA;IAEE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;KAAO,WAAU;eAAmD;KAAwB,CAAA,EAC5F,kBAAC,UAAD;KACE,OAAO;KACP,WAAW,MAAM,EAAqB,EAAE,OAAO,MAAM;KACrD,UAAU;KACV,WAAU;eAJZ,CAME,kBAAC,UAAD;MAAQ,OAAM;gBAAG;MAA8B,CAAA,EAC9C,EACE,QAAQ,MAAM,EAAE,OAAO,EAAO,YAAY,CAC1C,KAAK,MACJ,kBAAC,UAAD;MAA2B,OAAO,EAAU;gBACzC,EAAU;MACJ,EAFI,EAAU,GAEd,CACT,CACG;OACL,EAAA,CAAA;IAGN,kBAAC,OAAD,EAAA,UAAA;KACE,kBAAC,SAAD;MAAO,WAAU;gBAAmD;MAAuB,CAAA;KAC3F,kBAAC,OAAD;MAAK,WAAU;gBACX;OAAC;OAAS;OAAW;OAAc,CAAsB,KAAK,MAC9D,kBAAC,UAAD;OAEE,MAAK;OACL,eAAe,EAAkB,EAAK;OACtC,WAAW;;wBAGL,MAAmB,IACf,oCACA,yDACL;;iBAVP;QAaG,MAAS,WAAW;QACpB,MAAS,aAAa;QACtB,MAAS,iBAAiB;QACpB;SAfF,EAeE,CACT;MACE,CAAA;KACN,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACG,MAAmB,WAAW;OAC9B,MAAmB,aAAa;OAChC,MAAmB,iBAAiB;OACnC;;KACA,EAAA,CAAA;IAGN,kBAAC,OAAD,EAAA,UAAA;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,SAAD;OAAO,WAAU;iBAAwC;OAA0B,CAAA,EACnF,kBAAC,UAAD;OACE,MAAK;OACL,SAAS;OACT,WAAU;iBACX;OAEQ,CAAA,CACL;;KAEN,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAkB,KAAK,GAAS,MAC/B,kBAAC,OAAD;OAAiB,WAAU;iBACzB,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,SAAD;UACE,MAAK;UACL,OAAO,EAAQ;UACf,WAAW,MAAM,EAAuB,GAAO,OAAO,EAAE,OAAO,MAAM;UACrE,aAAY;UACZ,WAAU;UACV,CAAA;SACF,kBAAC,QAAD;UAAM,WAAU;oBAAqB;UAAQ,CAAA;SAC7C,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,SAAD;WACE,MAAK;WACL,OAAO,EAAQ;WACf,WAAW,MAAM,EAAuB,GAAO,SAAS,EAAE,OAAO,MAAM;WACvE,eAAe,EAAwB,EAAM;WAC7C,cAAc,iBAAiB,EAAwB,KAAK,EAAE,IAAI;WAClE,aAAY;WACZ,WAAU;WACV,CAAA,EAED,MAAyB,KAAS,EAAgB,SAAS,KAC1D,kBAAC,OAAD;WAAK,WAAU;qBACZ,EAAgB,MAAM,GAAG,GAAG,CAAC,KAAK,MACjC,kBAAC,UAAD;YAEE,MAAK;YACL,eAAe;AAEb,aADA,EAAuB,GAAO,SAAS,EAAM,EAC7C,EAAwB,KAAK;;YAE/B,WAAU;sBAET;YACM,EATF,EASE,CACT;WACE,CAAA,CAEJ;;SACL,EAAkB,SAAS,KAC1B,kBAAC,UAAD;UACE,MAAK;UACL,eAAe,EAAuB,EAAM;UAC5C,WAAU;oBAEV,kBAAC,OAAD;WAAK,WAAU;WAAU,MAAK;WAAO,QAAO;WAAe,SAAQ;qBACjE,kBAAC,QAAD;YAAM,eAAc;YAAQ,gBAAe;YAAQ,aAAa;YAAG,GAAE;YAAyB,CAAA;WAC1F,CAAA;UACC,CAAA;SAEP;;OACF,EAnDI,EAmDJ,CACN;MACE,CAAA;KAEN,kBAAC,KAAD;MAAG,WAAU;gBAAb;OAA+C;OACzC,kBAAC,QAAD;QAAM,WAAU;kBAA6B;QAAuB,CAAA;;OAExE,kBAAC,MAAD,EAAM,CAAA;;OACI,kBAAC,QAAD;QAAM,WAAU;kBAA6B;QAA0B,CAAA;;OAAE;OACnF,kBAAC,QAAD;QAAM,WAAU;kBAA6B;QAAqB,CAAA;;OAAE;OACpE,kBAAC,QAAD;QAAM,WAAU;kBAA6B;QAAmC,CAAA;OAC9E;;KACA,EAAA,CAAA;IAGN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,MAAD;OAAI,WAAU;iBAA6C;OAAqB,CAAA;MAGhF,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,WAAU;kBAA4B;QAA2B,CAAA,EACxE,kBAAC,KAAD;QAAG,WAAU;kBAA6B;QAAkD,CAAA,CACxF,EAAA,CAAA,EACN,kBAAC,UAAD;QACE,MAAK;QACL,MAAK;QACL,gBAAc;QACd,eAAe,EAAqB,CAAC,EAAkB;QACvD,WAAW;;sBAEL,IAAoB,kDAAkD,8BAA8B;;kBAG1G,kBAAC,QAAD,EACE,WAAW;;wBAEL,IAAoB,kBAAkB,gBAAgB;uBAE5D,CAAA;QACK,CAAA,CACL;;MAGN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,WAAU;kBAA4B;QAA2B,CAAA,EACxE,kBAAC,KAAD;QAAG,WAAU;kBAA6B;QAAiC,CAAA,CACvE,EAAA,CAAA,EACN,kBAAC,UAAD;QACE,OAAO;QACP,WAAW,MAAM,EAAY,OAAO,EAAE,OAAO,MAAM,CAAC;QACpD,WAAU;kBAET;SAAC;SAAG;SAAG;SAAG;SAAG;SAAE,CAAC,KAAK,MACpB,kBAAC,UAAD;SAAgB,OAAO;mBACpB;SACM,EAFI,EAEJ,CACT;QACK,CAAA,CACL;;MAGL,MAAmB,iBAClB,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,WAAU;kBAA4B;QAAe,CAAA,EAC5D,kBAAC,KAAD;QAAG,WAAU;kBAA6B;QAA+B,CAAA,CACrE,EAAA,CAAA,EACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,EAAU,OAAO;SAChC,WAAW;;0BAGL,MAAW,SACP,oCACA,uFACL;;mBAEN;SAEQ,CAAA,EACT,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,EAAU,MAAM;SAC/B,WAAW;;0BAGL,MAAW,QACP,oCACA,uFACL;;mBAEN;SAEQ,CAAA,CACL;UACF;;MAEJ;;IACL,EAAA,CAAA;GAIJ,CAAC,KAAW,EAAO,WAAW,MAC7B,kBAAC,OAAD;IAAK,WAAU;cAAkD;IAE3D,CAAA;GAEJ;;EAER"}