@burdenoff/microfe-bigconsole 2026.1008.10 → 2026.1008.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/dist/bigconsole/BigConsoleRoutes.d.ts.map +1 -1
  2. package/dist/bigconsole/BigConsoleRoutes.js +136 -127
  3. package/dist/bigconsole/BigConsoleRoutes.js.map +1 -1
  4. package/dist/bigconsole/assistant/assistantProduct.d.ts.map +1 -1
  5. package/dist/bigconsole/assistant/assistantProduct.js +3 -1
  6. package/dist/bigconsole/assistant/assistantProduct.js.map +1 -1
  7. package/dist/bigconsole/components/builder/inspector/DataBindingSection.js +31 -31
  8. package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js +44 -44
  9. package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js.map +1 -1
  10. package/dist/bigconsole/components/dashboard/DashboardCanvas.js +36 -36
  11. package/dist/bigconsole/components/dashboard/DashboardCanvas.js.map +1 -1
  12. package/dist/bigconsole/components/dashboard/DashboardToolbar.js +59 -59
  13. package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js +15 -15
  14. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterChip.js +30 -30
  15. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js +41 -41
  16. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js +34 -34
  17. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js +34 -34
  18. package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js +110 -110
  19. package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js.map +1 -1
  20. package/dist/bigconsole/components/dashboard/PublishToStoreDialog.js +21 -21
  21. package/dist/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.js +46 -46
  22. package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js +91 -91
  23. package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js.map +1 -1
  24. package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js +101 -101
  25. package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js.map +1 -1
  26. package/dist/bigconsole/components/dashboard/TemplateInstallOptions.js +31 -31
  27. package/dist/bigconsole/components/dashboard/TemplateLayoutPreview.js +15 -15
  28. package/dist/bigconsole/components/dashboard/TemplatePicker/TemplatePicker.js +1 -1
  29. package/dist/bigconsole/components/dashboard/WidgetPalette.js +46 -46
  30. package/dist/bigconsole/components/datasink/AlertExecutionHistory.js +37 -37
  31. package/dist/bigconsole/components/datasink/AlertRuleEditor.js +66 -66
  32. package/dist/bigconsole/components/datasink/CacheTTLSelector.js +35 -35
  33. package/dist/bigconsole/components/datasink/DataSinkCard.js +29 -29
  34. package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js +18 -18
  35. package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js +20 -20
  36. package/dist/bigconsole/components/datasink/ImportDataGuideDialog.js +47 -47
  37. package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js +91 -91
  38. package/dist/bigconsole/components/datasink/RefreshTypeSelector.js +35 -35
  39. package/dist/bigconsole/components/parser/DataSinkSelector.js +40 -40
  40. package/dist/bigconsole/components/parser/ImportParserDialog.js +120 -120
  41. package/dist/bigconsole/components/parser/ImportParserDialog.js.map +1 -1
  42. package/dist/bigconsole/components/parser/ParserSelector.js +51 -51
  43. package/dist/bigconsole/components/pipeline/PipelineScopePicker.js +10 -10
  44. package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js +27 -27
  45. package/dist/bigconsole/components/preview/AiPreviewPanel.js +30 -30
  46. package/dist/bigconsole/components/widgets/ActionConfigDialog.js +4 -4
  47. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js +93 -93
  48. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js.map +1 -1
  49. package/dist/bigconsole/components/widgets/PropertiesPanel.d.ts.map +1 -1
  50. package/dist/bigconsole/components/widgets/PropertiesPanel.js +280 -273
  51. package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
  52. package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js +4 -4
  53. package/dist/bigconsole/components/widgets/chart/ChartConfig.js +48 -48
  54. package/dist/bigconsole/components/widgets/comments/WidgetComments.js +46 -46
  55. package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js +61 -61
  56. package/dist/bigconsole/components/widgets/form/FormWidget.js +36 -36
  57. package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js +42 -42
  58. package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js +25 -25
  59. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +4 -4
  60. package/dist/bigconsole/components/widgets/list/ListConfig.js +30 -30
  61. package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js +38 -38
  62. package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js +9 -9
  63. package/dist/bigconsole/components/widgets/metric-card/TrendIndicator.js +9 -9
  64. package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js +49 -49
  65. package/dist/bigconsole/components/widgets/progress/ProgressConfig.js +39 -39
  66. package/dist/bigconsole/components/widgets/table/TableConfig.js +73 -73
  67. package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js +64 -64
  68. package/dist/bigconsole/components/workflow/WorkflowOpenGuard.js +15 -15
  69. package/dist/bigconsole/components/workflow/WorkflowSinkLinkForm.js +15 -15
  70. package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js +9 -9
  71. package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js +67 -67
  72. package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js.map +1 -1
  73. package/dist/bigconsole/hooks/useDashboardLayoutBaseline.d.ts +15 -0
  74. package/dist/bigconsole/hooks/useDashboardLayoutBaseline.d.ts.map +1 -0
  75. package/dist/bigconsole/hooks/useDashboardLayoutBaseline.js +34 -0
  76. package/dist/bigconsole/hooks/useDashboardLayoutBaseline.js.map +1 -0
  77. package/dist/bigconsole/hooks/useDrilldown.js +3 -3
  78. package/dist/bigconsole/hooks/useGlobalFilters.js +3 -3
  79. package/dist/bigconsole/pages/AdminPage.js +130 -130
  80. package/dist/bigconsole/pages/DashboardBuilderPage.d.ts.map +1 -1
  81. package/dist/bigconsole/pages/DashboardBuilderPage.js +72 -60
  82. package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
  83. package/dist/bigconsole/pages/DashboardViewPage.js +1 -1
  84. package/dist/bigconsole/pages/DataSinkAlertsPage.d.ts.map +1 -1
  85. package/dist/bigconsole/pages/DataSinkAlertsPage.js +30 -23
  86. package/dist/bigconsole/pages/DataSinkAlertsPage.js.map +1 -1
  87. package/dist/bigconsole/pages/DataSinkBuilderPage.d.ts.map +1 -1
  88. package/dist/bigconsole/pages/DataSinkBuilderPage.js +272 -263
  89. package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
  90. package/dist/bigconsole/pages/DataSinkViewPage.js +1 -1
  91. package/dist/bigconsole/pages/DataSinksPage.js +1 -1
  92. package/dist/bigconsole/pages/DataSourcesPage.js +5 -5
  93. package/dist/bigconsole/pages/InsightsPage.js +181 -181
  94. package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
  95. package/dist/bigconsole/pages/OverviewPage.js +47 -47
  96. package/dist/bigconsole/pages/OverviewPage.js.map +1 -1
  97. package/dist/bigconsole/pages/ParserBuilderPage.d.ts.map +1 -1
  98. package/dist/bigconsole/pages/ParserBuilderPage.js +227 -211
  99. package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
  100. package/dist/bigconsole/pages/ParserViewPage.js +97 -97
  101. package/dist/bigconsole/pages/PipelineBuilderPage.d.ts.map +1 -1
  102. package/dist/bigconsole/pages/PipelineBuilderPage.js +256 -214
  103. package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
  104. package/dist/bigconsole/pages/PipelineViewPage.js +146 -146
  105. package/dist/bigconsole/pages/PipelinesPage.js +88 -88
  106. package/dist/bigconsole/pages/PipelinesPage.js.map +1 -1
  107. package/dist/bigconsole/pages/SettingsPage.d.ts.map +1 -1
  108. package/dist/bigconsole/pages/SettingsPage.js +179 -173
  109. package/dist/bigconsole/pages/SettingsPage.js.map +1 -1
  110. package/dist/bigconsole/pages/WidgetDemoPage.js +42 -42
  111. package/dist/bigconsole/pages/WorkflowViewPage.js +1 -1
  112. package/dist/bigconsole/pages/WorkflowsPage.js +141 -141
  113. package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
  114. package/dist/bigconsole/providers/BigConsoleQuotaProvider.js +12 -12
  115. package/dist/bigconsole/renderers/adapters/AdaptiveCardRenderer.js +34 -34
  116. package/dist/bigconsole/renderers/adapters/BlockKitRenderer.js +79 -79
  117. package/dist/bigconsole/renderers/adapters/CustomRenderer.js +46 -46
  118. package/dist/bigconsole/store/widgetStore.d.ts +12 -0
  119. package/dist/bigconsole/store/widgetStore.d.ts.map +1 -1
  120. package/dist/bigconsole/store/widgetStore.js +3 -1
  121. package/dist/bigconsole/store/widgetStore.js.map +1 -1
  122. package/dist/bigconsole/utils/formDirty.d.ts +83 -0
  123. package/dist/bigconsole/utils/formDirty.d.ts.map +1 -0
  124. package/dist/bigconsole/utils/formDirty.js +23 -0
  125. package/dist/bigconsole/utils/formDirty.js.map +1 -0
  126. package/dist/bigconsole/utils/layoutBaseline.d.ts +131 -0
  127. package/dist/bigconsole/utils/layoutBaseline.d.ts.map +1 -0
  128. package/dist/bigconsole/utils/layoutBaseline.js +98 -0
  129. package/dist/bigconsole/utils/layoutBaseline.js.map +1 -0
  130. package/dist/translations/en.d.ts.map +1 -1
  131. package/package.json +3 -3
@@ -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, useRef } from 'react';\nimport {\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n} from '@burdenoff/fe-libs/ui';\nimport { formatDistanceToNow } from 'date-fns';\nimport { useDashboardSharing, type DashboardShare, type SharePermission } from '../../../hooks';\nimport type { DashboardVisibility } from '../../../types';\nimport { useBigConsoleAnalytics } from '../../../hooks/useBigConsoleAnalytics';\nimport { EmbedTab } from './EmbedTab';\nimport { useShareRecipients, type ShareRecipient } from '../../../hooks/useShareRecipients';\nimport { useBigConsole, useBigConsoleBasePath } from '../../../context/BigConsoleContext';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\n// Semantic variables follow shell themes even though the dialog is portalled.\nconst colors = {\n bgPrimary: 'var(--color-bg-surface)',\n bgSecondary: 'var(--color-bg-sunken)',\n bgTertiary: 'var(--color-bg-canvas)',\n textPrimary: 'var(--color-text-primary)',\n textSecondary: 'var(--color-text-secondary)',\n textTertiary: 'var(--color-text-muted)',\n borderDefault: 'var(--color-border-default)',\n actionPrimaryBg: 'var(--color-action-primary-bg)',\n actionPrimaryBgHover: 'var(--color-action-primary-bgHover)',\n statusSuccessBg: 'var(--color-status-success-bg)',\n statusErrorText: 'var(--color-status-error-text)',\n};\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ShareDialogProps {\n dashboardId: string;\n dashboardName: string;\n isOpen: boolean;\n onClose: () => void;\n /**\n * Current general-access level (`Dashboard.visibility`). The General access\n * control renders ONLY when this and `onVisibilityChange` are both supplied —\n * a selector with no known current value would be a guess, and one with no\n * handler would be a switch wired to nothing.\n */\n visibility?: DashboardVisibility;\n /** Persist a new general-access level. Resolves once the write completes. */\n onVisibilityChange?: (visibility: DashboardVisibility) => Promise<void>;\n /** False when the actor lacks `bigconsole-dashboard:update`; the control is then read-only. */\n canChangeVisibility?: boolean;\n}\n\n/** General-access levels, in widening order. */\nconst VISIBILITY_OPTIONS: { value: DashboardVisibility; label: string; description: string }[] = [\n { value: 'PRIVATE', label: 'Private', description: 'Only people added below' },\n { value: 'WORKSPACE', label: 'Workspace', description: 'Anyone in this workspace' },\n { value: 'PUBLIC', label: 'Public', description: 'Anyone with the link' },\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(props: ShareDialogProps) {\n const { workspaceId, currentUser } = useBigConsole();\n const returnFocusRef = useRef<HTMLElement | null>(null);\n // Remount sharing state at the authorization boundary, including in-flight ACL reads.\n // The existing sharing hook belongs to a single actor/workspace/dashboard.\n return (\n <ShareDialogContent\n key={`${currentUser?.id ?? ''}|${workspaceId ?? ''}|${props.dashboardId}`}\n {...props}\n returnFocusRef={returnFocusRef}\n />\n );\n}\n\nfunction ShareDialogContent({\n dashboardId,\n dashboardName,\n isOpen,\n onClose,\n visibility,\n onVisibilityChange,\n canChangeVisibility = true,\n returnFocusRef,\n}: ShareDialogProps & { returnFocusRef: React.RefObject<HTMLElement | null> }) {\n const { t } = useI18n();\n const {\n shares,\n loading,\n error: sharingError,\n fetchShares,\n shareWithUser,\n shareWithGroup,\n updateShare,\n revokeShare,\n 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 const [visibilitySaving, setVisibilitySaving] = useState(false);\n const [visibilityError, setVisibilityError] = useState<string | null>(null);\n const [shareError, setShareError] = useState<string | null>(null);\n const directory = useShareRecipients(isOpen, searchQuery);\n const basePath = useBigConsoleBasePath();\n useEffect(() => {\n let cancelled = false;\n void Promise.resolve().then(() => {\n if (cancelled) return;\n setSelectedRecipient(null);\n setSearchQuery('');\n setShareError(null);\n });\n return () => {\n cancelled = true;\n };\n }, [directory.owner, dashboardId, isOpen]);\n\n // Fetch shares when dialog opens\n useEffect(() => {\n if (isOpen && dashboardId) {\n fetchShares(dashboardId);\n // Generate share link\n const url = new URL(`${basePath}/dashboards/${encodeURIComponent(dashboardId)}`, window.location.origin);\n const context = new URLSearchParams(window.location.search);\n for (const key of ['org', 'workspace', 'project', 'tenant']) {\n const value = context.get(key);\n if (value) url.searchParams.set(key, value);\n }\n // The selected workspace remains authoritative when host navigation omits context parameters.\n if (directory.workspaceId) url.searchParams.set('workspace', directory.workspaceId);\n setShareLink(url.toString());\n }\n }, [isOpen, dashboardId, fetchShares, basePath, directory.workspaceId]);\n\n // Handle share - per spec: only USER and GROUP recipient types\n const handleShare = useCallback(async () => {\n if (!selectedRecipient || loading || selectedRecipient.workspaceId !== directory.workspaceId) return;\n setShareError(null);\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 if (!share) {\n setShareError(\n t('bigconsole.share.error.grantFailed', 'Access could not be granted. Review the recipient and try again.')\n );\n return;\n }\n setSelectedRecipient(null);\n setSearchQuery('');\n }, [\n directory.workspaceId,\n t,\n loading,\n dashboardId,\n emitBigConsoleEvent,\n selectedRecipient,\n selectedPermission,\n shareWithGroup,\n shareWithUser,\n ]);\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 const handleVisibilityChange = useCallback(\n async (next: DashboardVisibility) => {\n if (!onVisibilityChange || next === visibility) return;\n setVisibilityError(null);\n setVisibilitySaving(true);\n try {\n await onVisibilityChange(next);\n } catch (err) {\n // Surface the failure: the select snaps back to `visibility`, which the\n // parent has not changed, so a silent catch would look like a success.\n setVisibilityError(err instanceof Error ? err.message : 'Could not update general access.');\n } finally {\n setVisibilitySaving(false);\n }\n },\n [onVisibilityChange, visibility]\n );\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 {\n setShareError(\n t('bigconsole.share.error.copyFailed', 'The link could not be copied. Select the link and copy it manually.')\n );\n }\n }, [shareLink, t]);\n\n const searchResults = directory.results;\n\n if (!isOpen) return null;\n\n return (\n <ResponsiveDialog\n open={isOpen}\n onOpenChange={(open) => {\n if (!open) onClose();\n }}\n >\n <ResponsiveDialogContent\n showCloseButton={false}\n data-testid=\"share-dialog\"\n className=\"flex w-full flex-col gap-0 overflow-hidden rounded-card p-0 sm:w-[calc(100%-2rem)] sm:max-w-[520px]\"\n onOpenAutoFocus={() => {\n const active = document.activeElement;\n // ResponsiveDialog swaps implementations at the breakpoint while open.\n // Keep the original external trigger rather than a control in the old dialog.\n if (active instanceof HTMLElement && active !== document.body && !active.closest('[role=dialog]')) {\n returnFocusRef.current = active;\n }\n }}\n onCloseAutoFocus={(event) => {\n event.preventDefault();\n if (returnFocusRef.current?.isConnected) returnFocusRef.current.focus();\n }}\n style={{ maxWidth: '520px', maxHeight: '85dvh', backgroundColor: colors.bgPrimary, color: colors.textPrimary }}\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 <ResponsiveDialogTitle style={{ margin: 0, fontSize: '18px', fontWeight: 600, color: colors.textPrimary }}>\n Share Dashboard\n </ResponsiveDialogTitle>\n <ResponsiveDialogDescription style={{ margin: '4px 0 0', fontSize: '13px', color: colors.textSecondary }}>\n {dashboardName}\n </ResponsiveDialogDescription>\n </div>\n <button\n type=\"button\"\n aria-label={t('bigconsole.share.closeLabel', 'Close share dialog')}\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 {/* General access — WHO the link works for. It leads because the\n link below is only as useful as this setting allows: copying a\n URL from a PRIVATE board hands over something the recipient\n cannot open. Backed by `Dashboard.visibility` +\n `BigConsoleUpdateDashboardInput.visibility`. */}\n {visibility && onVisibilityChange && (\n <section aria-labelledby=\"share-visibility-heading\">\n <h3\n id=\"share-visibility-heading\"\n className=\"mb-form-gap text-sm font-semibold\"\n style={{ color: colors.textPrimary }}\n >\n General access\n </h3>\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', flexWrap: 'wrap' }}>\n <select\n aria-label=\"General access\"\n data-testid=\"share-visibility\"\n value={visibility}\n disabled={!canChangeVisibility || visibilitySaving}\n onChange={(e) => void handleVisibilityChange(e.target.value as DashboardVisibility)}\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 cursor: !canChangeVisibility || visibilitySaving ? 'not-allowed' : 'pointer',\n opacity: !canChangeVisibility || visibilitySaving ? 0.6 : 1,\n }}\n >\n {VISIBILITY_OPTIONS.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n <span style={{ fontSize: '12px', color: colors.textSecondary }}>\n {VISIBILITY_OPTIONS.find((opt) => opt.value === visibility)?.description}\n </span>\n </div>\n {!canChangeVisibility && (\n <p style={{ margin: '6px 0 0', fontSize: '11px', color: colors.textSecondary }}>\n You don&apos;t have permission to change general access.\n </p>\n )}\n {visibilityError && (\n <p style={{ margin: '6px 0 0', fontSize: '11px', color: colors.statusErrorText }}>\n {visibilityError}\n </p>\n )}\n </section>\n )}\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 {(sharingError || shareError) && (\n <p role=\"alert\" style={{ color: colors.statusErrorText }}>\n {shareError ||\n t('bigconsole.share.error.loadFailed', 'Dashboard access could not be loaded or updated. Try again.')}\n </p>\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 <p style={{ color: colors.textSecondary, fontSize: '13px', marginBottom: '8px' }}>\n {t(\n 'bigconsole.share.directory.scopeHint',\n 'Only members and groups from the current workspace are listed.'\n )}\n </p>\n {directory.loading && (\n <p role=\"status\">{t('bigconsole.share.directory.loading', 'Loading workspace recipients…')}</p>\n )}\n {directory.error && (\n <div role=\"alert\">\n <p>\n {t(\n 'bigconsole.share.directory.loadFailed',\n 'The workspace directory could not be loaded. Your access may not allow directory lookup.'\n )}\n </p>\n <button type=\"button\" onClick={directory.retry}>\n {t('bigconsole.share.directory.retry', 'Retry directory')}\n </button>\n </div>\n )}\n {searchQuery &&\n !selectedRecipient &&\n !directory.loading &&\n !directory.error &&\n searchResults.length === 0 && (\n <p role=\"status\">\n {t('bigconsole.share.directory.empty', 'No matching workspace members or groups.')}\n </p>\n )}\n {directory.hasMoreMembers && (\n <button type=\"button\" disabled={directory.loading} onClick={directory.loadMoreMembers}>\n {t('bigconsole.share.directory.loadMore', 'Load more workspace members')}\n </button>\n )}\n {directory.hasMoreGroups && (\n <p>\n {t(\n 'bigconsole.share.directory.moreGroups',\n 'More groups match. Narrow your search to find a specific group.'\n )}\n </p>\n )}\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 aria-label={t('bigconsole.share.directory.searchLabel', 'Search workspace members and groups')}\n placeholder={t(\n 'bigconsole.share.directory.searchPlaceholder',\n 'Search workspace members or groups...'\n )}\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.type}:${result.id}`}\n type=\"button\"\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 aria-label={t('bigconsole.share.permissionLabel', 'Access permission')}\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 || selectedRecipient.workspaceId !== directory.workspaceId}\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 </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\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: typeof colors;\n}\n\n/**\n * Access window for one share.\n *\n * `expiresAt` is selected by DashboardShareFields on every share this dialog\n * loads, but the row never said whether the access it lists ends — so a share\n * that lapsed yesterday looked identical to a permanent one. Expired shares are\n * called out explicitly: the backend leaves the row in place, so \"expired\" is a\n * state the reader has to be told about, not one they can infer from absence.\n */\nfunction describeExpiry(expiresAt: string | undefined): { label: string; expired: boolean } {\n if (!expiresAt) return { label: 'No expiry', expired: false };\n const date = new Date(expiresAt);\n if (Number.isNaN(date.getTime())) return { label: 'No expiry', expired: false };\n if (date.getTime() <= Date.now()) {\n return { label: `Expired ${formatDistanceToNow(date, { addSuffix: true })}`, expired: true };\n }\n return { label: `Expires ${formatDistanceToNow(date, { addSuffix: true })}`, expired: false };\n}\n\nfunction ShareItem({ share, onUpdatePermission, onRevoke, colors }: ShareItemProps) {\n const expiry = describeExpiry(share.expiresAt);\n\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', flexWrap: 'wrap' }}>\n <span\n data-testid=\"share-expiry\"\n title={share.expiresAt ? new Date(share.expiresAt).toLocaleString() : 'Access does not expire'}\n style={{\n fontSize: '11px',\n padding: '4px 8px',\n borderRadius: '999px',\n whiteSpace: 'nowrap',\n backgroundColor: colors.bgTertiary,\n color: expiry.expired ? colors.statusErrorText : colors.textSecondary,\n fontWeight: expiry.expired ? 600 : 400,\n }}\n >\n {expiry.label}\n </span>\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":";;;;;;;;;;;;AAuBA,IAAM,IAAS;CACb,WAAW;CACX,aAAa;CACb,YAAY;CACZ,aAAa;CACb,eAAe;CACf,cAAc;CACd,eAAe;CACf,iBAAiB;CACjB,sBAAsB;CACtB,iBAAiB;CACjB,iBAAiB;CAClB,EAyBK,IAA2F;CAC/F;EAAE,OAAO;EAAW,OAAO;EAAW,aAAa;EAA2B;CAC9E;EAAE,OAAO;EAAa,OAAO;EAAa,aAAa;EAA4B;CACnF;EAAE,OAAO;EAAU,OAAO;EAAU,aAAa;EAAwB;CAC1E,EAUK,IAAuF,CAC3F;CAAE,OAAO;CAAQ,OAAO;CAAQ,aAAa;CAA0B,EACvE;CAAE,OAAO;CAAQ,OAAO;CAAQ,aAAa;CAAuC,CACrF;AAQD,SAAgB,EAAY,GAAyB;CACnD,IAAM,EAAE,gBAAa,mBAAgB,GAAe,EAC9C,IAAiB,EAA2B,KAAK;AAGvD,QACE,kBAAC,GAAD;EAEE,GAAI;EACY;EAChB,EAHK,GAAG,GAAa,MAAM,GAAG,GAAG,KAAe,GAAG,GAAG,EAAM,cAG5D;;AAIN,SAAS,EAAmB,EAC1B,gBACA,kBACA,WACA,YACA,eACA,uBACA,yBAAsB,IACtB,qBAC6E;CAC7E,IAAM,EAAE,SAAM,IAAS,EACjB,EACJ,WACA,YACA,OAAO,IACP,gBACA,kBACA,mBACA,gBACA,gBACA,uBACE,GAAqB,EACnB,IAAsB,GAAwB,EAE9C,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,CAAC,GAAmB,KAAwB,EAAgC,KAAK,EACjF,CAAC,GAAoB,KAAyB,EAA0B,OAAO,EAC/E,CAAC,GAAW,MAAgB,EAAS,GAAG,EACxC,CAAC,GAAa,KAAkB,EAAS,GAAM,EAC/C,CAAC,GAAW,KAAgB,EAA6B,SAAS,EAClE,CAAC,GAAkB,KAAuB,EAAS,GAAM,EACzD,CAAC,GAAiB,KAAsB,EAAwB,KAAK,EACrE,CAAC,GAAY,KAAiB,EAAwB,KAAK,EAC3D,IAAY,EAAmB,GAAQ,EAAY,EACnD,IAAW,GAAuB;AAexC,CAdA,QAAgB;EACd,IAAI,IAAY;AAOhB,SANK,QAAQ,SAAS,CAAC,WAAW;AAC5B,SACJ,EAAqB,KAAK,EAC1B,EAAe,GAAG,EAClB,EAAc,KAAK;IACnB,QACW;AACX,OAAY;;IAEb;EAAC,EAAU;EAAO;EAAa;EAAO,CAAC,EAG1C,QAAgB;AACd,MAAI,KAAU,GAAa;AACzB,KAAY,EAAY;GAExB,IAAM,IAAM,IAAI,IAAI,GAAG,EAAS,cAAc,mBAAmB,EAAY,IAAI,OAAO,SAAS,OAAO,EAClG,IAAU,IAAI,gBAAgB,OAAO,SAAS,OAAO;AAC3D,QAAK,IAAM,KAAO;IAAC;IAAO;IAAa;IAAW;IAAS,EAAE;IAC3D,IAAM,IAAQ,EAAQ,IAAI,EAAI;AAC9B,IAAI,KAAO,EAAI,aAAa,IAAI,GAAK,EAAM;;AAI7C,GADI,EAAU,eAAa,EAAI,aAAa,IAAI,aAAa,EAAU,YAAY,EACnF,GAAa,EAAI,UAAU,CAAC;;IAE7B;EAAC;EAAQ;EAAa;EAAa;EAAU,EAAU;EAAY,CAAC;CAGvE,IAAM,KAAc,EAAY,YAAY;AAC1C,MAAI,CAAC,KAAqB,KAAW,EAAkB,gBAAgB,EAAU,YAAa;AAG9F,EAFA,EAAc,KAAK,EAEnB,EAAoB,sCAAsC;GACxD;GACA,YAAY;GACZ,eAAe,EAAkB;GAClC,CAAC;EAEF,IAAI,IAA+B;AAenC,MAdI,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,EAGA,CAAC,GAAO;AACV,KACE,EAAE,sCAAsC,mEAAmE,CAC5G;AACD;;AAGF,EADA,EAAqB,KAAK,EAC1B,EAAe,GAAG;IACjB;EACD,EAAU;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,EAGI,KAAyB,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,KAAkB,EAAY,YAAY;AAC9C,EAAI,OAAO,QAAQ,qDAAqD,IACtE,MAAM,EAAgB,EAAY;IAEnC,CAAC,GAAa,EAAgB,CAAC,EAE5B,KAAyB,EAC7B,OAAO,MAA8B;AAC/B,SAAC,KAAsB,MAAS,IAEpC;GADA,EAAmB,KAAK,EACxB,EAAoB,GAAK;AACzB,OAAI;AACF,UAAM,EAAmB,EAAK;YACvB,GAAK;AAGZ,MAAmB,aAAe,QAAQ,EAAI,UAAU,mCAAmC;aACnF;AACR,MAAoB,GAAM;;;IAG9B,CAAC,GAAoB,EAAW,CACjC,EAGK,KAAiB,EAAY,YAAY;AAC7C,MAAI;AAGF,GAFA,MAAM,UAAU,UAAU,UAAU,EAAU,EAC9C,EAAe,GAAK,EACpB,iBAAiB,EAAe,GAAM,EAAE,IAAK;UACvC;AACN,KACE,EAAE,qCAAqC,sEAAsE,CAC9G;;IAEF,CAAC,GAAW,EAAE,CAAC,EAEZ,IAAgB,EAAU;AAIhC,QAFK,IAGH,kBAAC,IAAD;EACE,MAAM;EACN,eAAe,MAAS;AACtB,GAAK,KAAM,GAAS;;YAGtB,kBAAC,GAAD;GACE,iBAAiB;GACjB,eAAY;GACZ,WAAU;GACV,uBAAuB;IACrB,IAAM,IAAS,SAAS;AAGxB,IAAI,aAAkB,eAAe,MAAW,SAAS,QAAQ,CAAC,EAAO,QAAQ,gBAAgB,KAC/F,EAAe,UAAU;;GAG7B,mBAAmB,MAAU;AAE3B,IADA,EAAM,gBAAgB,EAClB,EAAe,SAAS,eAAa,EAAe,QAAQ,OAAO;;GAEzE,OAAO;IAAE,UAAU;IAAS,WAAW;IAAS,iBAAiB,EAAO;IAAW,OAAO,EAAO;IAAa;aAhBhH;IAmBE,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,IAAD;MAAuB,OAAO;OAAE,QAAQ;OAAG,UAAU;OAAQ,YAAY;OAAK,OAAO,EAAO;OAAa;gBAAE;MAEnF,CAAA,EACxB,kBAAC,GAAD;MAA6B,OAAO;OAAE,QAAQ;OAAW,UAAU;OAAQ,OAAO,EAAO;OAAe;gBACrG;MAC2B,CAAA,CAC1B,EAAA,CAAA,EACN,kBAAC,UAAD;MACE,MAAK;MACL,cAAY,EAAE,+BAA+B,qBAAqB;MAClE,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;MASG,KAAc,KACb,kBAAC,WAAD;OAAS,mBAAgB;iBAAzB;QACE,kBAAC,MAAD;SACE,IAAG;SACH,WAAU;SACV,OAAO,EAAE,OAAO,EAAO,aAAa;mBACrC;SAEI,CAAA;QACL,kBAAC,OAAD;SAAK,OAAO;UAAE,SAAS;UAAQ,YAAY;UAAU,KAAK;UAAO,UAAU;UAAQ;mBAAnF,CACE,kBAAC,UAAD;UACE,cAAW;UACX,eAAY;UACZ,OAAO;UACP,UAAU,CAAC,KAAuB;UAClC,WAAW,MAAM,KAAK,GAAuB,EAAE,OAAO,MAA6B;UACnF,OAAO;WACL,SAAS;WACT,QAAQ,aAAa,EAAO;WAC5B,cAAc;WACd,UAAU;WACV,iBAAiB,EAAO;WACxB,OAAO,EAAO;WACd,QAAQ,CAAC,KAAuB,IAAmB,gBAAgB;WACnE,SAAS,CAAC,KAAuB,IAAmB,KAAM;WAC3D;oBAEA,EAAmB,KAAK,MACvB,kBAAC,UAAD;WAAwB,OAAO,EAAI;qBAChC,EAAI;WACE,EAFI,EAAI,MAER,CACT;UACK,CAAA,EACT,kBAAC,QAAD;UAAM,OAAO;WAAE,UAAU;WAAQ,OAAO,EAAO;WAAe;oBAC3D,EAAmB,MAAM,MAAQ,EAAI,UAAU,EAAW,EAAE;UACxD,CAAA,CACH;;QACL,CAAC,KACA,kBAAC,KAAD;SAAG,OAAO;UAAE,QAAQ;UAAW,UAAU;UAAQ,OAAO,EAAO;UAAe;mBAAE;SAE5E,CAAA;QAEL,KACC,kBAAC,KAAD;SAAG,OAAO;UAAE,QAAQ;UAAW,UAAU;UAAQ,OAAO,EAAO;UAAiB;mBAC7E;SACC,CAAA;QAEE;;MAIZ,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;;OAER,MAAgB,MAChB,kBAAC,KAAD;OAAG,MAAK;OAAQ,OAAO,EAAE,OAAO,EAAO,iBAAiB;iBACrD,KACC,EAAE,qCAAqC,8DAA8D;OACrG,CAAA;MAGN,kBAAC,WAAD;OAAS,mBAAgB;iBAAzB;QACE,kBAAC,MAAD;SACE,IAAG;SACH,WAAU;SACV,OAAO,EAAE,OAAO,EAAO,aAAa;mBACrC;SAEI,CAAA;QACL,kBAAC,KAAD;SAAG,OAAO;UAAE,OAAO,EAAO;UAAe,UAAU;UAAQ,cAAc;UAAO;mBAC7E,EACC,wCACA,iEACD;SACC,CAAA;QACH,EAAU,WACT,kBAAC,KAAD;SAAG,MAAK;mBAAU,EAAE,sCAAsC,gCAAgC;SAAK,CAAA;QAEhG,EAAU,SACT,kBAAC,OAAD;SAAK,MAAK;mBAAV,CACE,kBAAC,KAAD,EAAA,UACG,EACC,yCACA,2FACD,EACC,CAAA,EACJ,kBAAC,UAAD;UAAQ,MAAK;UAAS,SAAS,EAAU;oBACtC,EAAE,oCAAoC,kBAAkB;UAClD,CAAA,CACL;;QAEP,KACC,CAAC,KACD,CAAC,EAAU,WACX,CAAC,EAAU,SACX,EAAc,WAAW,KACvB,kBAAC,KAAD;SAAG,MAAK;mBACL,EAAE,oCAAoC,2CAA2C;SAChF,CAAA;QAEP,EAAU,kBACT,kBAAC,UAAD;SAAQ,MAAK;SAAS,UAAU,EAAU;SAAS,SAAS,EAAU;mBACnE,EAAE,uCAAuC,8BAA8B;SACjE,CAAA;QAEV,EAAU,iBACT,kBAAC,KAAD,EAAA,UACG,EACC,yCACA,kEACD,EACC,CAAA;QAEN,kBAAC,OAAD;SAAK,OAAO;UAAE,SAAS;UAAQ,KAAK;UAAO,cAAc;UAAO,UAAU;UAAQ;mBAAlF;UACE,kBAAC,OAAD;WAAK,OAAO;YAAE,MAAM;YAAG,UAAU;YAAY;qBAA7C,CACE,kBAAC,SAAD;YACE,MAAK;YACL,OAAO,IAAoB,EAAkB,OAAO;YACpD,WAAW,MAAM;AAEf,aADA,EAAe,EAAE,OAAO,MAAM,EAC9B,EAAqB,KAAK;;YAE5B,cAAY,EAAE,0CAA0C,sCAAsC;YAC9F,aAAa,EACX,gDACA,wCACD;YACD,OAAO;aACL,OAAO;aACP,SAAS;aACT,QAAQ,aAAa,EAAO;aAC5B,cAAc;aACd,UAAU;aACV,iBAAiB,EAAO;aACxB,OAAO,EAAO;aACf;YACD,CAAA,EAED,KAAe,CAAC,KAAqB,EAAc,SAAS,KAC3D,kBAAC,OAAD;YACE,OAAO;aACL,UAAU;aACV,KAAK;aACL,MAAM;aACN,OAAO;aACP,WAAW;aACX,iBAAiB,EAAO;aACxB,QAAQ,aAAa,EAAO;aAC5B,cAAc;aACd,WAAW;aACX,QAAQ;aACR,WAAW;aACX,WAAW;aACZ;sBAEA,EAAc,KAAK,MAClB,kBAAC,UAAD;aAEE,MAAK;aACL,eAAe,EAAqB,EAAO;aAC3C,OAAO;cACL,SAAS;cACT,OAAO;cACP,SAAS;cACT,WAAW;cACX,iBAAiB;cACjB,QAAQ;cACR,QAAQ;cACR,cAAc,aAAa,EAAO;cACnC;uBAbH;cAeE,kBAAC,OAAD;eAAK,OAAO;gBAAE,UAAU;gBAAQ,YAAY;gBAAK,OAAO,EAAO;gBAAa;yBACzE,EAAO;eACJ,CAAA;cACL,EAAO,SACN,kBAAC,OAAD;eAAK,OAAO;gBAAE,UAAU;gBAAQ,OAAO,EAAO;gBAAe;yBAAG,EAAO;eAAY,CAAA;cAErF,kBAAC,QAAD;eACE,OAAO;gBACL,UAAU;gBACV,OAAO,EAAO;gBACd,eAAe;gBAChB;yBAEA,EAAO;eACH,CAAA;cACA;eA7BF,GAAG,EAAO,KAAK,GAAG,EAAO,KA6BvB,CACT;YACE,CAAA,CAEJ;;UACN,kBAAC,UAAD;WACE,cAAY,EAAE,oCAAoC,oBAAoB;WACtE,OAAO;WACP,WAAW,MAAM,EAAsB,EAAE,OAAO,MAAyB;WACzE,OAAO;YACL,SAAS;YACT,QAAQ,aAAa,EAAO;YAC5B,cAAc;YACd,UAAU;YACV,iBAAiB,EAAO;YACxB,OAAO,EAAO;YACf;qBAEA,EAAmB,KAAK,MACvB,kBAAC,UAAD;YAAwB,OAAO,EAAI;sBAChC,EAAI;YACE,EAFI,EAAI,MAER,CACT;WACK,CAAA;UACT,kBAAC,UAAD;WACE,SAAS;WACT,UAAU,CAAC,KAAqB,KAAW,EAAkB,gBAAgB,EAAU;WACvF,OAAO;YACL,SAAS;YACT,iBAAiB,IAAoB,EAAO,kBAAkB,EAAO;YACrE,OAAO,IAAoB,qCAAqC,EAAO;YACvE,QAAQ;YACR,cAAc;YACd,QAAQ,IAAoB,YAAY;YACxC,UAAU;YACV,YAAY;YACb;qBACF;WAEQ,CAAA;UACL;;QACE;;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,IAAD;SAES;SACP,oBAAoB;SACpB,UAAU;SACF;SACR,EALK,EAAM,GAKX,CACF;QACE,CAAA,CAEA;;MACN;;IAEgB;;EACT,CAAA,GA1bD;;AAkdtB,SAAS,EAAe,GAAoE;AAC1F,KAAI,CAAC,EAAW,QAAO;EAAE,OAAO;EAAa,SAAS;EAAO;CAC7D,IAAM,IAAO,IAAI,KAAK,EAAU;AAKhC,QAJI,OAAO,MAAM,EAAK,SAAS,CAAC,GAAS;EAAE,OAAO;EAAa,SAAS;EAAO,GAC3E,EAAK,SAAS,IAAI,KAAK,KAAK,GACvB;EAAE,OAAO,WAAW,EAAoB,GAAM,EAAE,WAAW,IAAM,CAAC;EAAI,SAAS;EAAM,GAEvF;EAAE,OAAO,WAAW,EAAoB,GAAM,EAAE,WAAW,IAAM,CAAC;EAAI,SAAS;EAAO;;AAG/F,SAAS,GAAU,EAAE,UAAO,uBAAoB,aAAU,aAA0B;CAClF,IAAM,IAAS,EAAe,EAAM,UAAU;AAE9C,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,UAAU;IAAQ;aAAnF;IACE,kBAAC,QAAD;KACE,eAAY;KACZ,OAAO,EAAM,YAAY,IAAI,KAAK,EAAM,UAAU,CAAC,gBAAgB,GAAG;KACtE,OAAO;MACL,UAAU;MACV,SAAS;MACT,cAAc;MACd,YAAY;MACZ,iBAAiB,EAAO;MACxB,OAAO,EAAO,UAAU,EAAO,kBAAkB,EAAO;MACxD,YAAY,EAAO,UAAU,MAAM;MACpC;eAEA,EAAO;KACH,CAAA;IACP,kBAAC,UAAD;KACE,OAAO,EAAM;KACb,WAAW,MAAM,EAAmB,EAAM,IAAI,EAAE,OAAO,MAAyB;KAChF,OAAO;MACL,SAAS;MACT,QAAQ,aAAa,EAAO;MAC5B,cAAc;MACd,UAAU;MACV,iBAAiB,EAAO;MACxB,OAAO,EAAO;MACf;eAEA,EAAmB,KAAK,MACvB,kBAAC,UAAD;MAAwB,OAAO,EAAI;gBAChC,EAAI;MACE,EAFI,EAAI,MAER,CACT;KACK,CAAA;IACT,kBAAC,UAAD;KACE,eAAe,EAAS,EAAM,GAAG;KACjC,OAAO;MACL,SAAS;MACT,iBAAiB;MACjB,OAAO,EAAO;MACd,QAAQ,aAAa,EAAO;MAC5B,cAAc;MACd,QAAQ;MACR,UAAU;MACX;eACF;KAEQ,CAAA;IACL;KACF"}
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, useRef } from 'react';\nimport {\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n} from '@burdenoff/fe-libs/ui';\nimport { formatDistanceToNow } from 'date-fns';\nimport { useDashboardSharing, type DashboardShare, type SharePermission } from '../../../hooks';\nimport type { DashboardVisibility } from '../../../types';\nimport { useBigConsoleAnalytics } from '../../../hooks/useBigConsoleAnalytics';\nimport { EmbedTab } from './EmbedTab';\nimport { useShareRecipients, type ShareRecipient } from '../../../hooks/useShareRecipients';\nimport { useBigConsole, useBigConsoleBasePath } from '../../../context/BigConsoleContext';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\n// Semantic variables follow shell themes even though the dialog is portalled.\nconst colors = {\n bgPrimary: 'var(--color-bg-surface)',\n bgSecondary: 'var(--color-bg-sunken)',\n bgTertiary: 'var(--color-bg-canvas)',\n textPrimary: 'var(--color-text-primary)',\n textSecondary: 'var(--color-text-secondary)',\n textTertiary: 'var(--color-text-muted)',\n borderDefault: 'var(--color-border-default)',\n actionPrimaryBg: 'var(--color-action-primary-bg)',\n actionPrimaryBgHover: 'var(--color-action-primary-bgHover)',\n statusSuccessBg: 'var(--color-status-success-bg)',\n statusErrorText: 'var(--color-status-error-text)',\n};\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ShareDialogProps {\n dashboardId: string;\n dashboardName: string;\n isOpen: boolean;\n onClose: () => void;\n /**\n * Current general-access level (`Dashboard.visibility`). The General access\n * control renders ONLY when this and `onVisibilityChange` are both supplied —\n * a selector with no known current value would be a guess, and one with no\n * handler would be a switch wired to nothing.\n */\n visibility?: DashboardVisibility;\n /** Persist a new general-access level. Resolves once the write completes. */\n onVisibilityChange?: (visibility: DashboardVisibility) => Promise<void>;\n /** False when the actor lacks `bigconsole-dashboard:update`; the control is then read-only. */\n canChangeVisibility?: boolean;\n}\n\n/** General-access levels, in widening order. */\nconst VISIBILITY_OPTIONS: { value: DashboardVisibility; label: string; description: string }[] = [\n { value: 'PRIVATE', label: 'Private', description: 'Only people added below' },\n { value: 'WORKSPACE', label: 'Workspace', description: 'Anyone in this workspace' },\n { value: 'PUBLIC', label: 'Public', description: 'Anyone with the link' },\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(props: ShareDialogProps) {\n const { workspaceId, currentUser } = useBigConsole();\n const returnFocusRef = useRef<HTMLElement | null>(null);\n // Remount sharing state at the authorization boundary, including in-flight ACL reads.\n // The existing sharing hook belongs to a single actor/workspace/dashboard.\n return (\n <ShareDialogContent\n key={`${currentUser?.id ?? ''}|${workspaceId ?? ''}|${props.dashboardId}`}\n {...props}\n returnFocusRef={returnFocusRef}\n />\n );\n}\n\nfunction ShareDialogContent({\n dashboardId,\n dashboardName,\n isOpen,\n onClose,\n visibility,\n onVisibilityChange,\n canChangeVisibility = true,\n returnFocusRef,\n}: ShareDialogProps & { returnFocusRef: React.RefObject<HTMLElement | null> }) {\n const { t } = useI18n();\n const {\n shares,\n loading,\n error: sharingError,\n fetchShares,\n shareWithUser,\n shareWithGroup,\n updateShare,\n revokeShare,\n 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 const [visibilitySaving, setVisibilitySaving] = useState(false);\n const [visibilityError, setVisibilityError] = useState<string | null>(null);\n const [shareError, setShareError] = useState<string | null>(null);\n const directory = useShareRecipients(isOpen, searchQuery);\n const basePath = useBigConsoleBasePath();\n useEffect(() => {\n let cancelled = false;\n void Promise.resolve().then(() => {\n if (cancelled) return;\n setSelectedRecipient(null);\n setSearchQuery('');\n setShareError(null);\n });\n return () => {\n cancelled = true;\n };\n }, [directory.owner, dashboardId, isOpen]);\n\n // Fetch shares when dialog opens\n useEffect(() => {\n if (isOpen && dashboardId) {\n fetchShares(dashboardId);\n // Generate share link\n const url = new URL(`${basePath}/dashboards/${encodeURIComponent(dashboardId)}`, window.location.origin);\n const context = new URLSearchParams(window.location.search);\n for (const key of ['org', 'workspace', 'project', 'tenant']) {\n const value = context.get(key);\n if (value) url.searchParams.set(key, value);\n }\n // The selected workspace remains authoritative when host navigation omits context parameters.\n if (directory.workspaceId) url.searchParams.set('workspace', directory.workspaceId);\n setShareLink(url.toString());\n }\n }, [isOpen, dashboardId, fetchShares, basePath, directory.workspaceId]);\n\n // Handle share - per spec: only USER and GROUP recipient types\n const handleShare = useCallback(async () => {\n if (!selectedRecipient || loading || selectedRecipient.workspaceId !== directory.workspaceId) return;\n setShareError(null);\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 if (!share) {\n setShareError(\n t('bigconsole.share.error.grantFailed', 'Access could not be granted. Review the recipient and try again.')\n );\n return;\n }\n setSelectedRecipient(null);\n setSearchQuery('');\n }, [\n directory.workspaceId,\n t,\n loading,\n dashboardId,\n emitBigConsoleEvent,\n selectedRecipient,\n selectedPermission,\n shareWithGroup,\n shareWithUser,\n ]);\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 const handleVisibilityChange = useCallback(\n async (next: DashboardVisibility) => {\n if (!onVisibilityChange || next === visibility) return;\n setVisibilityError(null);\n setVisibilitySaving(true);\n try {\n await onVisibilityChange(next);\n } catch (err) {\n // Surface the failure: the select snaps back to `visibility`, which the\n // parent has not changed, so a silent catch would look like a success.\n setVisibilityError(err instanceof Error ? err.message : 'Could not update general access.');\n } finally {\n setVisibilitySaving(false);\n }\n },\n [onVisibilityChange, visibility]\n );\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 {\n setShareError(\n t('bigconsole.share.error.copyFailed', 'The link could not be copied. Select the link and copy it manually.')\n );\n }\n }, [shareLink, t]);\n\n const searchResults = directory.results;\n\n if (!isOpen) return null;\n\n return (\n <ResponsiveDialog\n open={isOpen}\n onOpenChange={(open) => {\n if (!open) onClose();\n }}\n >\n <ResponsiveDialogContent\n showCloseButton={false}\n data-testid=\"share-dialog\"\n className=\"flex w-full flex-col gap-0 overflow-hidden rounded-card p-0 sm:w-[calc(100%-2rem)] sm:max-w-[520px]\"\n onOpenAutoFocus={() => {\n const active = document.activeElement;\n // ResponsiveDialog swaps implementations at the breakpoint while open.\n // Keep the original external trigger rather than a control in the old dialog.\n if (active instanceof HTMLElement && active !== document.body && !active.closest('[role=dialog]')) {\n returnFocusRef.current = active;\n }\n }}\n onCloseAutoFocus={(event) => {\n event.preventDefault();\n if (returnFocusRef.current?.isConnected) returnFocusRef.current.focus();\n }}\n style={{ maxWidth: '520px', maxHeight: '85dvh', backgroundColor: colors.bgPrimary, color: colors.textPrimary }}\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 <ResponsiveDialogTitle style={{ margin: 0, fontSize: '18px', fontWeight: 600, color: colors.textPrimary }}>\n Share Dashboard\n </ResponsiveDialogTitle>\n <ResponsiveDialogDescription style={{ margin: '4px 0 0', fontSize: '13px', color: colors.textSecondary }}>\n {dashboardName}\n </ResponsiveDialogDescription>\n </div>\n <button\n type=\"button\"\n aria-label={t('bigconsole.share.closeLabel', 'Close share dialog')}\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 {/* General access — WHO the link works for. It leads because the\n link below is only as useful as this setting allows: copying a\n URL from a PRIVATE board hands over something the recipient\n cannot open. Backed by `Dashboard.visibility` +\n `BigConsoleUpdateDashboardInput.visibility`. */}\n {visibility && onVisibilityChange && (\n <section aria-labelledby=\"share-visibility-heading\">\n <h3\n id=\"share-visibility-heading\"\n className=\"mb-form-gap text-sm font-semibold\"\n style={{ color: colors.textPrimary }}\n >\n General access\n </h3>\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', flexWrap: 'wrap' }}>\n <select\n aria-label=\"General access\"\n data-testid=\"share-visibility\"\n value={visibility}\n disabled={!canChangeVisibility || visibilitySaving}\n onChange={(e) => void handleVisibilityChange(e.target.value as DashboardVisibility)}\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 cursor: !canChangeVisibility || visibilitySaving ? 'not-allowed' : 'pointer',\n opacity: !canChangeVisibility || visibilitySaving ? 0.6 : 1,\n }}\n >\n {VISIBILITY_OPTIONS.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n <span style={{ fontSize: '12px', color: colors.textSecondary }}>\n {VISIBILITY_OPTIONS.find((opt) => opt.value === visibility)?.description}\n </span>\n </div>\n {!canChangeVisibility && (\n <p style={{ margin: '6px 0 0', fontSize: '11px', color: colors.textSecondary }}>\n You don&apos;t have permission to change general access.\n </p>\n )}\n {visibilityError && (\n <p style={{ margin: '6px 0 0', fontSize: '11px', color: colors.statusErrorText }}>\n {visibilityError}\n </p>\n )}\n </section>\n )}\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 {(sharingError || shareError) && (\n <p role=\"alert\" style={{ color: colors.statusErrorText }}>\n {shareError ||\n t('bigconsole.share.error.loadFailed', 'Dashboard access could not be loaded or updated. Try again.')}\n </p>\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 <p style={{ color: colors.textSecondary, fontSize: '13px', marginBottom: '8px' }}>\n {t(\n 'bigconsole.share.directory.scopeHint',\n 'Only members and groups from the current workspace are listed.'\n )}\n </p>\n {directory.loading && (\n <p role=\"status\">{t('bigconsole.share.directory.loading', 'Loading workspace recipients…')}</p>\n )}\n {directory.error && (\n <div role=\"alert\">\n <p>\n {t(\n 'bigconsole.share.directory.loadFailed',\n 'The workspace directory could not be loaded. Your access may not allow directory lookup.'\n )}\n </p>\n <button type=\"button\" onClick={directory.retry}>\n {t('bigconsole.share.directory.retry', 'Retry directory')}\n </button>\n </div>\n )}\n {searchQuery &&\n !selectedRecipient &&\n !directory.loading &&\n !directory.error &&\n searchResults.length === 0 && (\n <p role=\"status\">\n {t('bigconsole.share.directory.empty', 'No matching workspace members or groups.')}\n </p>\n )}\n {directory.hasMoreMembers && (\n <button type=\"button\" disabled={directory.loading} onClick={directory.loadMoreMembers}>\n {t('bigconsole.share.directory.loadMore', 'Load more workspace members')}\n </button>\n )}\n {directory.hasMoreGroups && (\n <p>\n {t(\n 'bigconsole.share.directory.moreGroups',\n 'More groups match. Narrow your search to find a specific group.'\n )}\n </p>\n )}\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 aria-label={t('bigconsole.share.directory.searchLabel', 'Search workspace members and groups')}\n placeholder={t(\n 'bigconsole.share.directory.searchPlaceholder',\n 'Search workspace members or groups...'\n )}\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.type}:${result.id}`}\n type=\"button\"\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 aria-label={t('bigconsole.share.permissionLabel', 'Access permission')}\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 || selectedRecipient.workspaceId !== directory.workspaceId}\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 </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\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: typeof colors;\n}\n\n/**\n * Access window for one share.\n *\n * `expiresAt` is selected by DashboardShareFields on every share this dialog\n * loads, but the row never said whether the access it lists ends — so a share\n * that lapsed yesterday looked identical to a permanent one. Expired shares are\n * called out explicitly: the backend leaves the row in place, so \"expired\" is a\n * state the reader has to be told about, not one they can infer from absence.\n */\nfunction describeExpiry(expiresAt: string | undefined): { label: string; expired: boolean } {\n if (!expiresAt) return { label: 'No expiry', expired: false };\n const date = new Date(expiresAt);\n if (Number.isNaN(date.getTime())) return { label: 'No expiry', expired: false };\n if (date.getTime() <= Date.now()) {\n return { label: `Expired ${formatDistanceToNow(date, { addSuffix: true })}`, expired: true };\n }\n return { label: `Expires ${formatDistanceToNow(date, { addSuffix: true })}`, expired: false };\n}\n\nfunction ShareItem({ share, onUpdatePermission, onRevoke, colors }: ShareItemProps) {\n const expiry = describeExpiry(share.expiresAt);\n\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', flexWrap: 'wrap' }}>\n <span\n data-testid=\"share-expiry\"\n title={share.expiresAt ? new Date(share.expiresAt).toLocaleString() : 'Access does not expire'}\n style={{\n fontSize: '11px',\n padding: '4px 8px',\n borderRadius: '999px',\n whiteSpace: 'nowrap',\n backgroundColor: colors.bgTertiary,\n color: expiry.expired ? colors.statusErrorText : colors.textSecondary,\n fontWeight: expiry.expired ? 600 : 400,\n }}\n >\n {expiry.label}\n </span>\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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"}
@@ -2,14 +2,14 @@ import { ListDataSinksDocument as e } from "../../../generated/wspace-operations
2
2
  import { BIGCONSOLE_PERMISSIONS as t } from "../../../constants/permissions.js";
3
3
  import { useEffect as n, useId as r, useRef as i, useState as a } from "react";
4
4
  import { Input as o } from "@burdenoff/fe-libs/ui";
5
- import { useApolloClient as s } from "@apollo/client/react";
6
- import { jsx as c, jsxs as l } from "react/jsx-runtime";
7
- import { useI18n as u } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
5
+ import { useI18n as s } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
6
+ import { useApolloClient as c } from "@apollo/client/react";
7
+ import { jsx as l, jsxs as u } from "react/jsx-runtime";
8
8
  import { useActiveContext as d } from "@burdenoff/fe-libs/shared/providers/shell/ActiveContextProvider";
9
9
  import { usePermissions as f } from "@burdenoff/fe-libs/shared/providers/shell/PermissionProvider";
10
10
  //#region src/bigconsole/components/dashboard/TemplateInstallOptions.tsx
11
11
  function p({ content: p, bindings: m, onBindingChange: h, inputValues: g, onInputChange: _, disabled: v }) {
12
- let y = r(), { t: b } = u(), x = s(), { workspaceId: S } = d(), { hasPermission: C, isLoading: w } = f(), T = !w && C(t.DATASINK_READ), E = p.requiredDataSinks.length > 0, D = `${S}:${T}:${E}`, O = i(D);
12
+ let y = r(), { t: b } = s(), x = c(), { workspaceId: S } = d(), { hasPermission: C, isLoading: w } = f(), T = !w && C(t.DATASINK_READ), E = p.requiredDataSinks.length > 0, D = `${S}:${T}:${E}`, O = i(D);
13
13
  O.current = D;
14
14
  let [k, A] = a(0), [j, M] = a(null), N = j?.owner === D ? j.cursor : void 0, [P, F] = a(null);
15
15
  n(() => {
@@ -77,68 +77,68 @@ function p({ content: p, bindings: m, onBindingChange: h, inputValues: g, onInpu
77
77
  border: "1px solid var(--color-border-default)",
78
78
  borderRadius: "var(--radius-control)"
79
79
  };
80
- return /* @__PURE__ */ l("section", {
80
+ return /* @__PURE__ */ u("section", {
81
81
  "aria-label": b("bigconsole.dashboards.templateSetup.title", "Template setup"),
82
82
  className: "space-y-form-gap",
83
- children: [p.requiredDataSinks.length > 0 && /* @__PURE__ */ l("div", { children: [
84
- /* @__PURE__ */ c("h3", {
83
+ children: [p.requiredDataSinks.length > 0 && /* @__PURE__ */ u("div", { children: [
84
+ /* @__PURE__ */ l("h3", {
85
85
  className: "text-sm font-medium",
86
86
  children: b("bigconsole.dashboards.templateSetup.connect", "Connect your data")
87
87
  }),
88
- /* @__PURE__ */ c("p", {
88
+ /* @__PURE__ */ l("p", {
89
89
  className: "text-xs text-text-muted",
90
90
  children: b("bigconsole.dashboards.templateSetup.connectHelp", "Choose a source for each group of widgets. You can also connect it later in the dashboard builder.")
91
91
  }),
92
- !w && !T && /* @__PURE__ */ c("p", {
92
+ !w && !T && /* @__PURE__ */ l("p", {
93
93
  role: "status",
94
94
  children: b("bigconsole.dashboards.templateSetup.noReadPermission", "You do not have access to browse data sources. You can connect a source later with help from your workspace admin.")
95
95
  }),
96
- R && /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("p", {
96
+ R && /* @__PURE__ */ u("div", { children: [/* @__PURE__ */ l("p", {
97
97
  role: "alert",
98
98
  children: b("bigconsole.dashboards.templateSetup.loadError", "Could not load data sources.")
99
- }), /* @__PURE__ */ c("button", {
99
+ }), /* @__PURE__ */ l("button", {
100
100
  type: "button",
101
101
  disabled: v,
102
102
  onClick: () => A((e) => e + 1),
103
103
  children: b("bigconsole.dashboards.templateSetup.retry", "Retry loading sources")
104
104
  })] }),
105
- p.requiredDataSinks.map((e, t) => /* @__PURE__ */ l("div", {
105
+ p.requiredDataSinks.map((e, t) => /* @__PURE__ */ u("div", {
106
106
  className: "mt-form-gap",
107
107
  children: [
108
- /* @__PURE__ */ c("label", {
108
+ /* @__PURE__ */ l("label", {
109
109
  htmlFor: `${y}-sink-${t}`,
110
110
  className: "text-sm font-medium",
111
111
  children: e.label
112
112
  }),
113
- e.description && /* @__PURE__ */ c("p", {
113
+ e.description && /* @__PURE__ */ l("p", {
114
114
  className: "text-xs text-text-muted",
115
115
  children: e.description
116
116
  }),
117
- /* @__PURE__ */ l("select", {
117
+ /* @__PURE__ */ u("select", {
118
118
  id: `${y}-sink-${t}`,
119
119
  value: m[e.slot] ?? "",
120
120
  disabled: v || L || !S || !T,
121
121
  style: B,
122
122
  onChange: (t) => h(e.slot, t.target.value),
123
- children: [/* @__PURE__ */ c("option", {
123
+ children: [/* @__PURE__ */ l("option", {
124
124
  value: "",
125
125
  children: b("bigconsole.dashboards.templateSetup.connectLater", "Connect later")
126
- }), z.map((e) => /* @__PURE__ */ c("option", {
126
+ }), z.map((e) => /* @__PURE__ */ l("option", {
127
127
  value: e.id,
128
128
  children: e.name || e.key
129
129
  }, e.id))]
130
130
  }),
131
- e.expectedFields.length > 0 && /* @__PURE__ */ c("p", {
131
+ e.expectedFields.length > 0 && /* @__PURE__ */ l("p", {
132
132
  className: "text-xs text-text-muted",
133
133
  children: b("bigconsole.dashboards.templateSetup.expectedFields", "Expected fields: {fields}", { fields: e.expectedFields.map((e) => e.name).join(", ") })
134
134
  }),
135
- e.widgetTitles.length > 0 && /* @__PURE__ */ c("p", {
135
+ e.widgetTitles.length > 0 && /* @__PURE__ */ l("p", {
136
136
  className: "text-xs text-text-muted",
137
137
  children: b("bigconsole.dashboards.templateSetup.usedBy", "Used by: {widgets}", { widgets: e.widgetTitles.join(", ") })
138
138
  })
139
139
  ]
140
140
  }, e.slot)),
141
- I?.data?.listDataSinks.pageInfo.hasNextPage && /* @__PURE__ */ c("button", {
141
+ I?.data?.listDataSinks.pageInfo.hasNextPage && /* @__PURE__ */ l("button", {
142
142
  type: "button",
143
143
  disabled: v || L,
144
144
  onClick: () => M({
@@ -147,46 +147,46 @@ function p({ content: p, bindings: m, onBindingChange: h, inputValues: g, onInpu
147
147
  }),
148
148
  children: b("bigconsole.dashboards.templateSetup.loadMore", "Load more sources")
149
149
  })
150
- ] }), p.requiredInputs.map((e, t) => /* @__PURE__ */ l("div", { children: [
151
- /* @__PURE__ */ l("label", {
150
+ ] }), p.requiredInputs.map((e, t) => /* @__PURE__ */ u("div", { children: [
151
+ /* @__PURE__ */ u("label", {
152
152
  htmlFor: `${y}-input-${t}`,
153
153
  className: "text-sm font-medium",
154
154
  children: [e.label, e.required ? " *" : ""]
155
155
  }),
156
- e.type === "boolean" ? /* @__PURE__ */ l("select", {
156
+ e.type === "boolean" ? /* @__PURE__ */ u("select", {
157
157
  id: `${y}-input-${t}`,
158
158
  value: typeof g[e.name] == "boolean" ? String(g[e.name]) : "",
159
159
  style: B,
160
160
  disabled: v,
161
161
  onChange: (t) => _(e.name, t.target.value === "" ? void 0 : t.target.value === "true"),
162
162
  children: [
163
- /* @__PURE__ */ c("option", {
163
+ /* @__PURE__ */ l("option", {
164
164
  value: "",
165
165
  children: b("bigconsole.dashboards.templateSetup.chooseValue", "Choose a value")
166
166
  }),
167
- /* @__PURE__ */ c("option", {
167
+ /* @__PURE__ */ l("option", {
168
168
  value: "true",
169
169
  children: b("bigconsole.dashboards.templateSetup.true", "True")
170
170
  }),
171
- /* @__PURE__ */ c("option", {
171
+ /* @__PURE__ */ l("option", {
172
172
  value: "false",
173
173
  children: b("bigconsole.dashboards.templateSetup.false", "False")
174
174
  })
175
175
  ]
176
- }) : e.type === "select" ? /* @__PURE__ */ l("select", {
176
+ }) : e.type === "select" ? /* @__PURE__ */ u("select", {
177
177
  id: `${y}-input-${t}`,
178
178
  value: typeof g[e.name] == "string" ? String(g[e.name]) : "",
179
179
  style: B,
180
180
  disabled: v,
181
181
  onChange: (t) => _(e.name, t.target.value),
182
- children: [/* @__PURE__ */ c("option", {
182
+ children: [/* @__PURE__ */ l("option", {
183
183
  value: "",
184
184
  children: b("bigconsole.dashboards.templateSetup.chooseValue", "Choose a value")
185
- }), e.options?.map((e) => /* @__PURE__ */ c("option", {
185
+ }), e.options?.map((e) => /* @__PURE__ */ l("option", {
186
186
  value: e.value,
187
187
  children: e.label
188
188
  }, e.value))]
189
- }) : /* @__PURE__ */ c(o, {
189
+ }) : /* @__PURE__ */ l(o, {
190
190
  id: `${y}-input-${t}`,
191
191
  type: e.type === "secret" ? "password" : e.type === "number" ? "number" : "text",
192
192
  step: e.type === "number" ? "any" : void 0,
@@ -195,7 +195,7 @@ function p({ content: p, bindings: m, onBindingChange: h, inputValues: g, onInpu
195
195
  disabled: v,
196
196
  onChange: (t) => _(e.name, e.type === "number" ? t.target.value === "" ? void 0 : Number(t.target.value) : t.target.value)
197
197
  }),
198
- e.helpText && /* @__PURE__ */ c("p", {
198
+ e.helpText && /* @__PURE__ */ l("p", {
199
199
  className: "text-xs text-text-muted",
200
200
  children: e.helpText
201
201
  })
@@ -1,44 +1,44 @@
1
- import { jsx as e, jsxs as t } from "react/jsx-runtime";
2
- import { useI18n as n } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
1
+ import { useI18n as e } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
2
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
3
3
  //#region src/bigconsole/components/dashboard/TemplateLayoutPreview.tsx
4
4
  function r(e) {
5
5
  return typeof e == "object" && !!e && !Array.isArray(e);
6
6
  }
7
7
  function i({ content: i }) {
8
- let { t: a } = n();
9
- return !r(i.definition) || !Array.isArray(i.definition.pages) ? null : /* @__PURE__ */ t("section", {
8
+ let { t: a } = e();
9
+ return !r(i.definition) || !Array.isArray(i.definition.pages) ? null : /* @__PURE__ */ n("section", {
10
10
  "aria-label": a("bigconsole.dashboards.templatePreview.label", "Template layout preview"),
11
11
  className: "mb-form-gap space-y-control-gap",
12
12
  children: [
13
- /* @__PURE__ */ e("h3", {
13
+ /* @__PURE__ */ t("h3", {
14
14
  className: "text-sm font-medium",
15
15
  children: a("bigconsole.dashboards.templatePreview.title", "Layout preview")
16
16
  }),
17
- i.definition.pages.filter(r).map((n, i) => /* @__PURE__ */ t("div", { children: [/* @__PURE__ */ e("p", {
17
+ i.definition.pages.filter(r).map((e, i) => /* @__PURE__ */ n("div", { children: [/* @__PURE__ */ t("p", {
18
18
  className: "text-xs text-text-muted",
19
- children: typeof n.name == "string" ? n.name : a("bigconsole.dashboards.templatePreview.page", "Page {number}", { number: i + 1 })
20
- }), /* @__PURE__ */ e("div", {
19
+ children: typeof e.name == "string" ? e.name : a("bigconsole.dashboards.templatePreview.page", "Page {number}", { number: i + 1 })
20
+ }), /* @__PURE__ */ t("div", {
21
21
  style: {
22
22
  display: "grid",
23
23
  gridTemplateColumns: "repeat(12, minmax(0, 1fr))",
24
24
  gap: "var(--space-controlGap)"
25
25
  },
26
- children: Array.isArray(n.widgets) && n.widgets.filter(r).map((n, i) => {
27
- let o = r(n.config) ? n.config : {}, s = typeof o.chartType == "string" ? a("bigconsole.dashboards.templatePreview.chartType", "{type} chart", { type: o.chartType }) : typeof n.type == "string" ? n.type.toLowerCase().replaceAll("_", " ") : a("bigconsole.dashboards.templatePreview.widgetType", "Widget"), c = r(n.position) ? n.position : {};
28
- return /* @__PURE__ */ t("div", {
26
+ children: Array.isArray(e.widgets) && e.widgets.filter(r).map((e, i) => {
27
+ let o = r(e.config) ? e.config : {}, s = typeof o.chartType == "string" ? a("bigconsole.dashboards.templatePreview.chartType", "{type} chart", { type: o.chartType }) : typeof e.type == "string" ? e.type.toLowerCase().replaceAll("_", " ") : a("bigconsole.dashboards.templatePreview.widgetType", "Widget"), c = r(e.position) ? e.position : {};
28
+ return /* @__PURE__ */ n("div", {
29
29
  className: "rounded-card border border-border-default bg-bg-sunken p-3",
30
30
  style: { gridColumn: `span ${typeof c.width == "number" ? Math.min(12, Math.max(1, Math.round(c.width))) : 6}` },
31
- children: [/* @__PURE__ */ e("p", {
31
+ children: [/* @__PURE__ */ t("p", {
32
32
  className: "truncate text-xs font-medium",
33
- children: typeof n.title == "string" ? n.title : a("bigconsole.dashboards.templatePreview.widget", "Widget {number}", { number: i + 1 })
34
- }), /* @__PURE__ */ e("p", {
33
+ children: typeof e.title == "string" ? e.title : a("bigconsole.dashboards.templatePreview.widget", "Widget {number}", { number: i + 1 })
34
+ }), /* @__PURE__ */ t("p", {
35
35
  className: "truncate text-xs text-text-muted",
36
36
  children: s
37
37
  })]
38
38
  }, i);
39
39
  })
40
40
  })] }, i)),
41
- /* @__PURE__ */ e("p", {
41
+ /* @__PURE__ */ t("p", {
42
42
  className: "text-xs text-text-muted",
43
43
  children: a("bigconsole.dashboards.templatePreview.help", "Data appears after you connect a source. The dashboard uses these saved widgets and layouts.")
44
44
  })
@@ -1,4 +1,4 @@
1
1
  import "../../../hooks/index.js";
2
2
  import "react";
3
- import "react/jsx-runtime";
4
3
  import "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
4
+ import "react/jsx-runtime";