@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.
- package/dist/bigconsole/BigConsoleRoutes.d.ts.map +1 -1
- package/dist/bigconsole/BigConsoleRoutes.js +136 -127
- package/dist/bigconsole/BigConsoleRoutes.js.map +1 -1
- package/dist/bigconsole/assistant/assistantProduct.d.ts.map +1 -1
- package/dist/bigconsole/assistant/assistantProduct.js +3 -1
- package/dist/bigconsole/assistant/assistantProduct.js.map +1 -1
- package/dist/bigconsole/components/builder/inspector/DataBindingSection.js +31 -31
- package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js +44 -44
- package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/DashboardCanvas.js +36 -36
- package/dist/bigconsole/components/dashboard/DashboardCanvas.js.map +1 -1
- package/dist/bigconsole/components/dashboard/DashboardToolbar.js +59 -59
- package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js +15 -15
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterChip.js +30 -30
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js +41 -41
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js +34 -34
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js +34 -34
- package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js +110 -110
- package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/PublishToStoreDialog.js +21 -21
- package/dist/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.js +46 -46
- package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js +91 -91
- package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js.map +1 -1
- package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js +101 -101
- package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/TemplateInstallOptions.js +31 -31
- package/dist/bigconsole/components/dashboard/TemplateLayoutPreview.js +15 -15
- package/dist/bigconsole/components/dashboard/TemplatePicker/TemplatePicker.js +1 -1
- package/dist/bigconsole/components/dashboard/WidgetPalette.js +46 -46
- package/dist/bigconsole/components/datasink/AlertExecutionHistory.js +37 -37
- package/dist/bigconsole/components/datasink/AlertRuleEditor.js +66 -66
- package/dist/bigconsole/components/datasink/CacheTTLSelector.js +35 -35
- package/dist/bigconsole/components/datasink/DataSinkCard.js +29 -29
- package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js +18 -18
- package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js +20 -20
- package/dist/bigconsole/components/datasink/ImportDataGuideDialog.js +47 -47
- package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js +91 -91
- package/dist/bigconsole/components/datasink/RefreshTypeSelector.js +35 -35
- package/dist/bigconsole/components/parser/DataSinkSelector.js +40 -40
- package/dist/bigconsole/components/parser/ImportParserDialog.js +120 -120
- package/dist/bigconsole/components/parser/ImportParserDialog.js.map +1 -1
- package/dist/bigconsole/components/parser/ParserSelector.js +51 -51
- package/dist/bigconsole/components/pipeline/PipelineScopePicker.js +10 -10
- package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js +27 -27
- package/dist/bigconsole/components/preview/AiPreviewPanel.js +30 -30
- package/dist/bigconsole/components/widgets/ActionConfigDialog.js +4 -4
- package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js +93 -93
- package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/PropertiesPanel.d.ts.map +1 -1
- package/dist/bigconsole/components/widgets/PropertiesPanel.js +280 -273
- package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js +4 -4
- package/dist/bigconsole/components/widgets/chart/ChartConfig.js +48 -48
- package/dist/bigconsole/components/widgets/comments/WidgetComments.js +46 -46
- package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js +61 -61
- package/dist/bigconsole/components/widgets/form/FormWidget.js +36 -36
- package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js +42 -42
- package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js +25 -25
- package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +4 -4
- package/dist/bigconsole/components/widgets/list/ListConfig.js +30 -30
- package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js +38 -38
- package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js +9 -9
- package/dist/bigconsole/components/widgets/metric-card/TrendIndicator.js +9 -9
- package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js +49 -49
- package/dist/bigconsole/components/widgets/progress/ProgressConfig.js +39 -39
- package/dist/bigconsole/components/widgets/table/TableConfig.js +73 -73
- package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js +64 -64
- package/dist/bigconsole/components/workflow/WorkflowOpenGuard.js +15 -15
- package/dist/bigconsole/components/workflow/WorkflowSinkLinkForm.js +15 -15
- package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js +9 -9
- package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js +67 -67
- package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js.map +1 -1
- package/dist/bigconsole/hooks/useDashboardLayoutBaseline.d.ts +15 -0
- package/dist/bigconsole/hooks/useDashboardLayoutBaseline.d.ts.map +1 -0
- package/dist/bigconsole/hooks/useDashboardLayoutBaseline.js +34 -0
- package/dist/bigconsole/hooks/useDashboardLayoutBaseline.js.map +1 -0
- package/dist/bigconsole/hooks/useDrilldown.js +3 -3
- package/dist/bigconsole/hooks/useGlobalFilters.js +3 -3
- package/dist/bigconsole/pages/AdminPage.js +130 -130
- package/dist/bigconsole/pages/DashboardBuilderPage.d.ts.map +1 -1
- package/dist/bigconsole/pages/DashboardBuilderPage.js +72 -60
- package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/DashboardViewPage.js +1 -1
- package/dist/bigconsole/pages/DataSinkAlertsPage.d.ts.map +1 -1
- package/dist/bigconsole/pages/DataSinkAlertsPage.js +30 -23
- package/dist/bigconsole/pages/DataSinkAlertsPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkBuilderPage.d.ts.map +1 -1
- package/dist/bigconsole/pages/DataSinkBuilderPage.js +272 -263
- package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkViewPage.js +1 -1
- package/dist/bigconsole/pages/DataSinksPage.js +1 -1
- package/dist/bigconsole/pages/DataSourcesPage.js +5 -5
- package/dist/bigconsole/pages/InsightsPage.js +181 -181
- package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
- package/dist/bigconsole/pages/OverviewPage.js +47 -47
- package/dist/bigconsole/pages/OverviewPage.js.map +1 -1
- package/dist/bigconsole/pages/ParserBuilderPage.d.ts.map +1 -1
- package/dist/bigconsole/pages/ParserBuilderPage.js +227 -211
- package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/ParserViewPage.js +97 -97
- package/dist/bigconsole/pages/PipelineBuilderPage.d.ts.map +1 -1
- package/dist/bigconsole/pages/PipelineBuilderPage.js +256 -214
- package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelineViewPage.js +146 -146
- package/dist/bigconsole/pages/PipelinesPage.js +88 -88
- package/dist/bigconsole/pages/PipelinesPage.js.map +1 -1
- package/dist/bigconsole/pages/SettingsPage.d.ts.map +1 -1
- package/dist/bigconsole/pages/SettingsPage.js +179 -173
- package/dist/bigconsole/pages/SettingsPage.js.map +1 -1
- package/dist/bigconsole/pages/WidgetDemoPage.js +42 -42
- package/dist/bigconsole/pages/WorkflowViewPage.js +1 -1
- package/dist/bigconsole/pages/WorkflowsPage.js +141 -141
- package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
- package/dist/bigconsole/providers/BigConsoleQuotaProvider.js +12 -12
- package/dist/bigconsole/renderers/adapters/AdaptiveCardRenderer.js +34 -34
- package/dist/bigconsole/renderers/adapters/BlockKitRenderer.js +79 -79
- package/dist/bigconsole/renderers/adapters/CustomRenderer.js +46 -46
- package/dist/bigconsole/store/widgetStore.d.ts +12 -0
- package/dist/bigconsole/store/widgetStore.d.ts.map +1 -1
- package/dist/bigconsole/store/widgetStore.js +3 -1
- package/dist/bigconsole/store/widgetStore.js.map +1 -1
- package/dist/bigconsole/utils/formDirty.d.ts +83 -0
- package/dist/bigconsole/utils/formDirty.d.ts.map +1 -0
- package/dist/bigconsole/utils/formDirty.js +23 -0
- package/dist/bigconsole/utils/formDirty.js.map +1 -0
- package/dist/bigconsole/utils/layoutBaseline.d.ts +131 -0
- package/dist/bigconsole/utils/layoutBaseline.d.ts.map +1 -0
- package/dist/bigconsole/utils/layoutBaseline.js +98 -0
- package/dist/bigconsole/utils/layoutBaseline.js.map +1 -0
- package/dist/translations/en.d.ts.map +1 -1
- 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'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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"}
|
|
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'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 {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
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 } =
|
|
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__ */
|
|
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__ */
|
|
84
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
105
|
+
p.requiredDataSinks.map((e, t) => /* @__PURE__ */ u("div", {
|
|
106
106
|
className: "mt-form-gap",
|
|
107
107
|
children: [
|
|
108
|
-
/* @__PURE__ */
|
|
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__ */
|
|
113
|
+
e.description && /* @__PURE__ */ l("p", {
|
|
114
114
|
className: "text-xs text-text-muted",
|
|
115
115
|
children: e.description
|
|
116
116
|
}),
|
|
117
|
-
/* @__PURE__ */
|
|
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__ */
|
|
123
|
+
children: [/* @__PURE__ */ l("option", {
|
|
124
124
|
value: "",
|
|
125
125
|
children: b("bigconsole.dashboards.templateSetup.connectLater", "Connect later")
|
|
126
|
-
}), z.map((e) => /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
151
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
163
|
+
/* @__PURE__ */ l("option", {
|
|
164
164
|
value: "",
|
|
165
165
|
children: b("bigconsole.dashboards.templateSetup.chooseValue", "Choose a value")
|
|
166
166
|
}),
|
|
167
|
-
/* @__PURE__ */
|
|
167
|
+
/* @__PURE__ */ l("option", {
|
|
168
168
|
value: "true",
|
|
169
169
|
children: b("bigconsole.dashboards.templateSetup.true", "True")
|
|
170
170
|
}),
|
|
171
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
185
|
+
}), e.options?.map((e) => /* @__PURE__ */ l("option", {
|
|
186
186
|
value: e.value,
|
|
187
187
|
children: e.label
|
|
188
188
|
}, e.value))]
|
|
189
|
-
}) : /* @__PURE__ */
|
|
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__ */
|
|
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 {
|
|
2
|
-
import {
|
|
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 } =
|
|
9
|
-
return !r(i.definition) || !Array.isArray(i.definition.pages) ? null : /* @__PURE__ */
|
|
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__ */
|
|
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((
|
|
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
|
|
20
|
-
}), /* @__PURE__ */
|
|
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(
|
|
27
|
-
let o = r(
|
|
28
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
31
|
+
children: [/* @__PURE__ */ t("p", {
|
|
32
32
|
className: "truncate text-xs font-medium",
|
|
33
|
-
children: typeof
|
|
34
|
-
}), /* @__PURE__ */
|
|
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__ */
|
|
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
|
})
|