@burdenoff/microfe-bigconsole 2026.805.3 → 2026.812.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bigconsole/components/DrilldownDashboardRenderer.js +118 -106
- package/dist/bigconsole/components/DrilldownDashboardRenderer.js.map +1 -1
- package/dist/bigconsole/components/DrilldownModal.js +54 -50
- package/dist/bigconsole/components/DrilldownModal.js.map +1 -1
- package/dist/bigconsole/components/builder/BuilderCanvas.js +2 -2
- package/dist/bigconsole/components/builder/BuilderCanvas.js.map +1 -1
- package/dist/bigconsole/components/builder/BuilderTopbar.js +3 -3
- package/dist/bigconsole/components/builder/BuilderTopbar.js.map +1 -1
- package/dist/bigconsole/components/builder/inspector/AdvancedSection.js +24 -25
- package/dist/bigconsole/components/builder/inspector/AdvancedSection.js.map +1 -1
- package/dist/bigconsole/components/builder/inspector/AppearanceSection.js +40 -29
- package/dist/bigconsole/components/builder/inspector/AppearanceSection.js.map +1 -1
- package/dist/bigconsole/components/builder/inspector/DataBindingSection.js +135 -97
- package/dist/bigconsole/components/builder/inspector/DataBindingSection.js.map +1 -1
- package/dist/bigconsole/components/builder/inspector/GeneralSection.js +58 -44
- package/dist/bigconsole/components/builder/inspector/GeneralSection.js.map +1 -1
- package/dist/bigconsole/components/common/Section.js +70 -0
- package/dist/bigconsole/components/common/Section.js.map +1 -0
- package/dist/bigconsole/components/common/index.js +2 -0
- package/dist/bigconsole/components/common/sectionStyles.js +42 -0
- package/dist/bigconsole/components/common/sectionStyles.js.map +1 -0
- package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js +209 -193
- package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/DashboardCanvas.js +213 -231
- package/dist/bigconsole/components/dashboard/DashboardCanvas.js.map +1 -1
- package/dist/bigconsole/components/dashboard/DashboardGrid.js +12 -18
- package/dist/bigconsole/components/dashboard/DashboardGrid.js.map +1 -1
- package/dist/bigconsole/components/dashboard/DashboardToolbar.js +109 -102
- package/dist/bigconsole/components/dashboard/DashboardToolbar.js.map +1 -1
- package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js +81 -70
- package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js.map +1 -1
- package/dist/bigconsole/components/dashboard/ExportDashboardDialog.js +125 -159
- package/dist/bigconsole/components/dashboard/ExportDashboardDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterChip.js +25 -23
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterChip.js.map +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js +3 -3
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js.map +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js +5 -3
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js.map +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js +170 -284
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js.map +1 -1
- package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js +147 -151
- package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/LiveBoardBanner.js +45 -53
- package/dist/bigconsole/components/dashboard/LiveBoardBanner.js.map +1 -1
- package/dist/bigconsole/components/dashboard/PageTabsManager/PageTabsManager.js +157 -148
- package/dist/bigconsole/components/dashboard/PageTabsManager/PageTabsManager.js.map +1 -1
- package/dist/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.js +17 -8
- package/dist/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.js.map +1 -1
- package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js +101 -95
- package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/StoreTemplatePicker.js +20 -18
- package/dist/bigconsole/components/dashboard/StoreTemplatePicker.js.map +1 -1
- package/dist/bigconsole/components/dashboard/TemplateSetupBanner.js +26 -58
- package/dist/bigconsole/components/dashboard/TemplateSetupBanner.js.map +1 -1
- package/dist/bigconsole/components/dashboard/WidgetPalette.js +307 -231
- package/dist/bigconsole/components/dashboard/WidgetPalette.js.map +1 -1
- package/dist/bigconsole/components/datasink/CacheTTLSelector.js +29 -29
- package/dist/bigconsole/components/datasink/CacheTTLSelector.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkCard.js +78 -79
- package/dist/bigconsole/components/datasink/DataSinkCard.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkDataViewer.js +33 -34
- package/dist/bigconsole/components/datasink/DataSinkDataViewer.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js +79 -56
- package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js +75 -65
- package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkStatusBadge.js +1 -1
- package/dist/bigconsole/components/datasink/DataSinkStatusBadge.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkTableViewer.js +20 -19
- package/dist/bigconsole/components/datasink/DataSinkTableViewer.js.map +1 -1
- package/dist/bigconsole/components/datasink/ExportDataSinkDialog.js +127 -171
- package/dist/bigconsole/components/datasink/ExportDataSinkDialog.js.map +1 -1
- package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js +263 -243
- package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js.map +1 -1
- package/dist/bigconsole/components/datasink/LinkedParsersPanel.js +65 -66
- package/dist/bigconsole/components/datasink/LinkedParsersPanel.js.map +1 -1
- package/dist/bigconsole/components/datasink/LinkedWorkflowsPanel.js +121 -127
- package/dist/bigconsole/components/datasink/LinkedWorkflowsPanel.js.map +1 -1
- package/dist/bigconsole/components/datasink/RefreshTypeSelector.js +33 -26
- package/dist/bigconsole/components/datasink/RefreshTypeSelector.js.map +1 -1
- package/dist/bigconsole/components/datasink/SetupStateBadge.js +3 -3
- package/dist/bigconsole/components/datasink/SetupStateBadge.js.map +1 -1
- package/dist/bigconsole/components/datasink/WorkflowStatusPanel.js +95 -95
- package/dist/bigconsole/components/datasink/WorkflowStatusPanel.js.map +1 -1
- package/dist/bigconsole/components/parser/DataSinkSelector.js +154 -123
- package/dist/bigconsole/components/parser/DataSinkSelector.js.map +1 -1
- package/dist/bigconsole/components/parser/ExpressionEditor.js +3 -3
- package/dist/bigconsole/components/parser/ExpressionEditor.js.map +1 -1
- package/dist/bigconsole/components/parser/ImportParserDialog.js +235 -275
- package/dist/bigconsole/components/parser/ImportParserDialog.js.map +1 -1
- package/dist/bigconsole/components/parser/ParserCard.js +133 -114
- package/dist/bigconsole/components/parser/ParserCard.js.map +1 -1
- package/dist/bigconsole/components/parser/ParserSelector.js +191 -174
- package/dist/bigconsole/components/parser/ParserSelector.js.map +1 -1
- package/dist/bigconsole/components/parser/ParserStatusBadge.js +2 -2
- package/dist/bigconsole/components/parser/ParserStatusBadge.js.map +1 -1
- package/dist/bigconsole/components/parser/ParserTypeBadge.js +4 -4
- package/dist/bigconsole/components/parser/ParserTypeBadge.js.map +1 -1
- package/dist/bigconsole/components/pipeline/PipelineCard.js +134 -89
- package/dist/bigconsole/components/pipeline/PipelineCard.js.map +1 -1
- package/dist/bigconsole/components/pipeline/PipelineDeleteDialog.js +77 -64
- package/dist/bigconsole/components/pipeline/PipelineDeleteDialog.js.map +1 -1
- package/dist/bigconsole/components/pipeline/PipelineStatusBadge.js +7 -10
- package/dist/bigconsole/components/pipeline/PipelineStatusBadge.js.map +1 -1
- package/dist/bigconsole/components/preview/AiPreviewContent.js +31 -32
- package/dist/bigconsole/components/preview/AiPreviewContent.js.map +1 -1
- package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js +152 -106
- package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js.map +1 -1
- package/dist/bigconsole/components/preview/AiPreviewPanel.js +193 -152
- package/dist/bigconsole/components/preview/AiPreviewPanel.js.map +1 -1
- package/dist/bigconsole/components/preview/previewShared.js +41 -23
- package/dist/bigconsole/components/preview/previewShared.js.map +1 -1
- package/dist/bigconsole/components/widgets/ActionConfigDialog.js +342 -308
- package/dist/bigconsole/components/widgets/ActionConfigDialog.js.map +1 -1
- package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js +262 -238
- package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/PropertiesPanel.js +783 -867
- package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetErrorBoundary.js +7 -5
- package/dist/bigconsole/components/widgets/WidgetErrorBoundary.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetHeader.js +7 -8
- package/dist/bigconsole/components/widgets/WidgetHeader.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetRegistry.js +4 -4
- package/dist/bigconsole/components/widgets/WidgetRegistry.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetWrapper.js +8 -7
- package/dist/bigconsole/components/widgets/WidgetWrapper.js.map +1 -1
- package/dist/bigconsole/components/widgets/adaptive-card/AdaptiveCardWidget.js +1 -1
- package/dist/bigconsole/components/widgets/adaptive-card/AdaptiveCardWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js +2 -2
- package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/chart/ChartConfig.js +11 -5
- package/dist/bigconsole/components/widgets/chart/ChartConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/comments/WidgetComments.js +19 -15
- package/dist/bigconsole/components/widgets/comments/WidgetComments.js.map +1 -1
- package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js +154 -102
- package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js.map +1 -1
- package/dist/bigconsole/components/widgets/gauge/CircularGauge.js +36 -32
- package/dist/bigconsole/components/widgets/gauge/CircularGauge.js.map +1 -1
- package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js +85 -60
- package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/gauge/GaugeWidget.js +64 -35
- package/dist/bigconsole/components/widgets/gauge/GaugeWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/gauge/LinearGauge.js +46 -45
- package/dist/bigconsole/components/widgets/gauge/LinearGauge.js.map +1 -1
- package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js +35 -24
- package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/iframe-widget/IframeWidget.js +2 -2
- package/dist/bigconsole/components/widgets/iframe-widget/IframeWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +4 -4
- package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js +153 -90
- package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/list/ListConfig.js +8 -2
- package/dist/bigconsole/components/widgets/list/ListConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/list/ListItem.js +1 -1
- package/dist/bigconsole/components/widgets/list/ListItem.js.map +1 -1
- package/dist/bigconsole/components/widgets/map-widget/MapWidget.js +1 -1
- package/dist/bigconsole/components/widgets/map-widget/MapWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js +14 -4
- package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js +112 -89
- package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js +21 -13
- package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/index.js +4 -4
- package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js +3 -3
- package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/progress/ProgressConfig.js +34 -25
- package/dist/bigconsole/components/widgets/progress/ProgressConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/progress/ProgressWidget.js +129 -114
- package/dist/bigconsole/components/widgets/progress/ProgressWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/retention/RetentionWidget.js +3 -3
- package/dist/bigconsole/components/widgets/retention/RetentionWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/states/EmptyState.js +6 -4
- package/dist/bigconsole/components/widgets/states/EmptyState.js.map +1 -1
- package/dist/bigconsole/components/widgets/states/ErrorState.js +7 -5
- package/dist/bigconsole/components/widgets/states/ErrorState.js.map +1 -1
- package/dist/bigconsole/components/widgets/states/LoadingState.js +5 -4
- package/dist/bigconsole/components/widgets/states/LoadingState.js.map +1 -1
- package/dist/bigconsole/components/widgets/table/TableConfig.js +10 -4
- package/dist/bigconsole/components/widgets/table/TableConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/table/TableHeader.js +1 -1
- package/dist/bigconsole/components/widgets/table/TableHeader.js.map +1 -1
- package/dist/bigconsole/components/widgets/table/TableWidget.js +1 -1
- package/dist/bigconsole/components/widgets/table/TableWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/text-widget/TextWidget.js +1 -1
- package/dist/bigconsole/components/widgets/text-widget/TextWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js +3 -3
- package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/utils/conditionalFormat.js +2 -2
- package/dist/bigconsole/components/widgets/utils/conditionalFormat.js.map +1 -1
- package/dist/bigconsole/components/widgets/utils/targetProgress.js +13 -0
- package/dist/bigconsole/components/widgets/utils/targetProgress.js.map +1 -0
- package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js +112 -85
- package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js +28 -20
- package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js.map +1 -1
- package/dist/bigconsole/components/workflow/WorkflowCard.js +92 -77
- package/dist/bigconsole/components/workflow/WorkflowCard.js.map +1 -1
- package/dist/bigconsole/components/workflow/WorkflowDeleteDialog.js +70 -51
- package/dist/bigconsole/components/workflow/WorkflowDeleteDialog.js.map +1 -1
- package/dist/bigconsole/components/workflow/WorkflowStatusBadge.js +16 -17
- package/dist/bigconsole/components/workflow/WorkflowStatusBadge.js.map +1 -1
- package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js +6 -4
- package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js.map +1 -1
- package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js +360 -338
- package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js.map +1 -1
- package/dist/bigconsole/hooks/useModalFocusTrap.js +53 -0
- package/dist/bigconsole/hooks/useModalFocusTrap.js.map +1 -0
- package/dist/bigconsole/pages/DashboardBuilderPage.js +209 -203
- package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/DashboardViewPage.js +126 -120
- package/dist/bigconsole/pages/DashboardViewPage.js.map +1 -1
- package/dist/bigconsole/pages/DashboardsPage.js +838 -800
- package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
- package/dist/bigconsole/pages/DataParsersPage.js +263 -315
- package/dist/bigconsole/pages/DataParsersPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkBuilderPage.js +301 -341
- package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkViewPage.js +346 -339
- package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinksPage.js +356 -458
- package/dist/bigconsole/pages/DataSinksPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSourcesPage.js +7 -2
- package/dist/bigconsole/pages/DataSourcesPage.js.map +1 -1
- package/dist/bigconsole/pages/HomePage.js +186 -193
- package/dist/bigconsole/pages/HomePage.js.map +1 -1
- package/dist/bigconsole/pages/InsightsPage.js +887 -740
- package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
- package/dist/bigconsole/pages/ParserBuilderPage.js +679 -637
- package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/ParserViewPage.js +368 -342
- package/dist/bigconsole/pages/ParserViewPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelineBuilderPage.js +537 -444
- package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelineViewPage.js +412 -377
- package/dist/bigconsole/pages/PipelineViewPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelinesPage.js +248 -298
- package/dist/bigconsole/pages/PipelinesPage.js.map +1 -1
- package/dist/bigconsole/pages/WidgetDemoPage.js +251 -153
- package/dist/bigconsole/pages/WidgetDemoPage.js.map +1 -1
- package/dist/bigconsole/pages/WorkflowViewPage.js +381 -371
- package/dist/bigconsole/pages/WorkflowViewPage.js.map +1 -1
- package/dist/bigconsole/pages/WorkflowsPage.js +171 -286
- package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SavedViewsDropdown.js","names":[],"sources":["../../../../../src/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.tsx"],"sourcesContent":["/**\n * SavedViewsDropdown Component\n *\n * Dropdown for managing and switching between saved dashboard views.\n */\n\nimport React, { useState, useEffect, useCallback, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useDashboardViews, type DashboardView } from '../../../hooks';\nimport { SEMANTIC_COLORS } from '../../../utils/semanticTokens';\nimport { reportBigConsoleQuotaError } from '../../../utils/quota';\n\n// ============================================================================\n// Solid Background Colors (for portal-rendered dropdowns)\n// ============================================================================\n\n// Hook to detect dark mode and provide solid background color\nfunction useSolidBackground() {\n const [isDark, setIsDark] = useState(false);\n\n useEffect(() => {\n const checkDarkMode = () => {\n setIsDark(document.documentElement.classList.contains('dark'));\n };\n checkDarkMode();\n\n const observer = new MutationObserver(checkDarkMode);\n observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] });\n return () => observer.disconnect();\n }, []);\n\n // Return solid opaque colors - no transparency\n return isDark ? '#1f2937' : '#ffffff';\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface SavedViewsDropdownProps {\n dashboardId: string;\n currentFilters?: Record<string, unknown>;\n currentLayout?: Record<string, unknown>;\n onViewLoad?: (view: DashboardView) => void;\n className?: string;\n}\n\n// Use shared semantic tokens for portal rendering\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport function SavedViewsDropdown({\n dashboardId,\n currentFilters,\n currentLayout,\n onViewLoad,\n className = '',\n}: SavedViewsDropdownProps) {\n const { t } = useI18n();\n const {\n views,\n currentView,\n loading,\n fetchViews,\n saveCurrentView,\n loadView,\n updateView,\n deleteView,\n setAsDefault,\n clearCurrentView,\n } = useDashboardViews();\n\n const [isOpen, setIsOpen] = useState(false);\n const [showSaveDialog, setShowSaveDialog] = useState(false);\n const [newViewName, setNewViewName] = useState('');\n const [newViewDescription, setNewViewDescription] = useState('');\n const [saveAsDefault, setSaveAsDefault] = useState(false);\n const [dropdownPosition, setDropdownPosition] = useState({ top: 0, left: 0 });\n\n const buttonRef = useRef<HTMLButtonElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n // Get solid background color for portal-rendered dropdown (no transparency)\n const solidBgColor = useSolidBackground();\n\n // Fetch views on mount\n useEffect(() => {\n if (dashboardId) {\n fetchViews(dashboardId);\n }\n }, [dashboardId, fetchViews]);\n\n // Update dropdown position when opening\n useEffect(() => {\n if (isOpen && buttonRef.current) {\n const rect = buttonRef.current.getBoundingClientRect();\n const dropdownWidth = 280;\n\n // Calculate left position - align left edge with button, but ensure it doesn't go off screen\n let leftPos = rect.left;\n\n // If dropdown would go off the right edge of screen, align right edge with button instead\n if (leftPos + dropdownWidth > window.innerWidth - 16) {\n leftPos = rect.right - dropdownWidth;\n }\n\n // Ensure minimum left margin\n leftPos = Math.max(16, leftPos);\n\n setDropdownPosition({\n top: rect.bottom + 4,\n left: leftPos,\n });\n }\n }, [isOpen]);\n\n // Close dropdown when clicking outside\n useEffect(() => {\n function handleClickOutside(event: MouseEvent) {\n const target = event.target as Node;\n if (\n buttonRef.current &&\n !buttonRef.current.contains(target) &&\n dropdownRef.current &&\n !dropdownRef.current.contains(target)\n ) {\n setIsOpen(false);\n }\n }\n\n if (isOpen) {\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }\n }, [isOpen]);\n\n // Handle view selection\n const handleSelectView = useCallback(\n (viewId: string) => {\n const view = views.find((v) => v.id === viewId);\n if (view) {\n loadView(viewId);\n if (onViewLoad) {\n onViewLoad(view);\n }\n }\n setIsOpen(false);\n },\n [views, loadView, onViewLoad]\n );\n\n // Handle save new view\n const handleSaveView = useCallback(async () => {\n if (!newViewName.trim()) return;\n\n try {\n await saveCurrentView({\n dashboardId,\n name: newViewName.trim(),\n description: newViewDescription.trim() || undefined,\n filters: currentFilters,\n layout: currentLayout,\n isDefault: saveAsDefault,\n });\n } catch (err) {\n if (reportBigConsoleQuotaError(err, 'session')) {\n setShowSaveDialog(false);\n setIsOpen(false);\n return;\n }\n throw err;\n }\n\n setNewViewName('');\n setNewViewDescription('');\n setSaveAsDefault(false);\n setShowSaveDialog(false);\n }, [dashboardId, newViewName, newViewDescription, currentFilters, currentLayout, saveAsDefault, saveCurrentView]);\n\n // Handle update current view\n const handleUpdateCurrentView = useCallback(async () => {\n if (!currentView) return;\n\n await updateView({\n id: currentView.id,\n filters: currentFilters,\n layout: currentLayout,\n });\n }, [currentView, currentFilters, currentLayout, updateView]);\n\n // Handle delete view\n const handleDeleteView = useCallback(\n async (viewId: string, e: React.MouseEvent) => {\n e.stopPropagation();\n if (\n window.confirm(\n t('bigconsole.dashboards.savedViews.confirmDelete', 'Are you sure you want to delete this view?')\n )\n ) {\n await deleteView(viewId);\n }\n },\n [deleteView, t]\n );\n\n // Handle set as default\n const handleSetDefault = useCallback(\n async (viewId: string, e: React.MouseEvent) => {\n e.stopPropagation();\n await setAsDefault(viewId);\n },\n [setAsDefault]\n );\n\n // Clear current view\n const handleClearView = useCallback(() => {\n clearCurrentView();\n setIsOpen(false);\n }, [clearCurrentView]);\n\n // Dropdown Menu rendered via portal\n const dropdownMenu = isOpen\n ? createPortal(\n <div\n ref={dropdownRef}\n style={{\n position: 'fixed',\n top: dropdownPosition.top,\n left: Math.max(16, dropdownPosition.left), // Ensure minimum left margin\n minWidth: '280px',\n backgroundColor: solidBgColor, // Solid opaque background - no transparency\n border: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n borderRadius: '8px',\n boxShadow: '0 8px 24px rgba(0,0,0,0.15), 0 4px 8px rgba(0,0,0,0.1)',\n zIndex: 99998,\n overflow: 'hidden',\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: '12px 16px',\n borderBottom: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n }}\n >\n <span style={{ fontSize: '13px', fontWeight: 600, color: SEMANTIC_COLORS.textPrimary }}>\n {t('bigconsole.dashboards.savedViews.header', 'Saved Views')}\n </span>\n <button\n onClick={() => setShowSaveDialog(true)}\n style={{\n padding: '4px 10px',\n backgroundColor: SEMANTIC_COLORS.actionPrimaryBg,\n color: 'white',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n fontSize: '12px',\n }}\n >\n {t('bigconsole.dashboards.savedViews.saveCurrent', '+ Save Current')}\n </button>\n </div>\n\n {/* Views List */}\n <div style={{ maxHeight: '300px', overflowY: 'auto' }}>\n {loading && views.length === 0 ? (\n <div style={{ padding: '16px', color: SEMANTIC_COLORS.textSecondary, fontSize: '13px' }}>\n {t('bigconsole.dashboards.savedViews.loading', 'Loading views...')}\n </div>\n ) : views.length === 0 ? (\n <div style={{ padding: '16px', color: SEMANTIC_COLORS.textSecondary, fontSize: '13px' }}>\n {t(\n 'bigconsole.dashboards.savedViews.empty',\n 'No saved views yet. Save your current view to get started.'\n )}\n </div>\n ) : (\n <>\n {/* Reset to Default Option */}\n <button\n onClick={handleClearView}\n style={{\n display: 'flex',\n alignItems: 'center',\n width: '100%',\n padding: '10px 16px',\n backgroundColor: !currentView ? SEMANTIC_COLORS.bgSecondary : SEMANTIC_COLORS.bgPrimary,\n border: 'none',\n cursor: 'pointer',\n textAlign: 'left',\n borderBottom: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n }}\n >\n <div>\n <div style={{ fontSize: '13px', fontWeight: 500, color: SEMANTIC_COLORS.textPrimary }}>\n {t('bigconsole.dashboards.savedViews.defaultView', 'Default View')}\n </div>\n <div style={{ fontSize: '11px', color: SEMANTIC_COLORS.textSecondary }}>\n {t('bigconsole.dashboards.savedViews.defaultViewHint', 'Reset to original dashboard state')}\n </div>\n </div>\n </button>\n\n {/* Saved Views */}\n {views.map((view) => (\n <div\n key={view.id}\n onClick={() => handleSelectView(view.id)}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '10px 16px',\n backgroundColor:\n currentView?.id === view.id ? SEMANTIC_COLORS.bgSecondary : SEMANTIC_COLORS.bgPrimary,\n cursor: 'pointer',\n borderBottom: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n }}\n >\n <div style={{ flex: 1 }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '6px' }}>\n <span\n style={{\n fontSize: '13px',\n fontWeight: 500,\n color: SEMANTIC_COLORS.textPrimary,\n }}\n >\n {view.name}\n </span>\n {view.isDefault && (\n <span\n style={{\n fontSize: '9px',\n padding: '2px 4px',\n backgroundColor: SEMANTIC_COLORS.actionPrimaryBgSubtle,\n color: SEMANTIC_COLORS.actionPrimaryBg,\n borderRadius: '4px',\n textTransform: 'uppercase',\n fontWeight: 600,\n }}\n >\n {t('bigconsole.dashboards.savedViews.defaultBadge', 'Default')}\n </span>\n )}\n </div>\n {view.description && (\n <div style={{ fontSize: '11px', color: SEMANTIC_COLORS.textSecondary, marginTop: '2px' }}>\n {view.description}\n </div>\n )}\n <div style={{ fontSize: '10px', color: SEMANTIC_COLORS.textSecondary, marginTop: '2px' }}>\n {new Date(view.updatedAt).toLocaleDateString()}\n </div>\n </div>\n <div style={{ display: 'flex', alignItems: 'center', gap: '4px' }}>\n {!view.isDefault && (\n <button\n onClick={(e) => handleSetDefault(view.id, e)}\n title={t('bigconsole.dashboards.savedViews.setAsDefaultTitle', 'Set as default')}\n style={{\n padding: '4px 6px',\n backgroundColor: 'transparent',\n border: 'none',\n cursor: 'pointer',\n color: SEMANTIC_COLORS.textSecondary,\n fontSize: '11px',\n }}\n >\n {t('bigconsole.dashboards.savedViews.setDefault', 'Set Default')}\n </button>\n )}\n <button\n onClick={(e) => handleDeleteView(view.id, e)}\n title={t('bigconsole.dashboards.savedViews.deleteViewTitle', 'Delete view')}\n style={{\n padding: '4px 6px',\n backgroundColor: 'transparent',\n border: 'none',\n cursor: 'pointer',\n color: SEMANTIC_COLORS.statusErrorText,\n fontSize: '11px',\n }}\n >\n {t('bigconsole.dashboards.savedViews.delete', 'Delete')}\n </button>\n </div>\n </div>\n ))}\n </>\n )}\n </div>\n\n {/* Update Current View Button */}\n {currentView && (\n <div\n style={{\n padding: '12px 16px',\n borderTop: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n backgroundColor: SEMANTIC_COLORS.bgSecondary,\n }}\n >\n <button\n onClick={handleUpdateCurrentView}\n style={{\n width: '100%',\n padding: '8px',\n backgroundColor: SEMANTIC_COLORS.bgPrimary,\n border: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n borderRadius: '4px',\n cursor: 'pointer',\n fontSize: '12px',\n color: SEMANTIC_COLORS.textPrimary,\n }}\n >\n {t('bigconsole.dashboards.savedViews.updateCurrent', 'Update \"{{name}}\" with current state', {\n name: currentView.name ?? '',\n })}\n </button>\n </div>\n )}\n </div>,\n document.body\n )\n : null;\n\n // Save Dialog rendered via portal\n const saveDialog = showSaveDialog\n ? createPortal(\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.5)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 99999,\n isolation: 'isolate',\n }}\n onClick={() => setShowSaveDialog(false)}\n >\n <div\n style={{\n width: '400px',\n backgroundColor: solidBgColor, // Solid opaque background - no transparency\n borderRadius: '8px',\n boxShadow: '0 4px 24px rgba(0, 0, 0, 0.3)',\n overflow: 'hidden',\n position: 'relative',\n zIndex: 100000,\n color: SEMANTIC_COLORS.textPrimary,\n }}\n onClick={(e) => e.stopPropagation()}\n >\n <div\n style={{\n padding: '16px 20px',\n borderBottom: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n }}\n >\n <h3 style={{ margin: 0, fontSize: '16px', fontWeight: 600, color: SEMANTIC_COLORS.textPrimary }}>\n {t('bigconsole.dashboards.savedViews.saveDialog.title', 'Save Current View')}\n </h3>\n </div>\n <div style={{ padding: '20px' }}>\n <div style={{ marginBottom: '16px' }}>\n <label\n style={{\n display: 'block',\n marginBottom: '6px',\n fontSize: '13px',\n fontWeight: 500,\n color: SEMANTIC_COLORS.textPrimary,\n }}\n >\n {t('bigconsole.dashboards.savedViews.saveDialog.nameLabel', 'View Name *')}\n </label>\n <input\n type=\"text\"\n value={newViewName}\n onChange={(e) => setNewViewName(e.target.value)}\n placeholder={t(\n 'bigconsole.dashboards.savedViews.saveDialog.namePlaceholder',\n 'e.g., Q4 Analysis, Sales Overview'\n )}\n style={{\n width: '100%',\n padding: '10px 12px',\n border: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n borderRadius: '6px',\n fontSize: '14px',\n backgroundColor: SEMANTIC_COLORS.bgPrimary,\n color: SEMANTIC_COLORS.textPrimary,\n boxSizing: 'border-box',\n }}\n />\n </div>\n <div style={{ marginBottom: '16px' }}>\n <label\n style={{\n display: 'block',\n marginBottom: '6px',\n fontSize: '13px',\n fontWeight: 500,\n color: SEMANTIC_COLORS.textPrimary,\n }}\n >\n {t('bigconsole.dashboards.savedViews.saveDialog.descriptionLabel', 'Description')}\n </label>\n <textarea\n value={newViewDescription}\n onChange={(e) => setNewViewDescription(e.target.value)}\n placeholder={t(\n 'bigconsole.dashboards.savedViews.saveDialog.descriptionPlaceholder',\n 'Optional description...'\n )}\n rows={2}\n style={{\n width: '100%',\n padding: '10px 12px',\n border: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n borderRadius: '6px',\n fontSize: '14px',\n resize: 'vertical',\n backgroundColor: SEMANTIC_COLORS.bgPrimary,\n color: SEMANTIC_COLORS.textPrimary,\n boxSizing: 'border-box',\n }}\n />\n </div>\n <label style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer' }}>\n <input type=\"checkbox\" checked={saveAsDefault} onChange={(e) => setSaveAsDefault(e.target.checked)} />\n <span style={{ fontSize: '13px', color: SEMANTIC_COLORS.textPrimary }}>\n {t('bigconsole.dashboards.savedViews.saveDialog.setAsDefault', 'Set as default view')}\n </span>\n </label>\n </div>\n <div\n style={{\n padding: '16px 20px',\n borderTop: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n display: 'flex',\n justifyContent: 'flex-end',\n gap: '12px',\n backgroundColor: SEMANTIC_COLORS.bgSecondary,\n }}\n >\n <button\n onClick={() => setShowSaveDialog(false)}\n style={{\n padding: '10px 20px',\n backgroundColor: SEMANTIC_COLORS.bgPrimary,\n border: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n borderRadius: '6px',\n cursor: 'pointer',\n fontSize: '14px',\n color: SEMANTIC_COLORS.textPrimary,\n }}\n >\n {t('bigconsole.dashboards.savedViews.saveDialog.cancel', 'Cancel')}\n </button>\n <button\n onClick={handleSaveView}\n disabled={!newViewName.trim()}\n style={{\n padding: '10px 20px',\n backgroundColor: newViewName.trim() ? SEMANTIC_COLORS.actionPrimaryBg : SEMANTIC_COLORS.bgSecondary,\n color: newViewName.trim() ? 'white' : SEMANTIC_COLORS.textSecondary,\n border: 'none',\n borderRadius: '6px',\n cursor: newViewName.trim() ? 'pointer' : 'not-allowed',\n fontSize: '14px',\n fontWeight: 500,\n }}\n >\n {t('bigconsole.dashboards.savedViews.saveDialog.save', 'Save View')}\n </button>\n </div>\n </div>\n </div>,\n document.body\n )\n : null;\n\n return (\n <div className={className} style={{ position: 'relative', display: 'inline-block' }}>\n {/* Trigger Button */}\n <button\n ref={buttonRef}\n onClick={() => setIsOpen(!isOpen)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n padding: '6px 12px',\n backgroundColor: currentView ? SEMANTIC_COLORS.actionPrimaryBgSubtle : SEMANTIC_COLORS.bgSecondary,\n border: `1px solid ${currentView ? SEMANTIC_COLORS.actionPrimaryBg : SEMANTIC_COLORS.borderDefault}`,\n borderRadius: '6px',\n cursor: 'pointer',\n fontSize: '13px',\n color: currentView ? SEMANTIC_COLORS.actionPrimaryBg : SEMANTIC_COLORS.textPrimary,\n }}\n >\n <span style={{ fontWeight: 500 }}>\n {currentView ? currentView.name : t('bigconsole.dashboards.savedViews.triggerLabel', 'Views')}\n </span>\n <span style={{ fontSize: '10px' }}>{isOpen ? '▲' : '▼'}</span>\n </button>\n\n {/* Dropdown Menu - rendered via portal */}\n {dropdownMenu}\n\n {/* Save Dialog - rendered via portal */}\n {saveDialog}\n </div>\n );\n}\n\nexport default SavedViewsDropdown;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SavedViewsDropdown.js","names":[],"sources":["../../../../../src/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.tsx"],"sourcesContent":["/**\n * SavedViewsDropdown Component\n *\n * Dropdown for managing and switching between saved dashboard views.\n */\n\nimport React, { useState, useEffect, useCallback, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useDashboardViews, type DashboardView } from '../../../hooks';\nimport { SEMANTIC_COLORS } from '../../../utils/semanticTokens';\nimport { reportBigConsoleQuotaError } from '../../../utils/quota';\n\n// ============================================================================\n// Solid Background Colors (for portal-rendered dropdowns)\n// ============================================================================\n\n// Hook to detect dark mode and provide solid background color\nfunction useSolidBackground() {\n const [isDark, setIsDark] = useState(false);\n\n useEffect(() => {\n const checkDarkMode = () => {\n setIsDark(document.documentElement.classList.contains('dark'));\n };\n checkDarkMode();\n\n const observer = new MutationObserver(checkDarkMode);\n observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] });\n return () => observer.disconnect();\n }, []);\n\n // Return solid opaque colors - no transparency\n return isDark ? '#1f2937' : '#ffffff';\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface SavedViewsDropdownProps {\n dashboardId: string;\n currentFilters?: Record<string, unknown>;\n currentLayout?: Record<string, unknown>;\n onViewLoad?: (view: DashboardView) => void;\n className?: string;\n}\n\n// Use shared semantic tokens for portal rendering\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport function SavedViewsDropdown({\n dashboardId,\n currentFilters,\n currentLayout,\n onViewLoad,\n className = '',\n}: SavedViewsDropdownProps) {\n const { t } = useI18n();\n const {\n views,\n currentView,\n loading,\n fetchViews,\n saveCurrentView,\n loadView,\n updateView,\n deleteView,\n setAsDefault,\n clearCurrentView,\n } = useDashboardViews();\n\n const [isOpen, setIsOpen] = useState(false);\n const [showSaveDialog, setShowSaveDialog] = useState(false);\n const [newViewName, setNewViewName] = useState('');\n const [newViewDescription, setNewViewDescription] = useState('');\n const [saveAsDefault, setSaveAsDefault] = useState(false);\n const [dropdownPosition, setDropdownPosition] = useState({ top: 0, left: 0 });\n\n const buttonRef = useRef<HTMLButtonElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n // Get solid background color for portal-rendered dropdown (no transparency)\n const solidBgColor = useSolidBackground();\n\n // Fetch views on mount\n useEffect(() => {\n if (dashboardId) {\n fetchViews(dashboardId);\n }\n }, [dashboardId, fetchViews]);\n\n // Update dropdown position when opening\n useEffect(() => {\n if (isOpen && buttonRef.current) {\n const rect = buttonRef.current.getBoundingClientRect();\n const dropdownWidth = 280;\n\n // Calculate left position - align left edge with button, but ensure it doesn't go off screen\n let leftPos = rect.left;\n\n // If dropdown would go off the right edge of screen, align right edge with button instead\n if (leftPos + dropdownWidth > window.innerWidth - 16) {\n leftPos = rect.right - dropdownWidth;\n }\n\n // Ensure minimum left margin\n leftPos = Math.max(16, leftPos);\n\n setDropdownPosition({\n top: rect.bottom + 4,\n left: leftPos,\n });\n }\n }, [isOpen]);\n\n // Close dropdown when clicking outside\n useEffect(() => {\n function handleClickOutside(event: MouseEvent) {\n const target = event.target as Node;\n if (\n buttonRef.current &&\n !buttonRef.current.contains(target) &&\n dropdownRef.current &&\n !dropdownRef.current.contains(target)\n ) {\n setIsOpen(false);\n }\n }\n\n if (isOpen) {\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }\n }, [isOpen]);\n\n // Handle view selection\n const handleSelectView = useCallback(\n (viewId: string) => {\n const view = views.find((v) => v.id === viewId);\n if (view) {\n loadView(viewId);\n if (onViewLoad) {\n onViewLoad(view);\n }\n }\n setIsOpen(false);\n },\n [views, loadView, onViewLoad]\n );\n\n // Handle save new view\n const handleSaveView = useCallback(async () => {\n if (!newViewName.trim()) return;\n\n try {\n await saveCurrentView({\n dashboardId,\n name: newViewName.trim(),\n description: newViewDescription.trim() || undefined,\n filters: currentFilters,\n layout: currentLayout,\n isDefault: saveAsDefault,\n });\n } catch (err) {\n if (reportBigConsoleQuotaError(err, 'session')) {\n setShowSaveDialog(false);\n setIsOpen(false);\n return;\n }\n throw err;\n }\n\n setNewViewName('');\n setNewViewDescription('');\n setSaveAsDefault(false);\n setShowSaveDialog(false);\n }, [dashboardId, newViewName, newViewDescription, currentFilters, currentLayout, saveAsDefault, saveCurrentView]);\n\n // Handle update current view\n const handleUpdateCurrentView = useCallback(async () => {\n if (!currentView) return;\n\n await updateView({\n id: currentView.id,\n filters: currentFilters,\n layout: currentLayout,\n });\n }, [currentView, currentFilters, currentLayout, updateView]);\n\n // Handle delete view\n const handleDeleteView = useCallback(\n async (viewId: string, e: React.MouseEvent) => {\n e.stopPropagation();\n if (\n window.confirm(\n t('bigconsole.dashboards.savedViews.confirmDelete', 'Are you sure you want to delete this view?')\n )\n ) {\n await deleteView(viewId);\n }\n },\n [deleteView, t]\n );\n\n // Handle set as default\n const handleSetDefault = useCallback(\n async (viewId: string, e: React.MouseEvent) => {\n e.stopPropagation();\n await setAsDefault(viewId);\n },\n [setAsDefault]\n );\n\n // Clear current view\n const handleClearView = useCallback(() => {\n clearCurrentView();\n setIsOpen(false);\n }, [clearCurrentView]);\n\n // Dropdown Menu rendered via portal\n const dropdownMenu = isOpen\n ? createPortal(\n <div\n ref={dropdownRef}\n style={{\n position: 'fixed',\n top: dropdownPosition.top,\n left: Math.max(16, dropdownPosition.left), // Ensure minimum left margin\n minWidth: 'min(280px, calc(100vw - 2rem))',\n maxWidth: 'calc(100vw - 2rem)',\n backgroundColor: solidBgColor, // Solid opaque background - no transparency\n border: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n borderRadius: '8px',\n boxShadow: 'var(--shadow-elevation-3)',\n zIndex: 99998,\n overflow: 'hidden',\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: '12px 16px',\n borderBottom: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n }}\n >\n <span style={{ fontSize: '13px', fontWeight: 600, color: SEMANTIC_COLORS.textPrimary }}>\n {t('bigconsole.dashboards.savedViews.header', 'Saved Views')}\n </span>\n <button\n onClick={() => setShowSaveDialog(true)}\n style={{\n padding: '4px 10px',\n backgroundColor: SEMANTIC_COLORS.actionPrimaryBg,\n color: 'var(--color-action-primary-text)',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n fontSize: '12px',\n }}\n >\n {t('bigconsole.dashboards.savedViews.saveCurrent', '+ Save Current')}\n </button>\n </div>\n\n {/* Views List */}\n <div style={{ maxHeight: '300px', overflowY: 'auto' }}>\n {loading && views.length === 0 ? (\n <div style={{ padding: '16px', color: SEMANTIC_COLORS.textSecondary, fontSize: '13px' }}>\n {t('bigconsole.dashboards.savedViews.loading', 'Loading views...')}\n </div>\n ) : views.length === 0 ? (\n <div style={{ padding: '16px', color: SEMANTIC_COLORS.textSecondary, fontSize: '13px' }}>\n {t(\n 'bigconsole.dashboards.savedViews.empty',\n 'No saved views yet. Save your current view to get started.'\n )}\n </div>\n ) : (\n <>\n {/* Reset to Default Option */}\n <button\n onClick={handleClearView}\n style={{\n display: 'flex',\n alignItems: 'center',\n width: '100%',\n padding: '10px 16px',\n backgroundColor: !currentView ? SEMANTIC_COLORS.bgSecondary : SEMANTIC_COLORS.bgPrimary,\n border: 'none',\n cursor: 'pointer',\n textAlign: 'left',\n borderBottom: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n }}\n >\n <div>\n <div style={{ fontSize: '13px', fontWeight: 500, color: SEMANTIC_COLORS.textPrimary }}>\n {t('bigconsole.dashboards.savedViews.defaultView', 'Default View')}\n </div>\n <div style={{ fontSize: '11px', color: SEMANTIC_COLORS.textSecondary }}>\n {t('bigconsole.dashboards.savedViews.defaultViewHint', 'Reset to original dashboard state')}\n </div>\n </div>\n </button>\n\n {/* Saved Views */}\n {views.map((view) => (\n <div\n key={view.id}\n onClick={() => handleSelectView(view.id)}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '10px 16px',\n backgroundColor:\n currentView?.id === view.id ? SEMANTIC_COLORS.bgSecondary : SEMANTIC_COLORS.bgPrimary,\n cursor: 'pointer',\n borderBottom: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n }}\n >\n <div style={{ flex: 1 }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '6px' }}>\n <span\n style={{\n fontSize: '13px',\n fontWeight: 500,\n color: SEMANTIC_COLORS.textPrimary,\n }}\n >\n {view.name}\n </span>\n {view.isDefault && (\n <span\n style={{\n fontSize: '9px',\n padding: '2px 4px',\n backgroundColor: SEMANTIC_COLORS.actionPrimaryBgSubtle,\n color: SEMANTIC_COLORS.actionPrimaryBg,\n borderRadius: '4px',\n textTransform: 'uppercase',\n fontWeight: 600,\n }}\n >\n {t('bigconsole.dashboards.savedViews.defaultBadge', 'Default')}\n </span>\n )}\n </div>\n {view.description && (\n <div style={{ fontSize: '11px', color: SEMANTIC_COLORS.textSecondary, marginTop: '2px' }}>\n {view.description}\n </div>\n )}\n <div style={{ fontSize: '10px', color: SEMANTIC_COLORS.textSecondary, marginTop: '2px' }}>\n {new Date(view.updatedAt).toLocaleDateString()}\n </div>\n </div>\n <div style={{ display: 'flex', alignItems: 'center', gap: '4px' }}>\n {!view.isDefault && (\n <button\n onClick={(e) => handleSetDefault(view.id, e)}\n title={t('bigconsole.dashboards.savedViews.setAsDefaultTitle', 'Set as default')}\n style={{\n padding: '4px 6px',\n backgroundColor: 'transparent',\n border: 'none',\n cursor: 'pointer',\n color: SEMANTIC_COLORS.textSecondary,\n fontSize: '11px',\n }}\n >\n {t('bigconsole.dashboards.savedViews.setDefault', 'Set Default')}\n </button>\n )}\n <button\n onClick={(e) => handleDeleteView(view.id, e)}\n title={t('bigconsole.dashboards.savedViews.deleteViewTitle', 'Delete view')}\n style={{\n padding: '4px 6px',\n backgroundColor: 'transparent',\n border: 'none',\n cursor: 'pointer',\n color: SEMANTIC_COLORS.statusErrorText,\n fontSize: '11px',\n }}\n >\n {t('bigconsole.dashboards.savedViews.delete', 'Delete')}\n </button>\n </div>\n </div>\n ))}\n </>\n )}\n </div>\n\n {/* Update Current View Button */}\n {currentView && (\n <div\n style={{\n padding: '12px 16px',\n borderTop: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n backgroundColor: SEMANTIC_COLORS.bgSecondary,\n }}\n >\n <button\n onClick={handleUpdateCurrentView}\n style={{\n width: '100%',\n padding: '8px',\n backgroundColor: SEMANTIC_COLORS.bgPrimary,\n border: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n borderRadius: '4px',\n cursor: 'pointer',\n fontSize: '12px',\n color: SEMANTIC_COLORS.textPrimary,\n }}\n >\n {t('bigconsole.dashboards.savedViews.updateCurrent', 'Update \"{{name}}\" with current state', {\n name: currentView.name ?? '',\n })}\n </button>\n </div>\n )}\n </div>,\n document.body\n )\n : null;\n\n // Save Dialog rendered via portal\n const saveDialog = showSaveDialog\n ? createPortal(\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: 'var(--color-overlay-scrim)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n padding: 'var(--space-formGap)',\n zIndex: 99999,\n isolation: 'isolate',\n }}\n onClick={() => setShowSaveDialog(false)}\n >\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"saved-view-dialog-title\"\n style={{\n // was a hard 400px, which overflowed a 375px phone viewport\n width: '100%',\n maxWidth: '400px',\n maxHeight: '85vh',\n overflowY: 'auto',\n backgroundColor: solidBgColor, // Solid opaque background - no transparency\n borderRadius: 'var(--radius-card)',\n boxShadow: 'var(--shadow-elevation-3)',\n overflow: 'hidden',\n position: 'relative',\n zIndex: 100000,\n color: SEMANTIC_COLORS.textPrimary,\n }}\n onClick={(e) => e.stopPropagation()}\n >\n <div\n style={{\n padding: '16px 20px',\n borderBottom: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n }}\n >\n <h3\n id=\"saved-view-dialog-title\"\n style={{ margin: 0, fontSize: '16px', fontWeight: 600, color: SEMANTIC_COLORS.textPrimary }}\n >\n {t('bigconsole.dashboards.savedViews.saveDialog.title', 'Save Current View')}\n </h3>\n </div>\n <div style={{ padding: '20px' }}>\n <div style={{ marginBottom: '16px' }}>\n <label\n style={{\n display: 'block',\n marginBottom: '6px',\n fontSize: '13px',\n fontWeight: 500,\n color: SEMANTIC_COLORS.textPrimary,\n }}\n >\n {t('bigconsole.dashboards.savedViews.saveDialog.nameLabel', 'View Name *')}\n </label>\n <input\n type=\"text\"\n value={newViewName}\n onChange={(e) => setNewViewName(e.target.value)}\n placeholder={t(\n 'bigconsole.dashboards.savedViews.saveDialog.namePlaceholder',\n 'e.g., Q4 Analysis, Sales Overview'\n )}\n style={{\n width: '100%',\n padding: '10px 12px',\n border: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n borderRadius: '6px',\n fontSize: '14px',\n backgroundColor: SEMANTIC_COLORS.bgPrimary,\n color: SEMANTIC_COLORS.textPrimary,\n boxSizing: 'border-box',\n }}\n />\n </div>\n <div style={{ marginBottom: '16px' }}>\n <label\n style={{\n display: 'block',\n marginBottom: '6px',\n fontSize: '13px',\n fontWeight: 500,\n color: SEMANTIC_COLORS.textPrimary,\n }}\n >\n {t('bigconsole.dashboards.savedViews.saveDialog.descriptionLabel', 'Description')}\n </label>\n <textarea\n value={newViewDescription}\n onChange={(e) => setNewViewDescription(e.target.value)}\n placeholder={t(\n 'bigconsole.dashboards.savedViews.saveDialog.descriptionPlaceholder',\n 'Optional description...'\n )}\n rows={2}\n style={{\n width: '100%',\n padding: '10px 12px',\n border: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n borderRadius: '6px',\n fontSize: '14px',\n resize: 'vertical',\n backgroundColor: SEMANTIC_COLORS.bgPrimary,\n color: SEMANTIC_COLORS.textPrimary,\n boxSizing: 'border-box',\n }}\n />\n </div>\n <label style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer' }}>\n <input type=\"checkbox\" checked={saveAsDefault} onChange={(e) => setSaveAsDefault(e.target.checked)} />\n <span style={{ fontSize: '13px', color: SEMANTIC_COLORS.textPrimary }}>\n {t('bigconsole.dashboards.savedViews.saveDialog.setAsDefault', 'Set as default view')}\n </span>\n </label>\n </div>\n <div\n style={{\n padding: '16px 20px',\n borderTop: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n display: 'flex',\n justifyContent: 'flex-end',\n gap: '12px',\n backgroundColor: SEMANTIC_COLORS.bgSecondary,\n }}\n >\n <button\n onClick={() => setShowSaveDialog(false)}\n style={{\n padding: '10px 20px',\n backgroundColor: SEMANTIC_COLORS.bgPrimary,\n border: `1px solid ${SEMANTIC_COLORS.borderDefault}`,\n borderRadius: '6px',\n cursor: 'pointer',\n fontSize: '14px',\n color: SEMANTIC_COLORS.textPrimary,\n }}\n >\n {t('bigconsole.dashboards.savedViews.saveDialog.cancel', 'Cancel')}\n </button>\n <button\n onClick={handleSaveView}\n disabled={!newViewName.trim()}\n style={{\n padding: '10px 20px',\n backgroundColor: newViewName.trim() ? SEMANTIC_COLORS.actionPrimaryBg : SEMANTIC_COLORS.bgSecondary,\n color: newViewName.trim() ? 'var(--color-action-primary-text)' : SEMANTIC_COLORS.textSecondary,\n border: 'none',\n borderRadius: '6px',\n cursor: newViewName.trim() ? 'pointer' : 'not-allowed',\n fontSize: '14px',\n fontWeight: 500,\n }}\n >\n {t('bigconsole.dashboards.savedViews.saveDialog.save', 'Save View')}\n </button>\n </div>\n </div>\n </div>,\n document.body\n )\n : null;\n\n return (\n <div className={className} style={{ position: 'relative', display: 'inline-block' }}>\n {/* Trigger Button */}\n <button\n ref={buttonRef}\n onClick={() => setIsOpen(!isOpen)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n padding: '6px 12px',\n backgroundColor: currentView ? SEMANTIC_COLORS.actionPrimaryBgSubtle : SEMANTIC_COLORS.bgSecondary,\n border: `1px solid ${currentView ? SEMANTIC_COLORS.actionPrimaryBg : SEMANTIC_COLORS.borderDefault}`,\n borderRadius: '6px',\n cursor: 'pointer',\n fontSize: '13px',\n color: currentView ? SEMANTIC_COLORS.actionPrimaryBg : SEMANTIC_COLORS.textPrimary,\n }}\n >\n <span style={{ fontWeight: 500 }}>\n {currentView ? currentView.name : t('bigconsole.dashboards.savedViews.triggerLabel', 'Views')}\n </span>\n <span style={{ fontSize: '10px' }}>{isOpen ? '▲' : '▼'}</span>\n </button>\n\n {/* Dropdown Menu - rendered via portal */}\n {dropdownMenu}\n\n {/* Save Dialog - rendered via portal */}\n {saveDialog}\n </div>\n );\n}\n\nexport default SavedViewsDropdown;\n"],"mappings":"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"}
|
|
@@ -100,21 +100,30 @@ function f({ dashboardId: f, dashboardName: m, isOpen: h, onClose: g }) {
|
|
|
100
100
|
left: 0,
|
|
101
101
|
right: 0,
|
|
102
102
|
bottom: 0,
|
|
103
|
-
backgroundColor: "
|
|
103
|
+
backgroundColor: "var(--color-overlay-scrim)",
|
|
104
104
|
display: "flex",
|
|
105
105
|
alignItems: "center",
|
|
106
106
|
justifyContent: "center",
|
|
107
|
+
padding: "var(--space-formGap)",
|
|
107
108
|
zIndex: 99999,
|
|
108
109
|
isolation: "isolate"
|
|
109
110
|
},
|
|
110
111
|
onClick: g,
|
|
112
|
+
role: "presentation",
|
|
111
113
|
children: /* @__PURE__ */ c("div", {
|
|
114
|
+
role: "dialog",
|
|
115
|
+
"aria-modal": "true",
|
|
116
|
+
"aria-labelledby": "share-dialog-title",
|
|
117
|
+
"data-testid": "share-dialog",
|
|
112
118
|
style: {
|
|
113
|
-
width: "
|
|
114
|
-
|
|
119
|
+
width: "100%",
|
|
120
|
+
maxWidth: "520px",
|
|
121
|
+
maxHeight: "85vh",
|
|
122
|
+
display: "flex",
|
|
123
|
+
flexDirection: "column",
|
|
115
124
|
backgroundColor: G.bgPrimary,
|
|
116
|
-
borderRadius: "
|
|
117
|
-
boxShadow: "
|
|
125
|
+
borderRadius: "var(--radius-card)",
|
|
126
|
+
boxShadow: "var(--shadow-elevation-3)",
|
|
118
127
|
overflow: "hidden",
|
|
119
128
|
position: "relative",
|
|
120
129
|
zIndex: 1e5,
|
|
@@ -124,6 +133,7 @@ function f({ dashboardId: f, dashboardName: m, isOpen: h, onClose: g }) {
|
|
|
124
133
|
children: [
|
|
125
134
|
/* @__PURE__ */ c("div", {
|
|
126
135
|
style: {
|
|
136
|
+
flexShrink: 0,
|
|
127
137
|
padding: "20px 24px",
|
|
128
138
|
borderBottom: `1px solid ${G.borderDefault}`,
|
|
129
139
|
display: "flex",
|
|
@@ -131,7 +141,8 @@ function f({ dashboardId: f, dashboardName: m, isOpen: h, onClose: g }) {
|
|
|
131
141
|
justifyContent: "space-between",
|
|
132
142
|
backgroundColor: G.bgPrimary
|
|
133
143
|
},
|
|
134
|
-
children: [/* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("
|
|
144
|
+
children: [/* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("h2", {
|
|
145
|
+
id: "share-dialog-title",
|
|
135
146
|
style: {
|
|
136
147
|
margin: 0,
|
|
137
148
|
fontSize: "18px",
|
|
@@ -161,7 +172,10 @@ function f({ dashboardId: f, dashboardName: m, isOpen: h, onClose: g }) {
|
|
|
161
172
|
})]
|
|
162
173
|
}),
|
|
163
174
|
/* @__PURE__ */ s("div", {
|
|
175
|
+
role: "tablist",
|
|
176
|
+
"aria-label": "Share options",
|
|
164
177
|
style: {
|
|
178
|
+
flexShrink: 0,
|
|
165
179
|
display: "flex",
|
|
166
180
|
gap: "4px",
|
|
167
181
|
padding: "0 24px",
|
|
@@ -170,6 +184,8 @@ function f({ dashboardId: f, dashboardName: m, isOpen: h, onClose: g }) {
|
|
|
170
184
|
},
|
|
171
185
|
children: ["people", "embed"].map((e) => /* @__PURE__ */ s("button", {
|
|
172
186
|
type: "button",
|
|
187
|
+
role: "tab",
|
|
188
|
+
"aria-selected": I === e,
|
|
173
189
|
onClick: () => L(e),
|
|
174
190
|
style: {
|
|
175
191
|
padding: "10px 12px",
|
|
@@ -185,39 +201,29 @@ function f({ dashboardId: f, dashboardName: m, isOpen: h, onClose: g }) {
|
|
|
185
201
|
}, e))
|
|
186
202
|
}),
|
|
187
203
|
I === "embed" && /* @__PURE__ */ s("div", {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
maxHeight: "calc(80vh - 160px)",
|
|
191
|
-
backgroundColor: G.bgPrimary
|
|
192
|
-
},
|
|
204
|
+
className: "min-h-0 flex-1 overflow-y-auto",
|
|
205
|
+
style: { backgroundColor: G.bgPrimary },
|
|
193
206
|
children: /* @__PURE__ */ s(n, {
|
|
194
207
|
dashboardId: f,
|
|
195
208
|
colors: G
|
|
196
209
|
})
|
|
197
210
|
}),
|
|
198
211
|
I === "people" && /* @__PURE__ */ c("div", {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
overflowY: "auto",
|
|
202
|
-
maxHeight: "calc(80vh - 200px)",
|
|
203
|
-
backgroundColor: G.bgPrimary
|
|
204
|
-
},
|
|
212
|
+
className: "flex min-h-0 flex-1 flex-col gap-section-gap overflow-y-auto p-card-padding",
|
|
213
|
+
style: { backgroundColor: G.bgPrimary },
|
|
205
214
|
children: [
|
|
206
|
-
/* @__PURE__ */ c("
|
|
207
|
-
|
|
208
|
-
children: [/* @__PURE__ */ s("
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
fontWeight: 600,
|
|
214
|
-
color: G.textPrimary
|
|
215
|
-
},
|
|
216
|
-
children: "Share Link"
|
|
215
|
+
/* @__PURE__ */ c("section", {
|
|
216
|
+
"aria-labelledby": "share-link-heading",
|
|
217
|
+
children: [/* @__PURE__ */ s("h3", {
|
|
218
|
+
id: "share-link-heading",
|
|
219
|
+
className: "mb-form-gap text-sm font-semibold",
|
|
220
|
+
style: { color: G.textPrimary },
|
|
221
|
+
children: "Share link"
|
|
217
222
|
}), /* @__PURE__ */ c("div", {
|
|
218
223
|
style: {
|
|
219
224
|
display: "flex",
|
|
220
|
-
gap: "8px"
|
|
225
|
+
gap: "8px",
|
|
226
|
+
flexWrap: "wrap"
|
|
221
227
|
},
|
|
222
228
|
children: [/* @__PURE__ */ s("input", {
|
|
223
229
|
type: "text",
|
|
@@ -237,7 +243,7 @@ function f({ dashboardId: f, dashboardName: m, isOpen: h, onClose: g }) {
|
|
|
237
243
|
style: {
|
|
238
244
|
padding: "10px 16px",
|
|
239
245
|
backgroundColor: P ? G.statusSuccessBg : G.actionPrimaryBg,
|
|
240
|
-
color: "
|
|
246
|
+
color: "var(--color-action-primary-text)",
|
|
241
247
|
border: "none",
|
|
242
248
|
borderRadius: "6px",
|
|
243
249
|
cursor: "pointer",
|
|
@@ -249,22 +255,19 @@ function f({ dashboardId: f, dashboardName: m, isOpen: h, onClose: g }) {
|
|
|
249
255
|
})]
|
|
250
256
|
})]
|
|
251
257
|
}),
|
|
252
|
-
/* @__PURE__ */ c("
|
|
253
|
-
|
|
254
|
-
children: [/* @__PURE__ */ s("
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
fontWeight: 600,
|
|
260
|
-
color: G.textPrimary
|
|
261
|
-
},
|
|
262
|
-
children: "Add People"
|
|
258
|
+
/* @__PURE__ */ c("section", {
|
|
259
|
+
"aria-labelledby": "share-invite-heading",
|
|
260
|
+
children: [/* @__PURE__ */ s("h3", {
|
|
261
|
+
id: "share-invite-heading",
|
|
262
|
+
className: "mb-form-gap text-sm font-semibold",
|
|
263
|
+
style: { color: G.textPrimary },
|
|
264
|
+
children: "Invite people"
|
|
263
265
|
}), /* @__PURE__ */ c("div", {
|
|
264
266
|
style: {
|
|
265
267
|
display: "flex",
|
|
266
268
|
gap: "8px",
|
|
267
|
-
marginBottom: "8px"
|
|
269
|
+
marginBottom: "8px",
|
|
270
|
+
flexWrap: "wrap"
|
|
268
271
|
},
|
|
269
272
|
children: [
|
|
270
273
|
/* @__PURE__ */ c("div", {
|
|
@@ -298,7 +301,7 @@ function f({ dashboardId: f, dashboardName: m, isOpen: h, onClose: g }) {
|
|
|
298
301
|
backgroundColor: G.bgPrimary,
|
|
299
302
|
border: `1px solid ${G.borderDefault}`,
|
|
300
303
|
borderRadius: "6px",
|
|
301
|
-
boxShadow: "
|
|
304
|
+
boxShadow: "var(--shadow-elevation-3)",
|
|
302
305
|
zIndex: 100001,
|
|
303
306
|
maxHeight: "200px",
|
|
304
307
|
overflowY: "auto"
|
|
@@ -365,7 +368,7 @@ function f({ dashboardId: f, dashboardName: m, isOpen: h, onClose: g }) {
|
|
|
365
368
|
style: {
|
|
366
369
|
padding: "10px 16px",
|
|
367
370
|
backgroundColor: O ? G.actionPrimaryBg : G.bgTertiary,
|
|
368
|
-
color: O ? "
|
|
371
|
+
color: O ? "var(--color-action-primary-text)" : G.textSecondary,
|
|
369
372
|
border: "none",
|
|
370
373
|
borderRadius: "6px",
|
|
371
374
|
cursor: O ? "pointer" : "not-allowed",
|
|
@@ -377,61 +380,64 @@ function f({ dashboardId: f, dashboardName: m, isOpen: h, onClose: g }) {
|
|
|
377
380
|
]
|
|
378
381
|
})]
|
|
379
382
|
}),
|
|
380
|
-
/* @__PURE__ */ c("
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
alignItems: "center",
|
|
384
|
-
justifyContent: "space-between",
|
|
385
|
-
marginBottom: "12px"
|
|
386
|
-
},
|
|
387
|
-
children: [/* @__PURE__ */ c("label", {
|
|
383
|
+
/* @__PURE__ */ c("section", {
|
|
384
|
+
"aria-labelledby": "share-access-heading",
|
|
385
|
+
children: [/* @__PURE__ */ c("div", {
|
|
388
386
|
style: {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
387
|
+
display: "flex",
|
|
388
|
+
alignItems: "center",
|
|
389
|
+
justifyContent: "space-between",
|
|
390
|
+
flexWrap: "wrap",
|
|
391
|
+
gap: "8px",
|
|
392
|
+
marginBottom: "12px"
|
|
392
393
|
},
|
|
393
|
-
children: [
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
394
|
+
children: [/* @__PURE__ */ c("h3", {
|
|
395
|
+
id: "share-access-heading",
|
|
396
|
+
className: "text-sm font-semibold",
|
|
397
|
+
style: { color: G.textPrimary },
|
|
398
|
+
children: [
|
|
399
|
+
"People with access (",
|
|
400
|
+
_.length,
|
|
401
|
+
")"
|
|
402
|
+
]
|
|
403
|
+
}), _.length > 0 && /* @__PURE__ */ s("button", {
|
|
404
|
+
onClick: V,
|
|
405
|
+
style: {
|
|
406
|
+
padding: "4px 8px",
|
|
407
|
+
backgroundColor: "transparent",
|
|
408
|
+
color: G.statusErrorText,
|
|
409
|
+
border: "none",
|
|
410
|
+
cursor: "pointer",
|
|
411
|
+
fontSize: "12px"
|
|
412
|
+
},
|
|
413
|
+
children: "Revoke All"
|
|
414
|
+
})]
|
|
415
|
+
}), v && _.length === 0 ? /* @__PURE__ */ s("p", {
|
|
416
|
+
style: {
|
|
417
|
+
color: G.textSecondary,
|
|
418
|
+
fontSize: "13px"
|
|
419
|
+
},
|
|
420
|
+
children: "Loading..."
|
|
421
|
+
}) : _.length === 0 ? /* @__PURE__ */ s("p", {
|
|
400
422
|
style: {
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
423
|
+
color: G.textSecondary,
|
|
424
|
+
fontSize: "13px"
|
|
425
|
+
},
|
|
426
|
+
children: "No one has access to this dashboard yet."
|
|
427
|
+
}) : /* @__PURE__ */ s("div", {
|
|
428
|
+
style: {
|
|
429
|
+
display: "flex",
|
|
430
|
+
flexDirection: "column",
|
|
431
|
+
gap: "8px"
|
|
407
432
|
},
|
|
408
|
-
children:
|
|
433
|
+
children: _.map((e) => /* @__PURE__ */ s(p, {
|
|
434
|
+
share: e,
|
|
435
|
+
onUpdatePermission: z,
|
|
436
|
+
onRevoke: B,
|
|
437
|
+
colors: G
|
|
438
|
+
}, e.id))
|
|
409
439
|
})]
|
|
410
|
-
})
|
|
411
|
-
style: {
|
|
412
|
-
color: G.textSecondary,
|
|
413
|
-
fontSize: "13px"
|
|
414
|
-
},
|
|
415
|
-
children: "Loading..."
|
|
416
|
-
}) : _.length === 0 ? /* @__PURE__ */ s("p", {
|
|
417
|
-
style: {
|
|
418
|
-
color: G.textSecondary,
|
|
419
|
-
fontSize: "13px"
|
|
420
|
-
},
|
|
421
|
-
children: "No one has access to this dashboard yet."
|
|
422
|
-
}) : /* @__PURE__ */ s("div", {
|
|
423
|
-
style: {
|
|
424
|
-
display: "flex",
|
|
425
|
-
flexDirection: "column",
|
|
426
|
-
gap: "8px"
|
|
427
|
-
},
|
|
428
|
-
children: _.map((e) => /* @__PURE__ */ s(p, {
|
|
429
|
-
share: e,
|
|
430
|
-
onUpdatePermission: z,
|
|
431
|
-
onRevoke: B,
|
|
432
|
-
colors: G
|
|
433
|
-
}, e.id))
|
|
434
|
-
})] })
|
|
440
|
+
})
|
|
435
441
|
]
|
|
436
442
|
})
|
|
437
443
|
]
|
|
@@ -463,7 +469,7 @@ function p({ share: e, onUpdatePermission: t, onRevoke: n, colors: r }) {
|
|
|
463
469
|
display: "flex",
|
|
464
470
|
alignItems: "center",
|
|
465
471
|
justifyContent: "center",
|
|
466
|
-
color: "
|
|
472
|
+
color: "var(--color-action-primary-text)",
|
|
467
473
|
fontWeight: 600,
|
|
468
474
|
fontSize: "14px"
|
|
469
475
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ShareDialog.js","names":[],"sources":["../../../../../src/bigconsole/components/dashboard/ShareDialog/ShareDialog.tsx"],"sourcesContent":["/**\n * ShareDialog Component\n *\n * Dialog for sharing dashboards with users and roles.\n */\n\nimport React, { useState, useEffect, useCallback, useMemo } from 'react';\nimport { createPortal } from 'react-dom';\nimport {\n useDashboardSharing,\n type DashboardShare,\n type SharePermission,\n type ShareRecipientType,\n} from '../../../hooks';\nimport { useBigConsoleAnalytics } from '../../../hooks/useBigConsoleAnalytics';\nimport { EmbedTab } from './EmbedTab';\n\n// Dark mode aware colors\nconst getColors = (isDark: boolean) => ({\n bgPrimary: isDark ? '#1a1a2e' : '#ffffff',\n bgSecondary: isDark ? '#252542' : '#f4f4f5',\n bgTertiary: isDark ? '#2d2d4a' : '#e4e4e7',\n textPrimary: isDark ? '#f4f4f5' : '#18181b',\n textSecondary: isDark ? '#a1a1aa' : '#71717a',\n textTertiary: isDark ? '#71717a' : '#a1a1aa',\n borderDefault: isDark ? '#3f3f5c' : '#e4e4e7',\n actionPrimaryBg: '#6366f1',\n actionPrimaryBgHover: '#4f46e5',\n statusSuccessBg: '#22c55e',\n statusErrorText: '#ef4444',\n});\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ShareDialogProps {\n dashboardId: string;\n dashboardName: string;\n isOpen: boolean;\n onClose: () => void;\n}\n\ninterface ShareRecipient {\n id: string;\n name: string;\n email?: string;\n type: ShareRecipientType;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/**\n * Permission options as per spec (03-graphql-contract.md)\n * Spec values: view, edit\n */\nconst PERMISSION_OPTIONS: { value: SharePermission; label: string; description: string }[] = [\n { value: 'VIEW', label: 'View', description: 'Can view the dashboard' },\n { value: 'EDIT', label: 'Edit', description: 'Can edit widgets, layout, and share' },\n];\n\n// Use shared semantic tokens for portal rendering\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport function ShareDialog({ dashboardId, dashboardName, isOpen, onClose }: ShareDialogProps) {\n const { shares, loading, fetchShares, shareWithUser, shareWithGroup, updateShare, revokeShare, revokeAllShares } =\n useDashboardSharing();\n const emitBigConsoleEvent = useBigConsoleAnalytics();\n\n const [searchQuery, setSearchQuery] = useState('');\n const [selectedRecipient, setSelectedRecipient] = useState<ShareRecipient | null>(null);\n const [selectedPermission, setSelectedPermission] = useState<SharePermission>('VIEW');\n const [shareLink, setShareLink] = useState('');\n const [copySuccess, setCopySuccess] = useState(false);\n const [activeTab, setActiveTab] = useState<'people' | 'embed'>('people');\n\n // Fetch shares when dialog opens\n useEffect(() => {\n if (isOpen && dashboardId) {\n fetchShares(dashboardId);\n // Generate share link\n setShareLink(`${window.location.origin}/dashboard/${dashboardId}?shared=true`);\n }\n }, [isOpen, dashboardId, fetchShares]);\n\n // Handle share - per spec: only USER and GROUP recipient types\n const handleShare = useCallback(async () => {\n if (!selectedRecipient) return;\n\n emitBigConsoleEvent('bigconsole.dashboard.share_clicked', {\n dashboardId,\n permission: selectedPermission,\n recipientType: selectedRecipient.type,\n });\n\n let share: DashboardShare | null = null;\n if (selectedRecipient.type === 'USER') {\n share = await shareWithUser(dashboardId, selectedRecipient.id, selectedPermission);\n } else if (selectedRecipient.type === 'GROUP') {\n share = await shareWithGroup(dashboardId, selectedRecipient.id, selectedPermission);\n }\n\n if (share) {\n emitBigConsoleEvent('bigconsole.dashboard.shared', {\n dashboardId,\n permission: selectedPermission,\n recipientType: selectedRecipient.type,\n });\n }\n\n setSelectedRecipient(null);\n setSearchQuery('');\n }, [dashboardId, emitBigConsoleEvent, selectedRecipient, selectedPermission, shareWithGroup, shareWithUser]);\n\n // Handle update permission\n const handleUpdatePermission = useCallback(\n async (shareId: string, newPermission: SharePermission) => {\n await updateShare({ id: shareId, permission: newPermission });\n },\n [updateShare]\n );\n\n // Handle revoke\n const handleRevoke = useCallback(\n async (shareId: string) => {\n if (window.confirm('Are you sure you want to revoke this access?')) {\n await revokeShare(shareId);\n }\n },\n [revokeShare]\n );\n\n // Handle revoke all\n const handleRevokeAll = useCallback(async () => {\n if (window.confirm('Are you sure you want to revoke all shared access?')) {\n await revokeAllShares(dashboardId);\n }\n }, [dashboardId, revokeAllShares]);\n\n // Copy link to clipboard\n const handleCopyLink = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(shareLink);\n setCopySuccess(true);\n setTimeout(() => setCopySuccess(false), 2000);\n } catch (err) {}\n }, [shareLink]);\n\n // Mock search results (in real app, this would come from an API)\n // Per spec: ShareRecipientType is 'user' or 'group' only\n const searchResults: ShareRecipient[] = searchQuery\n ? (\n [\n { id: 'user-1', name: 'John Doe', email: 'john@example.com', type: 'USER' as ShareRecipientType },\n { id: 'user-2', name: 'Jane Smith', email: 'jane@example.com', type: 'USER' as ShareRecipientType },\n { id: 'group-admin', name: 'Administrators', type: 'GROUP' as ShareRecipientType },\n { id: 'group-editor', name: 'Editors', type: 'GROUP' as ShareRecipientType },\n ] as ShareRecipient[]\n ).filter(\n (r) =>\n r.name.toLowerCase().includes(searchQuery.toLowerCase()) ||\n r.email?.toLowerCase().includes(searchQuery.toLowerCase())\n )\n : [];\n\n // Check if dark mode is enabled\n const isDarkMode = typeof document !== 'undefined' && document.documentElement.classList.contains('dark');\n const colors = useMemo(() => getColors(isDarkMode), [isDarkMode]);\n\n if (!isOpen) return null;\n\n // Use portal to render at document.body level to avoid z-index/stacking context issues\n const dialogContent = (\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.6)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 99999,\n isolation: 'isolate',\n }}\n onClick={onClose}\n >\n <div\n style={{\n width: '520px',\n maxHeight: '80vh',\n backgroundColor: colors.bgPrimary,\n borderRadius: '12px',\n boxShadow: '0 8px 32px rgba(0, 0, 0, 0.3)',\n overflow: 'hidden',\n position: 'relative',\n zIndex: 100000,\n color: colors.textPrimary,\n }}\n onClick={(e) => e.stopPropagation()}\n >\n {/* Header */}\n <div\n style={{\n padding: '20px 24px',\n borderBottom: `1px solid ${colors.borderDefault}`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n backgroundColor: colors.bgPrimary,\n }}\n >\n <div>\n <h3 style={{ margin: 0, fontSize: '18px', fontWeight: 600, color: colors.textPrimary }}>Share Dashboard</h3>\n <p style={{ margin: '4px 0 0', fontSize: '13px', color: colors.textSecondary }}>{dashboardName}</p>\n </div>\n <button\n onClick={onClose}\n style={{\n background: 'none',\n border: 'none',\n fontSize: '24px',\n cursor: 'pointer',\n color: colors.textSecondary,\n padding: '4px',\n lineHeight: 1,\n }}\n >\n ×\n </button>\n </div>\n\n {/* Tabs */}\n <div\n style={{\n display: 'flex',\n gap: '4px',\n padding: '0 24px',\n borderBottom: `1px solid ${colors.borderDefault}`,\n backgroundColor: colors.bgPrimary,\n }}\n >\n {(['people', 'embed'] as const).map((tab) => (\n <button\n key={tab}\n type=\"button\"\n onClick={() => setActiveTab(tab)}\n style={{\n padding: '10px 12px',\n background: 'none',\n border: 'none',\n borderBottom: `2px solid ${activeTab === tab ? colors.actionPrimaryBg : 'transparent'}`,\n color: activeTab === tab ? colors.textPrimary : colors.textSecondary,\n fontSize: '13px',\n fontWeight: 600,\n cursor: 'pointer',\n }}\n >\n {tab === 'people' ? 'People' : 'Publish to web'}\n </button>\n ))}\n </div>\n\n {/* Publish-to-web tab */}\n {activeTab === 'embed' && (\n <div style={{ overflowY: 'auto', maxHeight: 'calc(80vh - 160px)', backgroundColor: colors.bgPrimary }}>\n <EmbedTab dashboardId={dashboardId} colors={colors} />\n </div>\n )}\n\n {/* People tab (existing content) */}\n {activeTab === 'people' && (\n <div\n style={{\n padding: '24px',\n overflowY: 'auto',\n maxHeight: 'calc(80vh - 200px)',\n backgroundColor: colors.bgPrimary,\n }}\n >\n {/* Share Link Section */}\n <div style={{ marginBottom: '24px' }}>\n <label\n style={{\n display: 'block',\n marginBottom: '8px',\n fontSize: '13px',\n fontWeight: 600,\n color: colors.textPrimary,\n }}\n >\n Share Link\n </label>\n <div style={{ display: 'flex', gap: '8px' }}>\n <input\n type=\"text\"\n value={shareLink}\n readOnly\n style={{\n flex: 1,\n padding: '10px 12px',\n border: `1px solid ${colors.borderDefault}`,\n borderRadius: '6px',\n fontSize: '13px',\n backgroundColor: colors.bgSecondary,\n color: colors.textPrimary,\n }}\n />\n <button\n onClick={handleCopyLink}\n style={{\n padding: '10px 16px',\n backgroundColor: copySuccess ? colors.statusSuccessBg : colors.actionPrimaryBg,\n color: 'white',\n border: 'none',\n borderRadius: '6px',\n cursor: 'pointer',\n fontSize: '13px',\n fontWeight: 500,\n minWidth: '80px',\n }}\n >\n {copySuccess ? 'Copied!' : 'Copy'}\n </button>\n </div>\n </div>\n\n {/* Add People Section */}\n <div style={{ marginBottom: '24px' }}>\n <label\n style={{\n display: 'block',\n marginBottom: '8px',\n fontSize: '13px',\n fontWeight: 600,\n color: colors.textPrimary,\n }}\n >\n Add People\n </label>\n <div style={{ display: 'flex', gap: '8px', marginBottom: '8px' }}>\n <div style={{ flex: 1, position: 'relative' }}>\n <input\n type=\"text\"\n value={selectedRecipient ? selectedRecipient.name : searchQuery}\n onChange={(e) => {\n setSearchQuery(e.target.value);\n setSelectedRecipient(null);\n }}\n placeholder=\"Search by name or email...\"\n style={{\n width: '100%',\n padding: '10px 12px',\n border: `1px solid ${colors.borderDefault}`,\n borderRadius: '6px',\n fontSize: '13px',\n backgroundColor: colors.bgPrimary,\n color: colors.textPrimary,\n }}\n />\n {/* Search Results Dropdown */}\n {searchQuery && !selectedRecipient && searchResults.length > 0 && (\n <div\n style={{\n position: 'absolute',\n top: '100%',\n left: 0,\n right: 0,\n marginTop: '4px',\n backgroundColor: colors.bgPrimary,\n border: `1px solid ${colors.borderDefault}`,\n borderRadius: '6px',\n boxShadow: '0 8px 24px rgba(0,0,0,0.25)',\n zIndex: 100001,\n maxHeight: '200px',\n overflowY: 'auto',\n }}\n >\n {searchResults.map((result) => (\n <button\n key={result.id}\n onClick={() => setSelectedRecipient(result)}\n style={{\n display: 'block',\n width: '100%',\n padding: '10px 12px',\n textAlign: 'left',\n backgroundColor: 'transparent',\n border: 'none',\n cursor: 'pointer',\n borderBottom: `1px solid ${colors.borderDefault}`,\n }}\n >\n <div style={{ fontSize: '13px', fontWeight: 500, color: colors.textPrimary }}>\n {result.name}\n </div>\n {result.email && (\n <div style={{ fontSize: '11px', color: colors.textSecondary }}>{result.email}</div>\n )}\n <span\n style={{\n fontSize: '10px',\n color: colors.textTertiary,\n textTransform: 'uppercase',\n }}\n >\n {result.type}\n </span>\n </button>\n ))}\n </div>\n )}\n </div>\n <select\n value={selectedPermission}\n onChange={(e) => setSelectedPermission(e.target.value as SharePermission)}\n style={{\n padding: '10px 12px',\n border: `1px solid ${colors.borderDefault}`,\n borderRadius: '6px',\n fontSize: '13px',\n backgroundColor: colors.bgPrimary,\n color: colors.textPrimary,\n }}\n >\n {PERMISSION_OPTIONS.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n <button\n onClick={handleShare}\n disabled={!selectedRecipient || loading}\n style={{\n padding: '10px 16px',\n backgroundColor: selectedRecipient ? colors.actionPrimaryBg : colors.bgTertiary,\n color: selectedRecipient ? 'white' : colors.textSecondary,\n border: 'none',\n borderRadius: '6px',\n cursor: selectedRecipient ? 'pointer' : 'not-allowed',\n fontSize: '13px',\n fontWeight: 500,\n }}\n >\n Share\n </button>\n </div>\n </div>\n\n {/* Current Shares */}\n <div>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n marginBottom: '12px',\n }}\n >\n <label\n style={{\n fontSize: '13px',\n fontWeight: 600,\n color: colors.textPrimary,\n }}\n >\n People with Access ({shares.length})\n </label>\n {shares.length > 0 && (\n <button\n onClick={handleRevokeAll}\n style={{\n padding: '4px 8px',\n backgroundColor: 'transparent',\n color: colors.statusErrorText,\n border: 'none',\n cursor: 'pointer',\n fontSize: '12px',\n }}\n >\n Revoke All\n </button>\n )}\n </div>\n\n {loading && shares.length === 0 ? (\n <p style={{ color: colors.textSecondary, fontSize: '13px' }}>Loading...</p>\n ) : shares.length === 0 ? (\n <p style={{ color: colors.textSecondary, fontSize: '13px' }}>\n No one has access to this dashboard yet.\n </p>\n ) : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>\n {shares.map((share) => (\n <ShareItem\n key={share.id}\n share={share}\n onUpdatePermission={handleUpdatePermission}\n onRevoke={handleRevoke}\n colors={colors}\n />\n ))}\n </div>\n )}\n </div>\n </div>\n )}\n </div>\n </div>\n );\n\n // Render via portal to document.body to escape any stacking context issues\n return createPortal(dialogContent, document.body);\n}\n\n// ============================================================================\n// ShareItem Sub-component\n// ============================================================================\n\ninterface ShareItemProps {\n share: DashboardShare;\n onUpdatePermission: (shareId: string, permission: SharePermission) => void;\n onRevoke: (shareId: string) => void;\n colors: ReturnType<typeof getColors>;\n}\n\nfunction ShareItem({ share, onUpdatePermission, onRevoke, colors }: ShareItemProps) {\n return (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '10px 12px',\n backgroundColor: colors.bgSecondary,\n borderRadius: '6px',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>\n <div\n style={{\n width: '36px',\n height: '36px',\n borderRadius: '50%',\n backgroundColor: colors.actionPrimaryBg,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: 'white',\n fontWeight: 600,\n fontSize: '14px',\n }}\n >\n {share.recipientType === 'USER' ? 'U' : 'R'}\n </div>\n <div>\n <div style={{ fontSize: '13px', fontWeight: 500, color: colors.textPrimary }}>{share.recipientId}</div>\n <div style={{ fontSize: '11px', color: colors.textSecondary }}>\n {share.recipientType} - Shared {new Date(share.createdAt).toLocaleDateString()}\n </div>\n </div>\n </div>\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>\n <select\n value={share.permission}\n onChange={(e) => onUpdatePermission(share.id, e.target.value as SharePermission)}\n style={{\n padding: '6px 10px',\n border: `1px solid ${colors.borderDefault}`,\n borderRadius: '4px',\n fontSize: '12px',\n backgroundColor: colors.bgPrimary,\n color: colors.textPrimary,\n }}\n >\n {PERMISSION_OPTIONS.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n <button\n onClick={() => onRevoke(share.id)}\n style={{\n padding: '6px 10px',\n backgroundColor: 'transparent',\n color: colors.statusErrorText,\n border: `1px solid ${colors.statusErrorText}`,\n borderRadius: '4px',\n cursor: 'pointer',\n fontSize: '12px',\n }}\n >\n Revoke\n </button>\n </div>\n </div>\n );\n}\n\nexport default ShareDialog;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ShareDialog.js","names":[],"sources":["../../../../../src/bigconsole/components/dashboard/ShareDialog/ShareDialog.tsx"],"sourcesContent":["/**\n * ShareDialog Component\n *\n * Dialog for sharing dashboards with users and roles.\n */\n\nimport React, { useState, useEffect, useCallback, useMemo } from 'react';\nimport { createPortal } from 'react-dom';\nimport {\n useDashboardSharing,\n type DashboardShare,\n type SharePermission,\n type ShareRecipientType,\n} from '../../../hooks';\nimport { useBigConsoleAnalytics } from '../../../hooks/useBigConsoleAnalytics';\nimport { EmbedTab } from './EmbedTab';\n\n// Dark mode aware colors\nconst getColors = (isDark: boolean) => ({\n bgPrimary: isDark ? '#1a1a2e' : '#ffffff',\n bgSecondary: isDark ? '#252542' : '#f4f4f5',\n bgTertiary: isDark ? '#2d2d4a' : '#e4e4e7',\n textPrimary: isDark ? '#f4f4f5' : '#18181b',\n textSecondary: isDark ? '#a1a1aa' : '#71717a',\n textTertiary: isDark ? '#71717a' : '#a1a1aa',\n borderDefault: isDark ? '#3f3f5c' : '#e4e4e7',\n actionPrimaryBg: '#6366f1',\n actionPrimaryBgHover: '#4f46e5',\n statusSuccessBg: '#22c55e',\n statusErrorText: '#ef4444',\n});\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ShareDialogProps {\n dashboardId: string;\n dashboardName: string;\n isOpen: boolean;\n onClose: () => void;\n}\n\ninterface ShareRecipient {\n id: string;\n name: string;\n email?: string;\n type: ShareRecipientType;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/**\n * Permission options as per spec (03-graphql-contract.md)\n * Spec values: view, edit\n */\nconst PERMISSION_OPTIONS: { value: SharePermission; label: string; description: string }[] = [\n { value: 'VIEW', label: 'View', description: 'Can view the dashboard' },\n { value: 'EDIT', label: 'Edit', description: 'Can edit widgets, layout, and share' },\n];\n\n// Use shared semantic tokens for portal rendering\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport function ShareDialog({ dashboardId, dashboardName, isOpen, onClose }: ShareDialogProps) {\n const { shares, loading, fetchShares, shareWithUser, shareWithGroup, updateShare, revokeShare, revokeAllShares } =\n useDashboardSharing();\n const emitBigConsoleEvent = useBigConsoleAnalytics();\n\n const [searchQuery, setSearchQuery] = useState('');\n const [selectedRecipient, setSelectedRecipient] = useState<ShareRecipient | null>(null);\n const [selectedPermission, setSelectedPermission] = useState<SharePermission>('VIEW');\n const [shareLink, setShareLink] = useState('');\n const [copySuccess, setCopySuccess] = useState(false);\n const [activeTab, setActiveTab] = useState<'people' | 'embed'>('people');\n\n // Fetch shares when dialog opens\n useEffect(() => {\n if (isOpen && dashboardId) {\n fetchShares(dashboardId);\n // Generate share link\n setShareLink(`${window.location.origin}/dashboard/${dashboardId}?shared=true`);\n }\n }, [isOpen, dashboardId, fetchShares]);\n\n // Handle share - per spec: only USER and GROUP recipient types\n const handleShare = useCallback(async () => {\n if (!selectedRecipient) return;\n\n emitBigConsoleEvent('bigconsole.dashboard.share_clicked', {\n dashboardId,\n permission: selectedPermission,\n recipientType: selectedRecipient.type,\n });\n\n let share: DashboardShare | null = null;\n if (selectedRecipient.type === 'USER') {\n share = await shareWithUser(dashboardId, selectedRecipient.id, selectedPermission);\n } else if (selectedRecipient.type === 'GROUP') {\n share = await shareWithGroup(dashboardId, selectedRecipient.id, selectedPermission);\n }\n\n if (share) {\n emitBigConsoleEvent('bigconsole.dashboard.shared', {\n dashboardId,\n permission: selectedPermission,\n recipientType: selectedRecipient.type,\n });\n }\n\n setSelectedRecipient(null);\n setSearchQuery('');\n }, [dashboardId, emitBigConsoleEvent, selectedRecipient, selectedPermission, shareWithGroup, shareWithUser]);\n\n // Handle update permission\n const handleUpdatePermission = useCallback(\n async (shareId: string, newPermission: SharePermission) => {\n await updateShare({ id: shareId, permission: newPermission });\n },\n [updateShare]\n );\n\n // Handle revoke\n const handleRevoke = useCallback(\n async (shareId: string) => {\n if (window.confirm('Are you sure you want to revoke this access?')) {\n await revokeShare(shareId);\n }\n },\n [revokeShare]\n );\n\n // Handle revoke all\n const handleRevokeAll = useCallback(async () => {\n if (window.confirm('Are you sure you want to revoke all shared access?')) {\n await revokeAllShares(dashboardId);\n }\n }, [dashboardId, revokeAllShares]);\n\n // Copy link to clipboard\n const handleCopyLink = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(shareLink);\n setCopySuccess(true);\n setTimeout(() => setCopySuccess(false), 2000);\n } catch (err) {}\n }, [shareLink]);\n\n // Mock search results (in real app, this would come from an API)\n // Per spec: ShareRecipientType is 'user' or 'group' only\n const searchResults: ShareRecipient[] = searchQuery\n ? (\n [\n { id: 'user-1', name: 'John Doe', email: 'john@example.com', type: 'USER' as ShareRecipientType },\n { id: 'user-2', name: 'Jane Smith', email: 'jane@example.com', type: 'USER' as ShareRecipientType },\n { id: 'group-admin', name: 'Administrators', type: 'GROUP' as ShareRecipientType },\n { id: 'group-editor', name: 'Editors', type: 'GROUP' as ShareRecipientType },\n ] as ShareRecipient[]\n ).filter(\n (r) =>\n r.name.toLowerCase().includes(searchQuery.toLowerCase()) ||\n r.email?.toLowerCase().includes(searchQuery.toLowerCase())\n )\n : [];\n\n // Check if dark mode is enabled\n const isDarkMode = typeof document !== 'undefined' && document.documentElement.classList.contains('dark');\n const colors = useMemo(() => getColors(isDarkMode), [isDarkMode]);\n\n if (!isOpen) return null;\n\n // Use portal to render at document.body level to avoid z-index/stacking context issues\n const dialogContent = (\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: 'var(--color-overlay-scrim)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n padding: 'var(--space-formGap)',\n zIndex: 99999,\n isolation: 'isolate',\n }}\n onClick={onClose}\n role=\"presentation\"\n >\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"share-dialog-title\"\n data-testid=\"share-dialog\"\n style={{\n // was a hard 520px, which overflowed every phone viewport\n width: '100%',\n maxWidth: '520px',\n maxHeight: '85vh',\n display: 'flex',\n flexDirection: 'column',\n backgroundColor: colors.bgPrimary,\n borderRadius: 'var(--radius-card)',\n boxShadow: 'var(--shadow-elevation-3)',\n overflow: 'hidden',\n position: 'relative',\n zIndex: 100000,\n color: colors.textPrimary,\n }}\n onClick={(e) => e.stopPropagation()}\n >\n {/* Header */}\n <div\n style={{\n flexShrink: 0,\n padding: '20px 24px',\n borderBottom: `1px solid ${colors.borderDefault}`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n backgroundColor: colors.bgPrimary,\n }}\n >\n <div>\n <h2\n id=\"share-dialog-title\"\n style={{ margin: 0, fontSize: '18px', fontWeight: 600, color: colors.textPrimary }}\n >\n Share Dashboard\n </h2>\n <p style={{ margin: '4px 0 0', fontSize: '13px', color: colors.textSecondary }}>{dashboardName}</p>\n </div>\n <button\n onClick={onClose}\n style={{\n background: 'none',\n border: 'none',\n fontSize: '24px',\n cursor: 'pointer',\n color: colors.textSecondary,\n padding: '4px',\n lineHeight: 1,\n }}\n >\n ×\n </button>\n </div>\n\n {/* Tabs */}\n <div\n role=\"tablist\"\n aria-label=\"Share options\"\n style={{\n flexShrink: 0,\n display: 'flex',\n gap: '4px',\n padding: '0 24px',\n borderBottom: `1px solid ${colors.borderDefault}`,\n backgroundColor: colors.bgPrimary,\n }}\n >\n {(['people', 'embed'] as const).map((tab) => (\n <button\n key={tab}\n type=\"button\"\n role=\"tab\"\n aria-selected={activeTab === tab}\n onClick={() => setActiveTab(tab)}\n style={{\n padding: '10px 12px',\n background: 'none',\n border: 'none',\n borderBottom: `2px solid ${activeTab === tab ? colors.actionPrimaryBg : 'transparent'}`,\n color: activeTab === tab ? colors.textPrimary : colors.textSecondary,\n fontSize: '13px',\n fontWeight: 600,\n cursor: 'pointer',\n }}\n >\n {tab === 'people' ? 'People' : 'Publish to web'}\n </button>\n ))}\n </div>\n\n {/* Publish-to-web tab */}\n {activeTab === 'embed' && (\n <div className=\"min-h-0 flex-1 overflow-y-auto\" style={{ backgroundColor: colors.bgPrimary }}>\n <EmbedTab dashboardId={dashboardId} colors={colors} />\n </div>\n )}\n\n {/* People tab (existing content) */}\n {activeTab === 'people' && (\n <div\n className=\"flex min-h-0 flex-1 flex-col gap-section-gap overflow-y-auto p-card-padding\"\n style={{ backgroundColor: colors.bgPrimary }}\n >\n {/* Share Link Section — the fastest way to share, so it leads */}\n <section aria-labelledby=\"share-link-heading\">\n <h3\n id=\"share-link-heading\"\n className=\"mb-form-gap text-sm font-semibold\"\n style={{ color: colors.textPrimary }}\n >\n Share link\n </h3>\n <div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap' }}>\n <input\n type=\"text\"\n value={shareLink}\n readOnly\n style={{\n flex: 1,\n padding: '10px 12px',\n border: `1px solid ${colors.borderDefault}`,\n borderRadius: '6px',\n fontSize: '13px',\n backgroundColor: colors.bgSecondary,\n color: colors.textPrimary,\n }}\n />\n <button\n onClick={handleCopyLink}\n style={{\n padding: '10px 16px',\n backgroundColor: copySuccess ? colors.statusSuccessBg : colors.actionPrimaryBg,\n color: 'var(--color-action-primary-text)',\n border: 'none',\n borderRadius: '6px',\n cursor: 'pointer',\n fontSize: '13px',\n fontWeight: 500,\n minWidth: '80px',\n }}\n >\n {copySuccess ? 'Copied!' : 'Copy'}\n </button>\n </div>\n </section>\n\n {/* Add People Section */}\n <section aria-labelledby=\"share-invite-heading\">\n <h3\n id=\"share-invite-heading\"\n className=\"mb-form-gap text-sm font-semibold\"\n style={{ color: colors.textPrimary }}\n >\n Invite people\n </h3>\n <div style={{ display: 'flex', gap: '8px', marginBottom: '8px', flexWrap: 'wrap' }}>\n <div style={{ flex: 1, position: 'relative' }}>\n <input\n type=\"text\"\n value={selectedRecipient ? selectedRecipient.name : searchQuery}\n onChange={(e) => {\n setSearchQuery(e.target.value);\n setSelectedRecipient(null);\n }}\n placeholder=\"Search by name or email...\"\n style={{\n width: '100%',\n padding: '10px 12px',\n border: `1px solid ${colors.borderDefault}`,\n borderRadius: '6px',\n fontSize: '13px',\n backgroundColor: colors.bgPrimary,\n color: colors.textPrimary,\n }}\n />\n {/* Search Results Dropdown */}\n {searchQuery && !selectedRecipient && searchResults.length > 0 && (\n <div\n style={{\n position: 'absolute',\n top: '100%',\n left: 0,\n right: 0,\n marginTop: '4px',\n backgroundColor: colors.bgPrimary,\n border: `1px solid ${colors.borderDefault}`,\n borderRadius: '6px',\n boxShadow: 'var(--shadow-elevation-3)',\n zIndex: 100001,\n maxHeight: '200px',\n overflowY: 'auto',\n }}\n >\n {searchResults.map((result) => (\n <button\n key={result.id}\n onClick={() => setSelectedRecipient(result)}\n style={{\n display: 'block',\n width: '100%',\n padding: '10px 12px',\n textAlign: 'left',\n backgroundColor: 'transparent',\n border: 'none',\n cursor: 'pointer',\n borderBottom: `1px solid ${colors.borderDefault}`,\n }}\n >\n <div style={{ fontSize: '13px', fontWeight: 500, color: colors.textPrimary }}>\n {result.name}\n </div>\n {result.email && (\n <div style={{ fontSize: '11px', color: colors.textSecondary }}>{result.email}</div>\n )}\n <span\n style={{\n fontSize: '10px',\n color: colors.textTertiary,\n textTransform: 'uppercase',\n }}\n >\n {result.type}\n </span>\n </button>\n ))}\n </div>\n )}\n </div>\n <select\n value={selectedPermission}\n onChange={(e) => setSelectedPermission(e.target.value as SharePermission)}\n style={{\n padding: '10px 12px',\n border: `1px solid ${colors.borderDefault}`,\n borderRadius: '6px',\n fontSize: '13px',\n backgroundColor: colors.bgPrimary,\n color: colors.textPrimary,\n }}\n >\n {PERMISSION_OPTIONS.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n <button\n onClick={handleShare}\n disabled={!selectedRecipient || loading}\n style={{\n padding: '10px 16px',\n backgroundColor: selectedRecipient ? colors.actionPrimaryBg : colors.bgTertiary,\n color: selectedRecipient ? 'var(--color-action-primary-text)' : colors.textSecondary,\n border: 'none',\n borderRadius: '6px',\n cursor: selectedRecipient ? 'pointer' : 'not-allowed',\n fontSize: '13px',\n fontWeight: 500,\n }}\n >\n Share\n </button>\n </div>\n </section>\n\n {/* Current Shares */}\n <section aria-labelledby=\"share-access-heading\">\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n flexWrap: 'wrap',\n gap: '8px',\n marginBottom: '12px',\n }}\n >\n <h3 id=\"share-access-heading\" className=\"text-sm font-semibold\" style={{ color: colors.textPrimary }}>\n People with access ({shares.length})\n </h3>\n {shares.length > 0 && (\n <button\n onClick={handleRevokeAll}\n style={{\n padding: '4px 8px',\n backgroundColor: 'transparent',\n color: colors.statusErrorText,\n border: 'none',\n cursor: 'pointer',\n fontSize: '12px',\n }}\n >\n Revoke All\n </button>\n )}\n </div>\n\n {loading && shares.length === 0 ? (\n <p style={{ color: colors.textSecondary, fontSize: '13px' }}>Loading...</p>\n ) : shares.length === 0 ? (\n <p style={{ color: colors.textSecondary, fontSize: '13px' }}>\n No one has access to this dashboard yet.\n </p>\n ) : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>\n {shares.map((share) => (\n <ShareItem\n key={share.id}\n share={share}\n onUpdatePermission={handleUpdatePermission}\n onRevoke={handleRevoke}\n colors={colors}\n />\n ))}\n </div>\n )}\n </section>\n </div>\n )}\n </div>\n </div>\n );\n\n // Render via portal to document.body to escape any stacking context issues\n return createPortal(dialogContent, document.body);\n}\n\n// ============================================================================\n// ShareItem Sub-component\n// ============================================================================\n\ninterface ShareItemProps {\n share: DashboardShare;\n onUpdatePermission: (shareId: string, permission: SharePermission) => void;\n onRevoke: (shareId: string) => void;\n colors: ReturnType<typeof getColors>;\n}\n\nfunction ShareItem({ share, onUpdatePermission, onRevoke, colors }: ShareItemProps) {\n return (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '10px 12px',\n backgroundColor: colors.bgSecondary,\n borderRadius: '6px',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>\n <div\n style={{\n width: '36px',\n height: '36px',\n borderRadius: '50%',\n backgroundColor: colors.actionPrimaryBg,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: 'var(--color-action-primary-text)',\n fontWeight: 600,\n fontSize: '14px',\n }}\n >\n {share.recipientType === 'USER' ? 'U' : 'R'}\n </div>\n <div>\n <div style={{ fontSize: '13px', fontWeight: 500, color: colors.textPrimary }}>{share.recipientId}</div>\n <div style={{ fontSize: '11px', color: colors.textSecondary }}>\n {share.recipientType} - Shared {new Date(share.createdAt).toLocaleDateString()}\n </div>\n </div>\n </div>\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>\n <select\n value={share.permission}\n onChange={(e) => onUpdatePermission(share.id, e.target.value as SharePermission)}\n style={{\n padding: '6px 10px',\n border: `1px solid ${colors.borderDefault}`,\n borderRadius: '4px',\n fontSize: '12px',\n backgroundColor: colors.bgPrimary,\n color: colors.textPrimary,\n }}\n >\n {PERMISSION_OPTIONS.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n <button\n onClick={() => onRevoke(share.id)}\n style={{\n padding: '6px 10px',\n backgroundColor: 'transparent',\n color: colors.statusErrorText,\n border: `1px solid ${colors.statusErrorText}`,\n borderRadius: '4px',\n cursor: 'pointer',\n fontSize: '12px',\n }}\n >\n Revoke\n </button>\n </div>\n </div>\n );\n}\n\nexport default ShareDialog;\n"],"mappings":";;;;;;;;AAkBA,IAAM,KAAa,OAAqB;CACtC,WAAW,IAAS,YAAY;CAChC,aAAa,IAAS,YAAY;CAClC,YAAY,IAAS,YAAY;CACjC,aAAa,IAAS,YAAY;CAClC,eAAe,IAAS,YAAY;CACpC,cAAc,IAAS,YAAY;CACnC,eAAe,IAAS,YAAY;CACpC,iBAAiB;CACjB,sBAAsB;CACtB,iBAAiB;CACjB,iBAAiB;CAClB,GA4BK,IAAuF,CAC3F;CAAE,OAAO;CAAQ,OAAO;CAAQ,aAAa;CAA0B,EACvE;CAAE,OAAO;CAAQ,OAAO;CAAQ,aAAa;CAAuC,CACrF;AAQD,SAAgB,EAAY,EAAE,gBAAa,kBAAe,WAAQ,cAA6B;CAC7F,IAAM,EAAE,WAAQ,YAAS,gBAAa,kBAAe,mBAAgB,gBAAa,gBAAa,uBAC7F,GAAqB,EACjB,IAAsB,GAAwB,EAE9C,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,CAAC,GAAmB,KAAwB,EAAgC,KAAK,EACjF,CAAC,GAAoB,KAAyB,EAA0B,OAAO,EAC/E,CAAC,GAAW,KAAgB,EAAS,GAAG,EACxC,CAAC,GAAa,KAAkB,EAAS,GAAM,EAC/C,CAAC,GAAW,KAAgB,EAA6B,SAAS;AAGxE,SAAgB;AACd,EAAI,KAAU,MACZ,EAAY,EAAY,EAExB,EAAa,GAAG,OAAO,SAAS,OAAO,aAAa,EAAY,cAAc;IAE/E;EAAC;EAAQ;EAAa;EAAY,CAAC;CAGtC,IAAM,IAAc,EAAY,YAAY;AAC1C,MAAI,CAAC,EAAmB;AAExB,IAAoB,sCAAsC;GACxD;GACA,YAAY;GACZ,eAAe,EAAkB;GAClC,CAAC;EAEF,IAAI,IAA+B;AAgBnC,EAfI,EAAkB,SAAS,SAC7B,IAAQ,MAAM,EAAc,GAAa,EAAkB,IAAI,EAAmB,GACzE,EAAkB,SAAS,YACpC,IAAQ,MAAM,EAAe,GAAa,EAAkB,IAAI,EAAmB,GAGjF,KACF,EAAoB,+BAA+B;GACjD;GACA,YAAY;GACZ,eAAe,EAAkB;GAClC,CAAC,EAGJ,EAAqB,KAAK,EAC1B,EAAe,GAAG;IACjB;EAAC;EAAa;EAAqB;EAAmB;EAAoB;EAAgB;EAAc,CAAC,EAGtG,IAAyB,EAC7B,OAAO,GAAiB,MAAmC;AACzD,QAAM,EAAY;GAAE,IAAI;GAAS,YAAY;GAAe,CAAC;IAE/D,CAAC,EAAY,CACd,EAGK,IAAe,EACnB,OAAO,MAAoB;AACzB,EAAI,OAAO,QAAQ,+CAA+C,IAChE,MAAM,EAAY,EAAQ;IAG9B,CAAC,EAAY,CACd,EAGK,IAAkB,EAAY,YAAY;AAC9C,EAAI,OAAO,QAAQ,qDAAqD,IACtE,MAAM,EAAgB,EAAY;IAEnC,CAAC,GAAa,EAAgB,CAAC,EAG5B,IAAiB,EAAY,YAAY;AAC7C,MAAI;AAGF,GAFA,MAAM,UAAU,UAAU,UAAU,EAAU,EAC9C,EAAe,GAAK,EACpB,iBAAiB,EAAe,GAAM,EAAE,IAAK;UACjC;IACb,CAAC,EAAU,CAAC,EAIT,IAAkC,IAElC;EACE;GAAE,IAAI;GAAU,MAAM;GAAY,OAAO;GAAoB,MAAM;GAA8B;EACjG;GAAE,IAAI;GAAU,MAAM;GAAc,OAAO;GAAoB,MAAM;GAA8B;EACnG;GAAE,IAAI;GAAe,MAAM;GAAkB,MAAM;GAA+B;EAClF;GAAE,IAAI;GAAgB,MAAM;GAAW,MAAM;GAA+B;EAC7E,CACD,QACC,MACC,EAAE,KAAK,aAAa,CAAC,SAAS,EAAY,aAAa,CAAC,IACxD,EAAE,OAAO,aAAa,CAAC,SAAS,EAAY,aAAa,CAAC,CAC7D,GACD,EAAE,EAGA,IAAa,OAAO,WAAa,OAAe,SAAS,gBAAgB,UAAU,SAAS,OAAO,EACnG,IAAS,QAAc,EAAU,EAAW,EAAE,CAAC,EAAW,CAAC;AAiWjE,QA/VK,IA+VE,EA3VL,kBAAC,OAAD;EACE,OAAO;GACL,UAAU;GACV,KAAK;GACL,MAAM;GACN,OAAO;GACP,QAAQ;GACR,iBAAiB;GACjB,SAAS;GACT,YAAY;GACZ,gBAAgB;GAChB,SAAS;GACT,QAAQ;GACR,WAAW;GACZ;EACD,SAAS;EACT,MAAK;YAEL,kBAAC,OAAD;GACE,MAAK;GACL,cAAW;GACX,mBAAgB;GAChB,eAAY;GACZ,OAAO;IAEL,OAAO;IACP,UAAU;IACV,WAAW;IACX,SAAS;IACT,eAAe;IACf,iBAAiB,EAAO;IACxB,cAAc;IACd,WAAW;IACX,UAAU;IACV,UAAU;IACV,QAAQ;IACR,OAAO,EAAO;IACf;GACD,UAAU,MAAM,EAAE,iBAAiB;aApBrC;IAuBE,kBAAC,OAAD;KACE,OAAO;MACL,YAAY;MACZ,SAAS;MACT,cAAc,aAAa,EAAO;MAClC,SAAS;MACT,YAAY;MACZ,gBAAgB;MAChB,iBAAiB,EAAO;MACzB;eATH,CAWE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;MACE,IAAG;MACH,OAAO;OAAE,QAAQ;OAAG,UAAU;OAAQ,YAAY;OAAK,OAAO,EAAO;OAAa;gBACnF;MAEI,CAAA,EACL,kBAAC,KAAD;MAAG,OAAO;OAAE,QAAQ;OAAW,UAAU;OAAQ,OAAO,EAAO;OAAe;gBAAG;MAAkB,CAAA,CAC/F,EAAA,CAAA,EACN,kBAAC,UAAD;MACE,SAAS;MACT,OAAO;OACL,YAAY;OACZ,QAAQ;OACR,UAAU;OACV,QAAQ;OACR,OAAO,EAAO;OACd,SAAS;OACT,YAAY;OACb;gBACF;MAEQ,CAAA,CACL;;IAGN,kBAAC,OAAD;KACE,MAAK;KACL,cAAW;KACX,OAAO;MACL,YAAY;MACZ,SAAS;MACT,KAAK;MACL,SAAS;MACT,cAAc,aAAa,EAAO;MAClC,iBAAiB,EAAO;MACzB;eAEC,CAAC,UAAU,QAAQ,CAAW,KAAK,MACnC,kBAAC,UAAD;MAEE,MAAK;MACL,MAAK;MACL,iBAAe,MAAc;MAC7B,eAAe,EAAa,EAAI;MAChC,OAAO;OACL,SAAS;OACT,YAAY;OACZ,QAAQ;OACR,cAAc,aAAa,MAAc,IAAM,EAAO,kBAAkB;OACxE,OAAO,MAAc,IAAM,EAAO,cAAc,EAAO;OACvD,UAAU;OACV,YAAY;OACZ,QAAQ;OACT;gBAEA,MAAQ,WAAW,WAAW;MACxB,EAjBF,EAiBE,CACT;KACE,CAAA;IAGL,MAAc,WACb,kBAAC,OAAD;KAAK,WAAU;KAAiC,OAAO,EAAE,iBAAiB,EAAO,WAAW;eAC1F,kBAAC,GAAD;MAAuB;MAAqB;MAAU,CAAA;KAClD,CAAA;IAIP,MAAc,YACb,kBAAC,OAAD;KACE,WAAU;KACV,OAAO,EAAE,iBAAiB,EAAO,WAAW;eAF9C;MAKE,kBAAC,WAAD;OAAS,mBAAgB;iBAAzB,CACE,kBAAC,MAAD;QACE,IAAG;QACH,WAAU;QACV,OAAO,EAAE,OAAO,EAAO,aAAa;kBACrC;QAEI,CAAA,EACL,kBAAC,OAAD;QAAK,OAAO;SAAE,SAAS;SAAQ,KAAK;SAAO,UAAU;SAAQ;kBAA7D,CACE,kBAAC,SAAD;SACE,MAAK;SACL,OAAO;SACP,UAAA;SACA,OAAO;UACL,MAAM;UACN,SAAS;UACT,QAAQ,aAAa,EAAO;UAC5B,cAAc;UACd,UAAU;UACV,iBAAiB,EAAO;UACxB,OAAO,EAAO;UACf;SACD,CAAA,EACF,kBAAC,UAAD;SACE,SAAS;SACT,OAAO;UACL,SAAS;UACT,iBAAiB,IAAc,EAAO,kBAAkB,EAAO;UAC/D,OAAO;UACP,QAAQ;UACR,cAAc;UACd,QAAQ;UACR,UAAU;UACV,YAAY;UACZ,UAAU;UACX;mBAEA,IAAc,YAAY;SACpB,CAAA,CACL;UACE;;MAGV,kBAAC,WAAD;OAAS,mBAAgB;iBAAzB,CACE,kBAAC,MAAD;QACE,IAAG;QACH,WAAU;QACV,OAAO,EAAE,OAAO,EAAO,aAAa;kBACrC;QAEI,CAAA,EACL,kBAAC,OAAD;QAAK,OAAO;SAAE,SAAS;SAAQ,KAAK;SAAO,cAAc;SAAO,UAAU;SAAQ;kBAAlF;SACE,kBAAC,OAAD;UAAK,OAAO;WAAE,MAAM;WAAG,UAAU;WAAY;oBAA7C,CACE,kBAAC,SAAD;WACE,MAAK;WACL,OAAO,IAAoB,EAAkB,OAAO;WACpD,WAAW,MAAM;AAEf,YADA,EAAe,EAAE,OAAO,MAAM,EAC9B,EAAqB,KAAK;;WAE5B,aAAY;WACZ,OAAO;YACL,OAAO;YACP,SAAS;YACT,QAAQ,aAAa,EAAO;YAC5B,cAAc;YACd,UAAU;YACV,iBAAiB,EAAO;YACxB,OAAO,EAAO;YACf;WACD,CAAA,EAED,KAAe,CAAC,KAAqB,EAAc,SAAS,KAC3D,kBAAC,OAAD;WACE,OAAO;YACL,UAAU;YACV,KAAK;YACL,MAAM;YACN,OAAO;YACP,WAAW;YACX,iBAAiB,EAAO;YACxB,QAAQ,aAAa,EAAO;YAC5B,cAAc;YACd,WAAW;YACX,QAAQ;YACR,WAAW;YACX,WAAW;YACZ;qBAEA,EAAc,KAAK,MAClB,kBAAC,UAAD;YAEE,eAAe,EAAqB,EAAO;YAC3C,OAAO;aACL,SAAS;aACT,OAAO;aACP,SAAS;aACT,WAAW;aACX,iBAAiB;aACjB,QAAQ;aACR,QAAQ;aACR,cAAc,aAAa,EAAO;aACnC;sBAZH;aAcE,kBAAC,OAAD;cAAK,OAAO;eAAE,UAAU;eAAQ,YAAY;eAAK,OAAO,EAAO;eAAa;wBACzE,EAAO;cACJ,CAAA;aACL,EAAO,SACN,kBAAC,OAAD;cAAK,OAAO;eAAE,UAAU;eAAQ,OAAO,EAAO;eAAe;wBAAG,EAAO;cAAY,CAAA;aAErF,kBAAC,QAAD;cACE,OAAO;eACL,UAAU;eACV,OAAO,EAAO;eACd,eAAe;eAChB;wBAEA,EAAO;cACH,CAAA;aACA;cA5BF,EAAO,GA4BL,CACT;WACE,CAAA,CAEJ;;SACN,kBAAC,UAAD;UACE,OAAO;UACP,WAAW,MAAM,EAAsB,EAAE,OAAO,MAAyB;UACzE,OAAO;WACL,SAAS;WACT,QAAQ,aAAa,EAAO;WAC5B,cAAc;WACd,UAAU;WACV,iBAAiB,EAAO;WACxB,OAAO,EAAO;WACf;oBAEA,EAAmB,KAAK,MACvB,kBAAC,UAAD;WAAwB,OAAO,EAAI;qBAChC,EAAI;WACE,EAFI,EAAI,MAER,CACT;UACK,CAAA;SACT,kBAAC,UAAD;UACE,SAAS;UACT,UAAU,CAAC,KAAqB;UAChC,OAAO;WACL,SAAS;WACT,iBAAiB,IAAoB,EAAO,kBAAkB,EAAO;WACrE,OAAO,IAAoB,qCAAqC,EAAO;WACvE,QAAQ;WACR,cAAc;WACd,QAAQ,IAAoB,YAAY;WACxC,UAAU;WACV,YAAY;WACb;oBACF;UAEQ,CAAA;SACL;UACE;;MAGV,kBAAC,WAAD;OAAS,mBAAgB;iBAAzB,CACE,kBAAC,OAAD;QACE,OAAO;SACL,SAAS;SACT,YAAY;SACZ,gBAAgB;SAChB,UAAU;SACV,KAAK;SACL,cAAc;SACf;kBARH,CAUE,kBAAC,MAAD;SAAI,IAAG;SAAuB,WAAU;SAAwB,OAAO,EAAE,OAAO,EAAO,aAAa;mBAApG;UAAsG;UAC/E,EAAO;UAAO;UAChC;YACJ,EAAO,SAAS,KACf,kBAAC,UAAD;SACE,SAAS;SACT,OAAO;UACL,SAAS;UACT,iBAAiB;UACjB,OAAO,EAAO;UACd,QAAQ;UACR,QAAQ;UACR,UAAU;UACX;mBACF;SAEQ,CAAA,CAEP;WAEL,KAAW,EAAO,WAAW,IAC5B,kBAAC,KAAD;QAAG,OAAO;SAAE,OAAO,EAAO;SAAe,UAAU;SAAQ;kBAAE;QAAc,CAAA,GACzE,EAAO,WAAW,IACpB,kBAAC,KAAD;QAAG,OAAO;SAAE,OAAO,EAAO;SAAe,UAAU;SAAQ;kBAAE;QAEzD,CAAA,GAEJ,kBAAC,OAAD;QAAK,OAAO;SAAE,SAAS;SAAQ,eAAe;SAAU,KAAK;SAAO;kBACjE,EAAO,KAAK,MACX,kBAAC,GAAD;SAES;SACP,oBAAoB;SACpB,UAAU;SACF;SACR,EALK,EAAM,GAKX,CACF;QACE,CAAA,CAEA;;MACN;;IAEJ;;EACF,CAAA,EAI2B,SAAS,KAAK,GA/V7B;;AA6WtB,SAAS,EAAU,EAAE,UAAO,uBAAoB,aAAU,aAA0B;AAClF,QACE,kBAAC,OAAD;EACE,OAAO;GACL,SAAS;GACT,YAAY;GACZ,gBAAgB;GAChB,SAAS;GACT,iBAAiB,EAAO;GACxB,cAAc;GACf;YARH,CAUE,kBAAC,OAAD;GAAK,OAAO;IAAE,SAAS;IAAQ,YAAY;IAAU,KAAK;IAAQ;aAAlE,CACE,kBAAC,OAAD;IACE,OAAO;KACL,OAAO;KACP,QAAQ;KACR,cAAc;KACd,iBAAiB,EAAO;KACxB,SAAS;KACT,YAAY;KACZ,gBAAgB;KAChB,OAAO;KACP,YAAY;KACZ,UAAU;KACX;cAEA,EAAM,kBAAkB,SAAS,MAAM;IACpC,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;IAAK,OAAO;KAAE,UAAU;KAAQ,YAAY;KAAK,OAAO,EAAO;KAAa;cAAG,EAAM;IAAkB,CAAA,EACvG,kBAAC,OAAD;IAAK,OAAO;KAAE,UAAU;KAAQ,OAAO,EAAO;KAAe;cAA7D;KACG,EAAM;KAAc;KAAW,IAAI,KAAK,EAAM,UAAU,CAAC,oBAAoB;KAC1E;MACF,EAAA,CAAA,CACF;MACN,kBAAC,OAAD;GAAK,OAAO;IAAE,SAAS;IAAQ,YAAY;IAAU,KAAK;IAAO;aAAjE,CACE,kBAAC,UAAD;IACE,OAAO,EAAM;IACb,WAAW,MAAM,EAAmB,EAAM,IAAI,EAAE,OAAO,MAAyB;IAChF,OAAO;KACL,SAAS;KACT,QAAQ,aAAa,EAAO;KAC5B,cAAc;KACd,UAAU;KACV,iBAAiB,EAAO;KACxB,OAAO,EAAO;KACf;cAEA,EAAmB,KAAK,MACvB,kBAAC,UAAD;KAAwB,OAAO,EAAI;eAChC,EAAI;KACE,EAFI,EAAI,MAER,CACT;IACK,CAAA,EACT,kBAAC,UAAD;IACE,eAAe,EAAS,EAAM,GAAG;IACjC,OAAO;KACL,SAAS;KACT,iBAAiB;KACjB,OAAO,EAAO;KACd,QAAQ,aAAa,EAAO;KAC5B,cAAc;KACd,QAAQ;KACR,UAAU;KACX;cACF;IAEQ,CAAA,CACL;KACF"}
|