@burdenoff/microfe-bigconsole 2026.805.2 → 2026.805.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bigconsole/components/builder/inspector/DataBindingSection.js +109 -113
- package/dist/bigconsole/components/builder/inspector/DataBindingSection.js.map +1 -1
- package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js +115 -113
- package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/DashboardCanvas.js +71 -62
- package/dist/bigconsole/components/dashboard/DashboardCanvas.js.map +1 -1
- package/dist/bigconsole/components/dashboard/DashboardToolbar.js +90 -89
- package/dist/bigconsole/components/dashboard/DashboardToolbar.js.map +1 -1
- package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js +56 -54
- package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js.map +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterChip.js +126 -125
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterChip.js.map +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js +151 -150
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js.map +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js +77 -76
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js.map +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js +97 -96
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js.map +1 -1
- package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js +172 -191
- package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/PublishToStoreDialog.js +75 -83
- package/dist/bigconsole/components/dashboard/PublishToStoreDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.js +151 -154
- package/dist/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.js.map +1 -1
- package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js +181 -190
- package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js.map +1 -1
- package/dist/bigconsole/components/dashboard/TemplatePicker/TemplatePicker.js +1 -0
- package/dist/bigconsole/components/dashboard/WidgetPalette.js +110 -108
- package/dist/bigconsole/components/dashboard/WidgetPalette.js.map +1 -1
- package/dist/bigconsole/components/datasink/CacheTTLSelector.js +102 -103
- package/dist/bigconsole/components/datasink/CacheTTLSelector.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js +36 -41
- package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js +38 -37
- package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js.map +1 -1
- package/dist/bigconsole/components/datasink/ImportDataGuideDialog.js +113 -117
- package/dist/bigconsole/components/datasink/ImportDataGuideDialog.js.map +1 -1
- package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js +182 -197
- package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js.map +1 -1
- package/dist/bigconsole/components/datasink/RefreshTypeSelector.js +166 -168
- package/dist/bigconsole/components/datasink/RefreshTypeSelector.js.map +1 -1
- package/dist/bigconsole/components/parser/DataSinkSelector.js +87 -86
- package/dist/bigconsole/components/parser/DataSinkSelector.js.map +1 -1
- package/dist/bigconsole/components/parser/ImportParserDialog.js +196 -211
- package/dist/bigconsole/components/parser/ImportParserDialog.js.map +1 -1
- package/dist/bigconsole/components/parser/ParserSelector.js +130 -128
- package/dist/bigconsole/components/parser/ParserSelector.js.map +1 -1
- package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js +66 -63
- package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js.map +1 -1
- package/dist/bigconsole/components/preview/AiPreviewPanel.js +95 -91
- package/dist/bigconsole/components/preview/AiPreviewPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/ActionConfigDialog.js +222 -215
- package/dist/bigconsole/components/widgets/ActionConfigDialog.js.map +1 -1
- package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js +149 -145
- package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/PropertiesPanel.js +504 -470
- package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js +44 -47
- package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/chart/ChartConfig.js +143 -142
- package/dist/bigconsole/components/widgets/chart/ChartConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/comments/WidgetComments.js +101 -88
- package/dist/bigconsole/components/widgets/comments/WidgetComments.js.map +1 -1
- package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js +135 -134
- package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js.map +1 -1
- package/dist/bigconsole/components/widgets/form/FormWidget.js +167 -159
- package/dist/bigconsole/components/widgets/form/FormWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js +69 -68
- package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js +64 -72
- package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +60 -59
- package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/list/ListConfig.js +57 -56
- package/dist/bigconsole/components/widgets/list/ListConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js +70 -69
- package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js +35 -34
- package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/TrendIndicator.js +20 -19
- package/dist/bigconsole/components/widgets/metric-card/TrendIndicator.js.map +1 -1
- package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js +178 -177
- package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/progress/ProgressConfig.js +76 -75
- package/dist/bigconsole/components/widgets/progress/ProgressConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/table/TableConfig.js +183 -168
- package/dist/bigconsole/components/widgets/table/TableConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js +187 -180
- package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js.map +1 -1
- package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js +40 -38
- package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js.map +1 -1
- package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js +150 -148
- package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js.map +1 -1
- package/dist/bigconsole/pages/DashboardBuilderPage.js +181 -176
- package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/DashboardViewPage.js +196 -192
- package/dist/bigconsole/pages/DashboardViewPage.js.map +1 -1
- package/dist/bigconsole/pages/DashboardsPage.js +223 -219
- package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
- package/dist/bigconsole/pages/DataParsersPage.js +167 -170
- package/dist/bigconsole/pages/DataParsersPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkBuilderPage.js +204 -189
- package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkViewPage.js +175 -169
- package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSourcesPage.js +8 -7
- package/dist/bigconsole/pages/DataSourcesPage.js.map +1 -1
- package/dist/bigconsole/pages/InsightsPage.js +238 -208
- package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
- package/dist/bigconsole/pages/ParserBuilderPage.js +464 -412
- package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/ParserViewPage.js +92 -90
- package/dist/bigconsole/pages/ParserViewPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelineBuilderPage.js +221 -194
- package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelineViewPage.js +181 -184
- package/dist/bigconsole/pages/PipelineViewPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelinesPage.js +128 -127
- package/dist/bigconsole/pages/PipelinesPage.js.map +1 -1
- package/dist/bigconsole/pages/SettingsPage.js +177 -172
- package/dist/bigconsole/pages/SettingsPage.js.map +1 -1
- package/dist/bigconsole/pages/WidgetDemoPage.js +121 -83
- package/dist/bigconsole/pages/WidgetDemoPage.js.map +1 -1
- package/dist/bigconsole/pages/WorkflowViewPage.js +199 -193
- package/dist/bigconsole/pages/WorkflowViewPage.js.map +1 -1
- package/dist/bigconsole/pages/WorkflowsPage.js +129 -128
- package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
- package/dist/bigconsole/renderers/adapters/AdaptiveCardRenderer.js +111 -109
- package/dist/bigconsole/renderers/adapters/AdaptiveCardRenderer.js.map +1 -1
- package/dist/bigconsole/renderers/adapters/BlockKitRenderer.js +127 -126
- package/dist/bigconsole/renderers/adapters/BlockKitRenderer.js.map +1 -1
- package/dist/bigconsole/renderers/adapters/CustomRenderer.js +103 -103
- package/dist/bigconsole/renderers/adapters/CustomRenderer.js.map +1 -1
- package/package.json +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmbedTab.js","names":[],"sources":["../../../../../src/bigconsole/components/dashboard/ShareDialog/EmbedTab.tsx"],"sourcesContent":["/**\n * EmbedTab — \"Publish to web\" section of the dashboard Share dialog.\n *\n * Owner-facing UI to publish a dashboard as an anonymous-link embed serving LIVE\n * data, manage the allowed parent domains, copy the iframe snippet, rotate the\n * link key, and unpublish. Backed by {@link useDashboardEmbedPolicy}; all\n * mutations are gateway-enforced by `@rbac(manage_embed)` (owner-only).\n *\n * Self-contained (inline styles driven by the dialog's `colors`) so it slots into\n * the existing hand-styled ShareDialog without a broader refactor.\n */\n\nimport React, { useEffect, useMemo, useRef, useState } from 'react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useDashboardEmbedPolicy, themeChoiceFromPolicy } from '../../../hooks/useDashboardEmbedPolicy';\nimport { BIGCONSOLE_PERMISSIONS } from '../../../../constants/permissions';\n\ninterface DialogColors {\n bgPrimary: string;\n bgSecondary: string;\n bgTertiary: string;\n textPrimary: string;\n textSecondary: string;\n textTertiary: string;\n borderDefault: string;\n actionPrimaryBg: string;\n actionPrimaryBgHover: string;\n statusSuccessBg: string;\n statusErrorText: string;\n}\n\nexport interface EmbedTabProps {\n dashboardId: string;\n colors: DialogColors;\n}\n\n/** Embed color-mode baked into the iframe URL (BOFF-5734). */\ntype EmbedSnippetTheme = 'light' | 'dark' | 'auto';\n\nconst THEME_OPTIONS: ReadonlyArray<{ value: EmbedSnippetTheme; label: string }> = [\n { value: 'light', label: 'Light' },\n { value: 'dark', label: 'Dark' },\n { value: 'auto', label: 'Auto (match viewer)' },\n];\n\n/**\n * Bake the chosen color mode into an iframe snippet by adding `?theme=` to its\n * `src` URL. `light` is the default and is left implicit so existing/plain\n * snippets stay unchanged. The secret `#key=` fragment is preserved untouched.\n *\n * Inserted via string splicing (before the fragment) rather than `URL`/\n * `URLSearchParams`, which re-serialize ALL params and could subtly re-encode\n * existing ones (e.g. `%20` → `+`). `theme` is a fixed enum, so no encoding is\n * needed; every other part of the URL is passed through byte-for-byte.\n */\nexport function withThemeInSnippet(snippet: string, theme: EmbedSnippetTheme): string {\n if (theme === 'light') return snippet;\n // Require whitespace before `src` so we match the real attribute, never a\n // substring like `data-src`/`srcdoc` (the snippet is backend-generated with\n // each attribute on its own indented line).\n return snippet.replace(/(?<=\\s)src=\"([^\"]*)\"/, (_match, url: string) => {\n const hashIdx = url.indexOf('#');\n const base = hashIdx === -1 ? url : url.slice(0, hashIdx);\n const fragment = hashIdx === -1 ? '' : url.slice(hashIdx);\n const sep = base.includes('?') ? '&' : '?';\n return `src=\"${base}${sep}theme=${theme}${fragment}\"`;\n });\n}\n\n/** Validate an exact https origin (matches the backend allowlist rules). */\nfunction normalizeOrigin(raw: string): string | null {\n const trimmed = raw.trim();\n if (!trimmed) return null;\n try {\n const url = new URL(trimmed);\n if (url.protocol !== 'https:') return null;\n if ((url.pathname !== '' && url.pathname !== '/') || url.search || url.hash) return null;\n return url.origin;\n } catch {\n return null;\n }\n}\n\nexport function EmbedTab({ dashboardId, colors }: EmbedTabProps) {\n const {\n policy,\n secret,\n loading,\n error,\n fetchPolicy,\n publishToWeb,\n applyPresentation,\n setAllowedOrigins,\n rotateKey,\n unpublish,\n } = useDashboardEmbedPolicy();\n\n // All embed policy mutations (publish, rotate, revoke, set-origins, apply\n // presentation) are gateway-enforced by `@rbac(manage_embed)`. Gate the UI on\n // the same permission so the controls degrade gracefully instead of erroring.\n const { hasPermission } = usePermissions();\n const canManageEmbed = hasPermission(BIGCONSOLE_PERMISSIONS.DASHBOARD_MANAGE_EMBED);\n\n const [domainInput, setDomainInput] = useState('');\n const [pendingDomains, setPendingDomains] = useState<string[]>([]);\n const [attested, setAttested] = useState(false);\n const [copied, setCopied] = useState(false);\n // Presentation options (BOFF-5735). Defaults mirror the backend column defaults\n // so a fresh publish captures a sensible look without extra clicks.\n const [theme, setTheme] = useState<EmbedSnippetTheme>('light');\n const [showTitle, setShowTitle] = useState(false);\n const [showBranding, setShowBranding] = useState(true);\n const [presentationSaved, setPresentationSaved] = useState(false);\n const [localError, setLocalError] = useState<string | null>(null);\n // Only seed the presentation controls once per policy identity — NOT on every\n // `policy` object change. Otherwise an unrelated mutation (e.g. adding a domain\n // via setAllowedOrigins) would return a fresh policy object and clobber the\n // owner's in-progress, not-yet-applied theme/title/branding edits.\n const syncedPolicyIdRef = useRef<string | null>(null);\n const savedTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (dashboardId) fetchPolicy(dashboardId);\n }, [dashboardId, fetchPolicy]);\n\n // Reflect the persisted presentation the first time each policy loads.\n useEffect(() => {\n if (!policy || syncedPolicyIdRef.current === policy.id) return;\n syncedPolicyIdRef.current = policy.id;\n setTheme(themeChoiceFromPolicy(policy.presentationTheme));\n setShowTitle(policy.showDashboardTitle);\n setShowBranding(policy.showBrandingFooter);\n }, [policy]);\n\n // Clear any pending \"Updated ✓\" timer on unmount.\n useEffect(\n () => () => {\n if (savedTimerRef.current) clearTimeout(savedTimerRef.current);\n },\n []\n );\n\n const isPublished = policy?.status === 'ACTIVE';\n const domains = isPublished ? (policy?.allowedParentOrigins ?? []) : pendingDomains;\n\n // The copyable iframe snippet: from the one-time secret if present (fresh\n // publish/rotate), else reconstructed from the locator for an already-published\n // policy (the fragment key is only available in the one-time secret).\n const iframeSnippet = useMemo(() => {\n if (secret?.iframeSnippet) return withThemeInSnippet(secret.iframeSnippet, theme);\n return null;\n }, [secret, theme]);\n\n const addDomain = () => {\n setLocalError(null);\n const origin = normalizeOrigin(domainInput);\n if (!origin) {\n setLocalError('Enter a valid https origin, e.g. https://example.com');\n return;\n }\n if (domains.includes(origin)) {\n setDomainInput('');\n return;\n }\n if (isPublished && policy) {\n void setAllowedOrigins(policy.id, [...domains, origin]);\n } else {\n setPendingDomains((prev) => [...prev, origin]);\n }\n setDomainInput('');\n };\n\n const removeDomain = (origin: string) => {\n if (isPublished && policy) {\n void setAllowedOrigins(\n policy.id,\n domains.filter((d) => d !== origin)\n );\n } else {\n setPendingDomains((prev) => prev.filter((d) => d !== origin));\n }\n };\n\n const handlePublish = async () => {\n setLocalError(null);\n if (pendingDomains.length === 0) {\n setLocalError('Add at least one allowed website domain before publishing.');\n return;\n }\n if (!attested) {\n setLocalError('Please confirm this dashboard is safe to be public.');\n return;\n }\n await publishToWeb(dashboardId, pendingDomains, true, { theme, showTitle, showBranding });\n };\n\n const handleApplyPresentation = async () => {\n if (!policy) return;\n setLocalError(null);\n const updated = await applyPresentation(policy.id, { theme, showTitle, showBranding });\n if (updated) {\n setPresentationSaved(true);\n // Clear any in-flight timer so rapid re-clicks don't hide the confirmation early.\n if (savedTimerRef.current) clearTimeout(savedTimerRef.current);\n savedTimerRef.current = setTimeout(() => setPresentationSaved(false), 1500);\n }\n };\n\n const handleCopy = async (text: string) => {\n try {\n await navigator.clipboard.writeText(text);\n setCopied(true);\n setTimeout(() => setCopied(false), 1500);\n } catch {\n setLocalError('Could not copy — select and copy manually.');\n }\n };\n\n const primaryBtn: React.CSSProperties = {\n padding: '8px 14px',\n borderRadius: '8px',\n border: 'none',\n background: colors.actionPrimaryBg,\n color: '#fff',\n fontSize: '13px',\n fontWeight: 600,\n cursor: 'pointer',\n };\n const ghostBtn: React.CSSProperties = {\n padding: '8px 14px',\n borderRadius: '8px',\n border: `1px solid ${colors.borderDefault}`,\n background: 'transparent',\n color: colors.textPrimary,\n fontSize: '13px',\n cursor: 'pointer',\n };\n const inputStyle: React.CSSProperties = {\n flex: 1,\n padding: '8px 10px',\n borderRadius: '8px',\n border: `1px solid ${colors.borderDefault}`,\n background: colors.bgSecondary,\n color: colors.textPrimary,\n fontSize: '13px',\n };\n const selectStyle: React.CSSProperties = {\n padding: '4px 8px',\n borderRadius: '6px',\n border: `1px solid ${colors.borderDefault}`,\n background: colors.bgSecondary,\n color: colors.textPrimary,\n fontSize: '12px',\n cursor: 'pointer',\n };\n const toggleRow: React.CSSProperties = {\n display: 'flex',\n gap: '8px',\n alignItems: 'flex-start',\n fontSize: '12px',\n color: colors.textSecondary,\n };\n\n // Presentation controls (BOFF-5735) — shared by the pre-publish and published\n // states. Local state drives both the persisted policy and the snippet `?theme=`.\n const presentationControls = (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>\n <label style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '8px' }}>\n <span style={{ fontSize: '12px', color: colors.textSecondary }}>Theme</span>\n <select\n value={theme}\n onChange={(e) => {\n // The options are fixed, but narrow instead of casting so an\n // unexpected value can never slip into state.\n const value = e.target.value;\n if (value === 'light' || value === 'dark' || value === 'auto') {\n setTheme(value);\n }\n }}\n style={selectStyle}\n >\n {THEME_OPTIONS.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </label>\n <label style={toggleRow}>\n <input type=\"checkbox\" checked={showTitle} onChange={(e) => setShowTitle(e.target.checked)} />\n <span>Show the dashboard title as a header</span>\n </label>\n <label style={toggleRow}>\n <input type=\"checkbox\" checked={showBranding} onChange={(e) => setShowBranding(e.target.checked)} />\n <span>Show a subtle “Powered by BigConsole” footer</span>\n </label>\n </div>\n );\n\n return (\n <div style={{ padding: '20px 24px' }}>\n {/* Status banner */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '12px 14px',\n borderRadius: '10px',\n background: colors.bgSecondary,\n marginBottom: '16px',\n }}\n >\n <div>\n <div style={{ fontSize: '14px', fontWeight: 600, color: colors.textPrimary }}>Publish to the web</div>\n <div style={{ fontSize: '12px', color: colors.textSecondary, marginTop: '2px' }}>\n {isPublished\n ? 'This dashboard is live. Anyone with the link on an allowed website sees its live data.'\n : 'Embed this dashboard on your website. Viewers see live data — no login required.'}\n </div>\n </div>\n <span\n style={{\n fontSize: '11px',\n fontWeight: 700,\n padding: '3px 8px',\n borderRadius: '999px',\n color: '#fff',\n background: isPublished ? colors.statusSuccessBg : colors.textTertiary,\n }}\n >\n {isPublished ? 'PUBLISHED' : 'PRIVATE'}\n </span>\n </div>\n\n {/* Allowed domains */}\n <div style={{ marginBottom: '16px' }}>\n <div style={{ fontSize: '12px', fontWeight: 600, color: colors.textSecondary, marginBottom: '6px' }}>\n Allowed website domains\n </div>\n <div style={{ display: 'flex', gap: '8px', marginBottom: '8px' }}>\n <input\n style={inputStyle}\n placeholder=\"https://yoursite.com\"\n value={domainInput}\n onChange={(e) => setDomainInput(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') addDomain();\n }}\n />\n <button style={ghostBtn} onClick={addDomain} type=\"button\" disabled={!canManageEmbed}>\n Add\n </button>\n </div>\n {domains.length === 0 ? (\n <div style={{ fontSize: '12px', color: colors.textTertiary }}>\n No domains yet. Only listed https domains may frame this dashboard.\n </div>\n ) : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>\n {domains.map((d) => (\n <div\n key={d}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '6px 10px',\n borderRadius: '8px',\n background: colors.bgTertiary,\n }}\n >\n <span style={{ fontSize: '13px', color: colors.textPrimary }}>{d}</span>\n {canManageEmbed && (\n <button\n style={{ ...ghostBtn, padding: '2px 8px', color: colors.statusErrorText }}\n onClick={() => removeDomain(d)}\n type=\"button\"\n >\n Remove\n </button>\n )}\n </div>\n ))}\n </div>\n )}\n </div>\n\n {/* Presentation (unpublished — captured into the publish) */}\n {!isPublished && (\n <div style={{ marginBottom: '16px' }}>\n <div style={{ fontSize: '12px', fontWeight: 600, color: colors.textSecondary, marginBottom: '8px' }}>\n Presentation\n </div>\n {presentationControls}\n </div>\n )}\n\n {/* Publish CTA (unpublished) */}\n {!isPublished && (\n <div style={{ marginBottom: '8px' }}>\n <label style={{ display: 'flex', gap: '8px', alignItems: 'flex-start', marginBottom: '12px' }}>\n <input type=\"checkbox\" checked={attested} onChange={(e) => setAttested(e.target.checked)} />\n <span style={{ fontSize: '12px', color: colors.textSecondary }}>\n I understand this makes the dashboard's live data visible to anyone with the link, and I confirm it\n is safe to be public.\n </span>\n </label>\n <button style={primaryBtn} onClick={handlePublish} disabled={loading || !canManageEmbed} type=\"button\">\n {loading ? 'Publishing…' : 'Publish to web'}\n </button>\n </div>\n )}\n\n {/* Embed snippet + management (published) */}\n {isPublished && (\n <>\n {iframeSnippet ? (\n <div style={{ marginBottom: '16px' }}>\n <div style={{ marginBottom: '6px' }}>\n <span style={{ fontSize: '12px', fontWeight: 600, color: colors.textSecondary }}>Embed snippet</span>\n </div>\n <textarea\n readOnly\n value={iframeSnippet}\n style={{\n width: '100%',\n minHeight: '96px',\n padding: '10px',\n borderRadius: '8px',\n border: `1px solid ${colors.borderDefault}`,\n background: colors.bgSecondary,\n color: colors.textPrimary,\n fontFamily: 'monospace',\n fontSize: '12px',\n resize: 'vertical',\n }}\n />\n <button style={{ ...ghostBtn, marginTop: '8px' }} onClick={() => handleCopy(iframeSnippet)} type=\"button\">\n {copied ? 'Copied ✓' : 'Copy snippet'}\n </button>\n </div>\n ) : (\n <div\n style={{\n fontSize: '12px',\n color: colors.textSecondary,\n background: colors.bgSecondary,\n borderRadius: '8px',\n padding: '10px 12px',\n marginBottom: '16px',\n }}\n >\n The embed link is already active. For security the snippet (which contains the secret key) is only shown\n once at publish time — use <strong>Rotate link</strong> to generate a fresh snippet.\n </div>\n )}\n\n {/* Presentation (published — persisted + re-published to take effect) */}\n <div style={{ marginBottom: '16px' }}>\n <div style={{ fontSize: '12px', fontWeight: 600, color: colors.textSecondary, marginBottom: '8px' }}>\n Presentation\n </div>\n {presentationControls}\n <div style={{ display: 'flex', alignItems: 'center', gap: '10px', marginTop: '10px' }}>\n <button\n style={ghostBtn}\n onClick={handleApplyPresentation}\n disabled={loading || !canManageEmbed}\n type=\"button\"\n >\n {loading ? 'Applying…' : 'Apply changes'}\n </button>\n {presentationSaved && <span style={{ fontSize: '12px', color: colors.textTertiary }}>Updated ✓</span>}\n </div>\n <div style={{ fontSize: '11px', color: colors.textTertiary, marginTop: '6px' }}>\n Changes apply to live embeds within a few seconds — no re-publish needed, and the embed link stays the\n same.\n </div>\n </div>\n\n {/* Rotate/Unpublish are destructive management actions — hide entirely\n when the caller can't manage the embed. */}\n {canManageEmbed && (\n <div style={{ display: 'flex', gap: '8px' }}>\n <button style={ghostBtn} onClick={() => policy && rotateKey(policy.id)} disabled={loading} type=\"button\">\n Rotate link\n </button>\n <button\n style={{ ...ghostBtn, color: colors.statusErrorText, borderColor: colors.statusErrorText }}\n onClick={() => {\n if (\n policy &&\n window.confirm(\n 'Unpublish this dashboard? The embed will stop working immediately for anyone using the link.'\n )\n ) {\n void unpublish(policy.id);\n }\n }}\n disabled={loading}\n type=\"button\"\n >\n Unpublish\n </button>\n </div>\n )}\n </>\n )}\n\n {(localError || error) && (\n <div style={{ marginTop: '12px', fontSize: '12px', color: colors.statusErrorText }}>\n {localError ?? error?.message}\n </div>\n )}\n </div>\n );\n}\n\nexport default EmbedTab;\n"],"mappings":";;;;;;AAuCA,IAAM,IAA4E;CAChF;EAAE,OAAO;EAAS,OAAO;EAAS;CAClC;EAAE,OAAO;EAAQ,OAAO;EAAQ;CAChC;EAAE,OAAO;EAAQ,OAAO;EAAuB;CAChD;AAYD,SAAgB,GAAmB,GAAiB,GAAkC;AAKpF,QAJI,MAAU,UAAgB,IAIvB,EAAQ,QAAQ,yBAAyB,GAAQ,MAAgB;EACtE,IAAM,IAAU,EAAI,QAAQ,IAAI,EAC1B,IAAO,MAAY,KAAK,IAAM,EAAI,MAAM,GAAG,EAAQ,EACnD,IAAW,MAAY,KAAK,KAAK,EAAI,MAAM,EAAQ;AAEzD,SAAO,QAAQ,IADH,EAAK,SAAS,IAAI,GAAG,MAAM,IACb,QAAQ,IAAQ,EAAS;GACnD;;AAIJ,SAAS,GAAgB,GAA4B;CACnD,IAAM,IAAU,EAAI,MAAM;AAC1B,KAAI,CAAC,EAAS,QAAO;AACrB,KAAI;EACF,IAAM,IAAM,IAAI,IAAI,EAAQ;AAG5B,SAFI,EAAI,aAAa,YAChB,EAAI,aAAa,MAAM,EAAI,aAAa,OAAQ,EAAI,UAAU,EAAI,OAAa,OAC7E,EAAI;SACL;AACN,SAAO;;;AAIX,SAAgB,EAAS,EAAE,gBAAa,aAAyB;CAC/D,IAAM,EACJ,WACA,WACA,YACA,UACA,gBACA,iBACA,sBACA,sBACA,cACA,kBACE,GAAyB,EAKvB,EAAE,qBAAkB,GAAgB,EACpC,IAAiB,EAAc,EAAuB,uBAAuB,EAE7E,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,CAAC,GAAgB,KAAqB,EAAmB,EAAE,CAAC,EAC5D,CAAC,GAAU,KAAe,EAAS,GAAM,EACzC,CAAC,GAAQ,KAAa,EAAS,GAAM,EAGrC,CAAC,GAAO,KAAY,EAA4B,QAAQ,EACxD,CAAC,GAAW,KAAgB,EAAS,GAAM,EAC3C,CAAC,GAAc,KAAmB,EAAS,GAAK,EAChD,CAAC,IAAmB,KAAwB,EAAS,GAAM,EAC3D,CAAC,GAAY,KAAiB,EAAwB,KAAK,EAK3D,IAAoB,EAAsB,KAAK,EAC/C,IAAgB,EAA6C,KAAK;AAgBxE,CAdA,QAAgB;AACd,EAAI,KAAa,EAAY,EAAY;IACxC,CAAC,GAAa,EAAY,CAAC,EAG9B,QAAgB;AACV,GAAC,KAAU,EAAkB,YAAY,EAAO,OACpD,EAAkB,UAAU,EAAO,IACnC,EAAS,EAAsB,EAAO,kBAAkB,CAAC,EACzD,EAAa,EAAO,mBAAmB,EACvC,EAAgB,EAAO,mBAAmB;IACzC,CAAC,EAAO,CAAC,EAGZ,cACc;AACV,EAAI,EAAc,WAAS,aAAa,EAAc,QAAQ;IAEhE,EAAE,CACH;CAED,IAAM,IAAc,GAAQ,WAAW,UACjC,IAAU,IAAe,GAAQ,wBAAwB,EAAE,GAAI,GAK/D,IAAgB,QAChB,GAAQ,gBAAsB,GAAmB,EAAO,eAAe,EAAM,GAC1E,MACN,CAAC,GAAQ,EAAM,CAAC,EAEb,UAAkB;AACtB,IAAc,KAAK;EACnB,IAAM,IAAS,GAAgB,EAAY;AAC3C,MAAI,CAAC,GAAQ;AACX,KAAc,uDAAuD;AACrE;;AAEF,MAAI,EAAQ,SAAS,EAAO,EAAE;AAC5B,KAAe,GAAG;AAClB;;AAOF,EALI,KAAe,IACZ,EAAkB,EAAO,IAAI,CAAC,GAAG,GAAS,EAAO,CAAC,GAEvD,GAAmB,MAAS,CAAC,GAAG,GAAM,EAAO,CAAC,EAEhD,EAAe,GAAG;IAGd,KAAgB,MAAmB;AACvC,EAAI,KAAe,IACZ,EACH,EAAO,IACP,EAAQ,QAAQ,MAAM,MAAM,EAAO,CACpC,GAED,GAAmB,MAAS,EAAK,QAAQ,MAAM,MAAM,EAAO,CAAC;IAI3D,IAAgB,YAAY;AAEhC,MADA,EAAc,KAAK,EACf,EAAe,WAAW,GAAG;AAC/B,KAAc,6DAA6D;AAC3E;;AAEF,MAAI,CAAC,GAAU;AACb,KAAc,sDAAsD;AACpE;;AAEF,QAAM,EAAa,GAAa,GAAgB,IAAM;GAAE;GAAO;GAAW;GAAc,CAAC;IAGrF,KAA0B,YAAY;AACrC,QACL,EAAc,KAAK,EACH,MAAM,EAAkB,EAAO,IAAI;GAAE;GAAO;GAAW;GAAc,CAAC,KAEpF,EAAqB,GAAK,EAEtB,EAAc,WAAS,aAAa,EAAc,QAAQ,EAC9D,EAAc,UAAU,iBAAiB,EAAqB,GAAM,EAAE,KAAK;IAIzE,IAAa,OAAO,MAAiB;AACzC,MAAI;AAGF,GAFA,MAAM,UAAU,UAAU,UAAU,EAAK,EACzC,EAAU,GAAK,EACf,iBAAiB,EAAU,GAAM,EAAE,KAAK;UAClC;AACN,KAAc,6CAA6C;;IAIzD,KAAkC;EACtC,SAAS;EACT,cAAc;EACd,QAAQ;EACR,YAAY,EAAO;EACnB,OAAO;EACP,UAAU;EACV,YAAY;EACZ,QAAQ;EACT,EACK,IAAgC;EACpC,SAAS;EACT,cAAc;EACd,QAAQ,aAAa,EAAO;EAC5B,YAAY;EACZ,OAAO,EAAO;EACd,UAAU;EACV,QAAQ;EACT,EACK,KAAkC;EACtC,MAAM;EACN,SAAS;EACT,cAAc;EACd,QAAQ,aAAa,EAAO;EAC5B,YAAY,EAAO;EACnB,OAAO,EAAO;EACd,UAAU;EACX,EACK,KAAmC;EACvC,SAAS;EACT,cAAc;EACd,QAAQ,aAAa,EAAO;EAC5B,YAAY,EAAO;EACnB,OAAO,EAAO;EACd,UAAU;EACV,QAAQ;EACT,EACK,IAAiC;EACrC,SAAS;EACT,KAAK;EACL,YAAY;EACZ,UAAU;EACV,OAAO,EAAO;EACf,EAIK,IACJ,kBAAC,OAAD;EAAK,OAAO;GAAE,SAAS;GAAQ,eAAe;GAAU,KAAK;GAAQ;YAArE;GACE,kBAAC,SAAD;IAAO,OAAO;KAAE,SAAS;KAAQ,YAAY;KAAU,gBAAgB;KAAiB,KAAK;KAAO;cAApG,CACE,kBAAC,QAAD;KAAM,OAAO;MAAE,UAAU;MAAQ,OAAO,EAAO;MAAe;eAAE;KAAY,CAAA,EAC5E,kBAAC,UAAD;KACE,OAAO;KACP,WAAW,MAAM;MAGf,IAAM,IAAQ,EAAE,OAAO;AACvB,OAAI,MAAU,WAAW,MAAU,UAAU,MAAU,WACrD,EAAS,EAAM;;KAGnB,OAAO;eAEN,EAAc,KAAK,MAClB,kBAAC,UAAD;MAAwB,OAAO,EAAI;gBAChC,EAAI;MACE,EAFI,EAAI,MAER,CACT;KACK,CAAA,CACH;;GACR,kBAAC,SAAD;IAAO,OAAO;cAAd,CACE,kBAAC,SAAD;KAAO,MAAK;KAAW,SAAS;KAAW,WAAW,MAAM,EAAa,EAAE,OAAO,QAAQ;KAAI,CAAA,EAC9F,kBAAC,QAAD,EAAA,UAAM,wCAA2C,CAAA,CAC3C;;GACR,kBAAC,SAAD;IAAO,OAAO;cAAd,CACE,kBAAC,SAAD;KAAO,MAAK;KAAW,SAAS;KAAc,WAAW,MAAM,EAAgB,EAAE,OAAO,QAAQ;KAAI,CAAA,EACpG,kBAAC,QAAD,EAAA,UAAM,gDAAmD,CAAA,CACnD;;GACJ;;AAGR,QACE,kBAAC,OAAD;EAAK,OAAO,EAAE,SAAS,aAAa;YAApC;GAEE,kBAAC,OAAD;IACE,OAAO;KACL,SAAS;KACT,YAAY;KACZ,gBAAgB;KAChB,SAAS;KACT,cAAc;KACd,YAAY,EAAO;KACnB,cAAc;KACf;cATH,CAWE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;KAAK,OAAO;MAAE,UAAU;MAAQ,YAAY;MAAK,OAAO,EAAO;MAAa;eAAE;KAAwB,CAAA,EACtG,kBAAC,OAAD;KAAK,OAAO;MAAE,UAAU;MAAQ,OAAO,EAAO;MAAe,WAAW;MAAO;eAC5E,IACG,2FACA;KACA,CAAA,CACF,EAAA,CAAA,EACN,kBAAC,QAAD;KACE,OAAO;MACL,UAAU;MACV,YAAY;MACZ,SAAS;MACT,cAAc;MACd,OAAO;MACP,YAAY,IAAc,EAAO,kBAAkB,EAAO;MAC3D;eAEA,IAAc,cAAc;KACxB,CAAA,CACH;;GAGN,kBAAC,OAAD;IAAK,OAAO,EAAE,cAAc,QAAQ;cAApC;KACE,kBAAC,OAAD;MAAK,OAAO;OAAE,UAAU;OAAQ,YAAY;OAAK,OAAO,EAAO;OAAe,cAAc;OAAO;gBAAE;MAE/F,CAAA;KACN,kBAAC,OAAD;MAAK,OAAO;OAAE,SAAS;OAAQ,KAAK;OAAO,cAAc;OAAO;gBAAhE,CACE,kBAAC,SAAD;OACE,OAAO;OACP,aAAY;OACZ,OAAO;OACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAM;OAC/C,YAAY,MAAM;AAChB,QAAI,EAAE,QAAQ,WAAS,GAAW;;OAEpC,CAAA,EACF,kBAAC,UAAD;OAAQ,OAAO;OAAU,SAAS;OAAW,MAAK;OAAS,UAAU,CAAC;iBAAgB;OAE7E,CAAA,CACL;;KACL,EAAQ,WAAW,IAClB,kBAAC,OAAD;MAAK,OAAO;OAAE,UAAU;OAAQ,OAAO,EAAO;OAAc;gBAAE;MAExD,CAAA,GAEN,kBAAC,OAAD;MAAK,OAAO;OAAE,SAAS;OAAQ,eAAe;OAAU,KAAK;OAAO;gBACjE,EAAQ,KAAK,MACZ,kBAAC,OAAD;OAEE,OAAO;QACL,SAAS;QACT,YAAY;QACZ,gBAAgB;QAChB,SAAS;QACT,cAAc;QACd,YAAY,EAAO;QACpB;iBATH,CAWE,kBAAC,QAAD;QAAM,OAAO;SAAE,UAAU;SAAQ,OAAO,EAAO;SAAa;kBAAG;QAAS,CAAA,EACvE,KACC,kBAAC,UAAD;QACE,OAAO;SAAE,GAAG;SAAU,SAAS;SAAW,OAAO,EAAO;SAAiB;QACzE,eAAe,EAAa,EAAE;QAC9B,MAAK;kBACN;QAEQ,CAAA,CAEP;SApBC,EAoBD,CACN;MACE,CAAA;KAEJ;;GAGL,CAAC,KACA,kBAAC,OAAD;IAAK,OAAO,EAAE,cAAc,QAAQ;cAApC,CACE,kBAAC,OAAD;KAAK,OAAO;MAAE,UAAU;MAAQ,YAAY;MAAK,OAAO,EAAO;MAAe,cAAc;MAAO;eAAE;KAE/F,CAAA,EACL,EACG;;GAIP,CAAC,KACA,kBAAC,OAAD;IAAK,OAAO,EAAE,cAAc,OAAO;cAAnC,CACE,kBAAC,SAAD;KAAO,OAAO;MAAE,SAAS;MAAQ,KAAK;MAAO,YAAY;MAAc,cAAc;MAAQ;eAA7F,CACE,kBAAC,SAAD;MAAO,MAAK;MAAW,SAAS;MAAU,WAAW,MAAM,EAAY,EAAE,OAAO,QAAQ;MAAI,CAAA,EAC5F,kBAAC,QAAD;MAAM,OAAO;OAAE,UAAU;OAAQ,OAAO,EAAO;OAAe;gBAAE;MAGzD,CAAA,CACD;QACR,kBAAC,UAAD;KAAQ,OAAO;KAAY,SAAS;KAAe,UAAU,KAAW,CAAC;KAAgB,MAAK;eAC3F,IAAU,gBAAgB;KACpB,CAAA,CACL;;GAIP,KACC,kBAAA,GAAA,EAAA,UAAA;IACG,IACC,kBAAC,OAAD;KAAK,OAAO,EAAE,cAAc,QAAQ;eAApC;MACE,kBAAC,OAAD;OAAK,OAAO,EAAE,cAAc,OAAO;iBACjC,kBAAC,QAAD;QAAM,OAAO;SAAE,UAAU;SAAQ,YAAY;SAAK,OAAO,EAAO;SAAe;kBAAE;QAAoB,CAAA;OACjG,CAAA;MACN,kBAAC,YAAD;OACE,UAAA;OACA,OAAO;OACP,OAAO;QACL,OAAO;QACP,WAAW;QACX,SAAS;QACT,cAAc;QACd,QAAQ,aAAa,EAAO;QAC5B,YAAY,EAAO;QACnB,OAAO,EAAO;QACd,YAAY;QACZ,UAAU;QACV,QAAQ;QACT;OACD,CAAA;MACF,kBAAC,UAAD;OAAQ,OAAO;QAAE,GAAG;QAAU,WAAW;QAAO;OAAE,eAAe,EAAW,EAAc;OAAE,MAAK;iBAC9F,IAAS,aAAa;OAChB,CAAA;MACL;SAEN,kBAAC,OAAD;KACE,OAAO;MACL,UAAU;MACV,OAAO,EAAO;MACd,YAAY,EAAO;MACnB,cAAc;MACd,SAAS;MACT,cAAc;MACf;eARH;MASC;MAE4B,kBAAC,UAAD,EAAA,UAAQ,eAAoB,CAAA;;MACnD;;IAIR,kBAAC,OAAD;KAAK,OAAO,EAAE,cAAc,QAAQ;eAApC;MACE,kBAAC,OAAD;OAAK,OAAO;QAAE,UAAU;QAAQ,YAAY;QAAK,OAAO,EAAO;QAAe,cAAc;QAAO;iBAAE;OAE/F,CAAA;MACL;MACD,kBAAC,OAAD;OAAK,OAAO;QAAE,SAAS;QAAQ,YAAY;QAAU,KAAK;QAAQ,WAAW;QAAQ;iBAArF,CACE,kBAAC,UAAD;QACE,OAAO;QACP,SAAS;QACT,UAAU,KAAW,CAAC;QACtB,MAAK;kBAEJ,IAAU,cAAc;QAClB,CAAA,EACR,MAAqB,kBAAC,QAAD;QAAM,OAAO;SAAE,UAAU;SAAQ,OAAO,EAAO;SAAc;kBAAE;QAAgB,CAAA,CACjG;;MACN,kBAAC,OAAD;OAAK,OAAO;QAAE,UAAU;QAAQ,OAAO,EAAO;QAAc,WAAW;QAAO;iBAAE;OAG1E,CAAA;MACF;;IAIL,KACC,kBAAC,OAAD;KAAK,OAAO;MAAE,SAAS;MAAQ,KAAK;MAAO;eAA3C,CACE,kBAAC,UAAD;MAAQ,OAAO;MAAU,eAAe,KAAU,EAAU,EAAO,GAAG;MAAE,UAAU;MAAS,MAAK;gBAAS;MAEhG,CAAA,EACT,kBAAC,UAAD;MACE,OAAO;OAAE,GAAG;OAAU,OAAO,EAAO;OAAiB,aAAa,EAAO;OAAiB;MAC1F,eAAe;AACb,OACE,KACA,OAAO,QACL,+FACD,IAEI,GAAU,EAAO,GAAG;;MAG7B,UAAU;MACV,MAAK;gBACN;MAEQ,CAAA,CACL;;IAEP,EAAA,CAAA;IAGH,KAAc,MACd,kBAAC,OAAD;IAAK,OAAO;KAAE,WAAW;KAAQ,UAAU;KAAQ,OAAO,EAAO;KAAiB;cAC/E,KAAc,GAAO;IAClB,CAAA;GAEJ"}
|
|
1
|
+
{"version":3,"file":"EmbedTab.js","names":[],"sources":["../../../../../src/bigconsole/components/dashboard/ShareDialog/EmbedTab.tsx"],"sourcesContent":["/**\n * EmbedTab — \"Publish to web\" section of the dashboard Share dialog.\n *\n * Owner-facing UI to publish a dashboard as an anonymous-link embed serving LIVE\n * data, manage the allowed parent domains, copy the iframe snippet, rotate the\n * link key, and unpublish. Backed by {@link useDashboardEmbedPolicy}; all\n * mutations are gateway-enforced by `@rbac(manage_embed)` (owner-only).\n *\n * Self-contained (inline styles driven by the dialog's `colors`) so it slots into\n * the existing hand-styled ShareDialog without a broader refactor.\n */\n\nimport React, { useEffect, useMemo, useRef, useState } from 'react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useDashboardEmbedPolicy, themeChoiceFromPolicy } from '../../../hooks/useDashboardEmbedPolicy';\nimport { BIGCONSOLE_PERMISSIONS } from '../../../../constants/permissions';\n\ninterface DialogColors {\n bgPrimary: string;\n bgSecondary: string;\n bgTertiary: string;\n textPrimary: string;\n textSecondary: string;\n textTertiary: string;\n borderDefault: string;\n actionPrimaryBg: string;\n actionPrimaryBgHover: string;\n statusSuccessBg: string;\n statusErrorText: string;\n}\n\nexport interface EmbedTabProps {\n dashboardId: string;\n colors: DialogColors;\n}\n\n/** Embed color-mode baked into the iframe URL (BOFF-5734). */\ntype EmbedSnippetTheme = 'light' | 'dark' | 'auto';\n\nconst THEME_OPTION_VALUES: ReadonlyArray<EmbedSnippetTheme> = ['light', 'dark', 'auto'];\n\n/**\n * Bake the chosen color mode into an iframe snippet by adding `?theme=` to its\n * `src` URL. `light` is the default and is left implicit so existing/plain\n * snippets stay unchanged. The secret `#key=` fragment is preserved untouched.\n *\n * Inserted via string splicing (before the fragment) rather than `URL`/\n * `URLSearchParams`, which re-serialize ALL params and could subtly re-encode\n * existing ones (e.g. `%20` → `+`). `theme` is a fixed enum, so no encoding is\n * needed; every other part of the URL is passed through byte-for-byte.\n */\nexport function withThemeInSnippet(snippet: string, theme: EmbedSnippetTheme): string {\n if (theme === 'light') return snippet;\n // Require whitespace before `src` so we match the real attribute, never a\n // substring like `data-src`/`srcdoc` (the snippet is backend-generated with\n // each attribute on its own indented line).\n return snippet.replace(/(?<=\\s)src=\"([^\"]*)\"/, (_match, url: string) => {\n const hashIdx = url.indexOf('#');\n const base = hashIdx === -1 ? url : url.slice(0, hashIdx);\n const fragment = hashIdx === -1 ? '' : url.slice(hashIdx);\n const sep = base.includes('?') ? '&' : '?';\n return `src=\"${base}${sep}theme=${theme}${fragment}\"`;\n });\n}\n\n/** Validate an exact https origin (matches the backend allowlist rules). */\nfunction normalizeOrigin(raw: string): string | null {\n const trimmed = raw.trim();\n if (!trimmed) return null;\n try {\n const url = new URL(trimmed);\n if (url.protocol !== 'https:') return null;\n if ((url.pathname !== '' && url.pathname !== '/') || url.search || url.hash) return null;\n return url.origin;\n } catch {\n return null;\n }\n}\n\nexport function EmbedTab({ dashboardId, colors }: EmbedTabProps) {\n const { t } = useI18n();\n const {\n policy,\n secret,\n loading,\n error,\n fetchPolicy,\n publishToWeb,\n applyPresentation,\n setAllowedOrigins,\n rotateKey,\n unpublish,\n } = useDashboardEmbedPolicy();\n\n // All embed policy mutations (publish, rotate, revoke, set-origins, apply\n // presentation) are gateway-enforced by `@rbac(manage_embed)`. Gate the UI on\n // the same permission so the controls degrade gracefully instead of erroring.\n const { hasPermission } = usePermissions();\n const canManageEmbed = hasPermission(BIGCONSOLE_PERMISSIONS.DASHBOARD_MANAGE_EMBED);\n\n const [domainInput, setDomainInput] = useState('');\n const [pendingDomains, setPendingDomains] = useState<string[]>([]);\n const [attested, setAttested] = useState(false);\n const [copied, setCopied] = useState(false);\n // Presentation options (BOFF-5735). Defaults mirror the backend column defaults\n // so a fresh publish captures a sensible look without extra clicks.\n const [theme, setTheme] = useState<EmbedSnippetTheme>('light');\n const [showTitle, setShowTitle] = useState(false);\n const [showBranding, setShowBranding] = useState(true);\n const [presentationSaved, setPresentationSaved] = useState(false);\n const [localError, setLocalError] = useState<string | null>(null);\n // Only seed the presentation controls once per policy identity — NOT on every\n // `policy` object change. Otherwise an unrelated mutation (e.g. adding a domain\n // via setAllowedOrigins) would return a fresh policy object and clobber the\n // owner's in-progress, not-yet-applied theme/title/branding edits.\n const syncedPolicyIdRef = useRef<string | null>(null);\n const savedTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (dashboardId) fetchPolicy(dashboardId);\n }, [dashboardId, fetchPolicy]);\n\n // Reflect the persisted presentation the first time each policy loads.\n useEffect(() => {\n if (!policy || syncedPolicyIdRef.current === policy.id) return;\n syncedPolicyIdRef.current = policy.id;\n setTheme(themeChoiceFromPolicy(policy.presentationTheme));\n setShowTitle(policy.showDashboardTitle);\n setShowBranding(policy.showBrandingFooter);\n }, [policy]);\n\n // Clear any pending \"Updated ✓\" timer on unmount.\n useEffect(\n () => () => {\n if (savedTimerRef.current) clearTimeout(savedTimerRef.current);\n },\n []\n );\n\n const isPublished = policy?.status === 'ACTIVE';\n const domains = isPublished ? (policy?.allowedParentOrigins ?? []) : pendingDomains;\n\n // The copyable iframe snippet: from the one-time secret if present (fresh\n // publish/rotate), else reconstructed from the locator for an already-published\n // policy (the fragment key is only available in the one-time secret).\n const iframeSnippet = useMemo(() => {\n if (secret?.iframeSnippet) return withThemeInSnippet(secret.iframeSnippet, theme);\n return null;\n }, [secret, theme]);\n\n const addDomain = () => {\n setLocalError(null);\n const origin = normalizeOrigin(domainInput);\n if (!origin) {\n setLocalError(\n t('bigconsole.dashboards.embed.error.invalidOrigin', 'Enter a valid https origin, e.g. https://example.com')\n );\n return;\n }\n if (domains.includes(origin)) {\n setDomainInput('');\n return;\n }\n if (isPublished && policy) {\n void setAllowedOrigins(policy.id, [...domains, origin]);\n } else {\n setPendingDomains((prev) => [...prev, origin]);\n }\n setDomainInput('');\n };\n\n const removeDomain = (origin: string) => {\n if (isPublished && policy) {\n void setAllowedOrigins(\n policy.id,\n domains.filter((d) => d !== origin)\n );\n } else {\n setPendingDomains((prev) => prev.filter((d) => d !== origin));\n }\n };\n\n const handlePublish = async () => {\n setLocalError(null);\n if (pendingDomains.length === 0) {\n setLocalError(\n t('bigconsole.dashboards.embed.error.noDomains', 'Add at least one allowed website domain before publishing.')\n );\n return;\n }\n if (!attested) {\n setLocalError(\n t('bigconsole.dashboards.embed.error.notAttested', 'Please confirm this dashboard is safe to be public.')\n );\n return;\n }\n await publishToWeb(dashboardId, pendingDomains, true, { theme, showTitle, showBranding });\n };\n\n const handleApplyPresentation = async () => {\n if (!policy) return;\n setLocalError(null);\n const updated = await applyPresentation(policy.id, { theme, showTitle, showBranding });\n if (updated) {\n setPresentationSaved(true);\n // Clear any in-flight timer so rapid re-clicks don't hide the confirmation early.\n if (savedTimerRef.current) clearTimeout(savedTimerRef.current);\n savedTimerRef.current = setTimeout(() => setPresentationSaved(false), 1500);\n }\n };\n\n const handleCopy = async (text: string) => {\n try {\n await navigator.clipboard.writeText(text);\n setCopied(true);\n setTimeout(() => setCopied(false), 1500);\n } catch {\n setLocalError(t('bigconsole.dashboards.embed.error.copyFailed', 'Could not copy — select and copy manually.'));\n }\n };\n\n const primaryBtn: React.CSSProperties = {\n padding: '8px 14px',\n borderRadius: '8px',\n border: 'none',\n background: colors.actionPrimaryBg,\n color: '#fff',\n fontSize: '13px',\n fontWeight: 600,\n cursor: 'pointer',\n };\n const ghostBtn: React.CSSProperties = {\n padding: '8px 14px',\n borderRadius: '8px',\n border: `1px solid ${colors.borderDefault}`,\n background: 'transparent',\n color: colors.textPrimary,\n fontSize: '13px',\n cursor: 'pointer',\n };\n const inputStyle: React.CSSProperties = {\n flex: 1,\n padding: '8px 10px',\n borderRadius: '8px',\n border: `1px solid ${colors.borderDefault}`,\n background: colors.bgSecondary,\n color: colors.textPrimary,\n fontSize: '13px',\n };\n const selectStyle: React.CSSProperties = {\n padding: '4px 8px',\n borderRadius: '6px',\n border: `1px solid ${colors.borderDefault}`,\n background: colors.bgSecondary,\n color: colors.textPrimary,\n fontSize: '12px',\n cursor: 'pointer',\n };\n const toggleRow: React.CSSProperties = {\n display: 'flex',\n gap: '8px',\n alignItems: 'flex-start',\n fontSize: '12px',\n color: colors.textSecondary,\n };\n\n const themeOptions = useMemo(\n () =>\n THEME_OPTION_VALUES.map((value) => ({\n value,\n label:\n value === 'light'\n ? t('bigconsole.dashboards.embed.theme.option.light', 'Light')\n : value === 'dark'\n ? t('bigconsole.dashboards.embed.theme.option.dark', 'Dark')\n : t('bigconsole.dashboards.embed.theme.option.auto', 'Auto (match viewer)'),\n })),\n [t]\n );\n\n // Presentation controls (BOFF-5735) — shared by the pre-publish and published\n // states. Local state drives both the persisted policy and the snippet `?theme=`.\n const presentationControls = (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>\n <label style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '8px' }}>\n <span style={{ fontSize: '12px', color: colors.textSecondary }}>\n {t('bigconsole.dashboards.embed.theme.label', 'Theme')}\n </span>\n <select\n value={theme}\n onChange={(e) => {\n // The options are fixed, but narrow instead of casting so an\n // unexpected value can never slip into state.\n const value = e.target.value;\n if (value === 'light' || value === 'dark' || value === 'auto') {\n setTheme(value);\n }\n }}\n style={selectStyle}\n >\n {themeOptions.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </label>\n <label style={toggleRow}>\n <input type=\"checkbox\" checked={showTitle} onChange={(e) => setShowTitle(e.target.checked)} />\n <span>{t('bigconsole.dashboards.embed.presentation.showTitle', 'Show the dashboard title as a header')}</span>\n </label>\n <label style={toggleRow}>\n <input type=\"checkbox\" checked={showBranding} onChange={(e) => setShowBranding(e.target.checked)} />\n <span>\n {t('bigconsole.dashboards.embed.presentation.showBranding', 'Show a subtle “Powered by BigConsole” footer')}\n </span>\n </label>\n </div>\n );\n\n return (\n <div style={{ padding: '20px 24px' }}>\n {/* Status banner */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '12px 14px',\n borderRadius: '10px',\n background: colors.bgSecondary,\n marginBottom: '16px',\n }}\n >\n <div>\n <div style={{ fontSize: '14px', fontWeight: 600, color: colors.textPrimary }}>\n {t('bigconsole.dashboards.embed.heading', 'Publish to the web')}\n </div>\n <div style={{ fontSize: '12px', color: colors.textSecondary, marginTop: '2px' }}>\n {isPublished\n ? t(\n 'bigconsole.dashboards.embed.status.liveDescription',\n 'This dashboard is live. Anyone with the link on an allowed website sees its live data.'\n )\n : t(\n 'bigconsole.dashboards.embed.status.privateDescription',\n 'Embed this dashboard on your website. Viewers see live data — no login required.'\n )}\n </div>\n </div>\n <span\n style={{\n fontSize: '11px',\n fontWeight: 700,\n padding: '3px 8px',\n borderRadius: '999px',\n color: '#fff',\n background: isPublished ? colors.statusSuccessBg : colors.textTertiary,\n }}\n >\n {isPublished\n ? t('bigconsole.dashboards.embed.badge.published', 'PUBLISHED')\n : t('bigconsole.dashboards.embed.badge.private', 'PRIVATE')}\n </span>\n </div>\n\n {/* Allowed domains */}\n <div style={{ marginBottom: '16px' }}>\n <div style={{ fontSize: '12px', fontWeight: 600, color: colors.textSecondary, marginBottom: '6px' }}>\n {t('bigconsole.dashboards.embed.domains.label', 'Allowed website domains')}\n </div>\n <div style={{ display: 'flex', gap: '8px', marginBottom: '8px' }}>\n <input\n style={inputStyle}\n placeholder={t('bigconsole.dashboards.embed.domains.placeholder', 'https://yoursite.com')}\n value={domainInput}\n onChange={(e) => setDomainInput(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') addDomain();\n }}\n />\n <button style={ghostBtn} onClick={addDomain} type=\"button\" disabled={!canManageEmbed}>\n {t('bigconsole.dashboards.embed.domains.add', 'Add')}\n </button>\n </div>\n {domains.length === 0 ? (\n <div style={{ fontSize: '12px', color: colors.textTertiary }}>\n {t(\n 'bigconsole.dashboards.embed.domains.empty',\n 'No domains yet. Only listed https domains may frame this dashboard.'\n )}\n </div>\n ) : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>\n {domains.map((d) => (\n <div\n key={d}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '6px 10px',\n borderRadius: '8px',\n background: colors.bgTertiary,\n }}\n >\n <span style={{ fontSize: '13px', color: colors.textPrimary }}>{d}</span>\n {canManageEmbed && (\n <button\n style={{ ...ghostBtn, padding: '2px 8px', color: colors.statusErrorText }}\n onClick={() => removeDomain(d)}\n type=\"button\"\n >\n {t('bigconsole.dashboards.embed.domains.remove', 'Remove')}\n </button>\n )}\n </div>\n ))}\n </div>\n )}\n </div>\n\n {/* Presentation (unpublished — captured into the publish) */}\n {!isPublished && (\n <div style={{ marginBottom: '16px' }}>\n <div style={{ fontSize: '12px', fontWeight: 600, color: colors.textSecondary, marginBottom: '8px' }}>\n {t('bigconsole.dashboards.embed.presentation.heading', 'Presentation')}\n </div>\n {presentationControls}\n </div>\n )}\n\n {/* Publish CTA (unpublished) */}\n {!isPublished && (\n <div style={{ marginBottom: '8px' }}>\n <label style={{ display: 'flex', gap: '8px', alignItems: 'flex-start', marginBottom: '12px' }}>\n <input type=\"checkbox\" checked={attested} onChange={(e) => setAttested(e.target.checked)} />\n <span style={{ fontSize: '12px', color: colors.textSecondary }}>\n {t(\n 'bigconsole.dashboards.embed.attestation',\n 'I understand this makes the dashboard’s live data visible to anyone with the link, and I confirm it is safe to be public.'\n )}\n </span>\n </label>\n <button style={primaryBtn} onClick={handlePublish} disabled={loading || !canManageEmbed} type=\"button\">\n {loading\n ? t('bigconsole.dashboards.embed.publishing', 'Publishing…')\n : t('bigconsole.dashboards.embed.publish', 'Publish to web')}\n </button>\n </div>\n )}\n\n {/* Embed snippet + management (published) */}\n {isPublished && (\n <>\n {iframeSnippet ? (\n <div style={{ marginBottom: '16px' }}>\n <div style={{ marginBottom: '6px' }}>\n <span style={{ fontSize: '12px', fontWeight: 600, color: colors.textSecondary }}>\n {t('bigconsole.dashboards.embed.snippet.label', 'Embed snippet')}\n </span>\n </div>\n <textarea\n readOnly\n value={iframeSnippet}\n style={{\n width: '100%',\n minHeight: '96px',\n padding: '10px',\n borderRadius: '8px',\n border: `1px solid ${colors.borderDefault}`,\n background: colors.bgSecondary,\n color: colors.textPrimary,\n fontFamily: 'monospace',\n fontSize: '12px',\n resize: 'vertical',\n }}\n />\n <button style={{ ...ghostBtn, marginTop: '8px' }} onClick={() => handleCopy(iframeSnippet)} type=\"button\">\n {copied\n ? t('bigconsole.dashboards.embed.snippet.copied', 'Copied ✓')\n : t('bigconsole.dashboards.embed.snippet.copy', 'Copy snippet')}\n </button>\n </div>\n ) : (\n <div\n style={{\n fontSize: '12px',\n color: colors.textSecondary,\n background: colors.bgSecondary,\n borderRadius: '8px',\n padding: '10px 12px',\n marginBottom: '16px',\n }}\n >\n {t(\n 'bigconsole.dashboards.embed.snippet.alreadyActive',\n 'The embed link is already active. For security the snippet (which contains the secret key) is only shown once at publish time — use {{rotateLabel}} to generate a fresh snippet.',\n { rotateLabel: t('bigconsole.dashboards.embed.rotate', 'Rotate link') }\n )}\n </div>\n )}\n\n {/* Presentation (published — persisted + re-published to take effect) */}\n <div style={{ marginBottom: '16px' }}>\n <div style={{ fontSize: '12px', fontWeight: 600, color: colors.textSecondary, marginBottom: '8px' }}>\n {t('bigconsole.dashboards.embed.presentation.heading', 'Presentation')}\n </div>\n {presentationControls}\n <div style={{ display: 'flex', alignItems: 'center', gap: '10px', marginTop: '10px' }}>\n <button\n style={ghostBtn}\n onClick={handleApplyPresentation}\n disabled={loading || !canManageEmbed}\n type=\"button\"\n >\n {loading\n ? t('bigconsole.dashboards.embed.applying', 'Applying…')\n : t('bigconsole.dashboards.embed.apply', 'Apply changes')}\n </button>\n {presentationSaved && (\n <span style={{ fontSize: '12px', color: colors.textTertiary }}>\n {t('bigconsole.dashboards.embed.updated', 'Updated ✓')}\n </span>\n )}\n </div>\n <div style={{ fontSize: '11px', color: colors.textTertiary, marginTop: '6px' }}>\n {t(\n 'bigconsole.dashboards.embed.presentation.applyHelp',\n 'Changes apply to live embeds within a few seconds — no re-publish needed, and the embed link stays the same.'\n )}\n </div>\n </div>\n\n {/* Rotate/Unpublish are destructive management actions — hide entirely\n when the caller can't manage the embed. */}\n {canManageEmbed && (\n <div style={{ display: 'flex', gap: '8px' }}>\n <button style={ghostBtn} onClick={() => policy && rotateKey(policy.id)} disabled={loading} type=\"button\">\n {t('bigconsole.dashboards.embed.rotate', 'Rotate link')}\n </button>\n <button\n style={{ ...ghostBtn, color: colors.statusErrorText, borderColor: colors.statusErrorText }}\n onClick={() => {\n if (\n policy &&\n window.confirm(\n t(\n 'bigconsole.dashboards.embed.unpublishConfirm',\n 'Unpublish this dashboard? The embed will stop working immediately for anyone using the link.'\n )\n )\n ) {\n void unpublish(policy.id);\n }\n }}\n disabled={loading}\n type=\"button\"\n >\n {t('bigconsole.dashboards.embed.unpublish', 'Unpublish')}\n </button>\n </div>\n )}\n </>\n )}\n\n {(localError || error) && (\n <div style={{ marginTop: '12px', fontSize: '12px', color: colors.statusErrorText }}>\n {localError ?? error?.message}\n </div>\n )}\n </div>\n );\n}\n\nexport default EmbedTab;\n"],"mappings":"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"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { WIDGET_CATEGORY_LABELS as e, getWidgetCategories as t, getWidgetKey as n } from "../widgets/WidgetRegistry.js";
|
|
2
2
|
import { memo as r, useCallback as i, useMemo as a, useState as o } from "react";
|
|
3
3
|
import { Activity as s, BarChart3 as c, Calendar as l, ChevronDown as u, ChevronRight as d, Columns as f, ExternalLink as p, FileText as m, Filter as h, Gauge as g, GitBranch as _, Grid3x3 as v, GripVertical as y, Layers as b, LayoutDashboard as x, List as S, MapPin as C, Puzzle as w, Search as T, Store as E, Table as D, TrendingUp as O, Type as k, X as A } from "lucide-react";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { useI18n as j } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
5
|
+
import { Input as M } from "@burdenoff/fe-libs/ui";
|
|
6
|
+
import { jsx as N, jsxs as P } from "react/jsx-runtime";
|
|
6
7
|
//#region src/bigconsole/components/dashboard/WidgetPalette.tsx
|
|
7
|
-
var
|
|
8
|
+
var F = {
|
|
8
9
|
TrendingUp: O,
|
|
9
10
|
BarChart3: c,
|
|
10
11
|
Filter: h,
|
|
@@ -23,10 +24,10 @@ var P = {
|
|
|
23
24
|
Puzzle: w,
|
|
24
25
|
LayoutDashboard: x
|
|
25
26
|
};
|
|
26
|
-
function
|
|
27
|
-
return
|
|
27
|
+
function I(e) {
|
|
28
|
+
return F[e] || w;
|
|
28
29
|
}
|
|
29
|
-
var
|
|
30
|
+
var L = {
|
|
30
31
|
container: {
|
|
31
32
|
width: "300px",
|
|
32
33
|
height: "100%",
|
|
@@ -283,8 +284,8 @@ var I = {
|
|
|
283
284
|
cursor: "pointer",
|
|
284
285
|
transition: "border-color 0.15s, color 0.15s"
|
|
285
286
|
}
|
|
286
|
-
},
|
|
287
|
-
let
|
|
287
|
+
}, R = r(function({ isOpen: r, onClose: s, onWidgetSelect: c, onDragStart: l, onDragEnd: f, installedWidgets: m = [], installedWidgetsLoading: h = !1, definitions: g }) {
|
|
288
|
+
let { t: _ } = j(), [v, x] = o(""), [S, C] = o(new Set([
|
|
288
289
|
"KPI",
|
|
289
290
|
"Visualization",
|
|
290
291
|
"Data",
|
|
@@ -292,7 +293,7 @@ var I = {
|
|
|
292
293
|
"Temporal",
|
|
293
294
|
"Custom",
|
|
294
295
|
"Installed"
|
|
295
|
-
])), [
|
|
296
|
+
])), [w, D] = o(null), O = a(() => (g ? Object.keys(e).map((t) => ({
|
|
296
297
|
category: t,
|
|
297
298
|
label: e[t],
|
|
298
299
|
widgets: g.filter((e) => e.category === t)
|
|
@@ -316,19 +317,19 @@ var I = {
|
|
|
316
317
|
};
|
|
317
318
|
}
|
|
318
319
|
return e;
|
|
319
|
-
}).filter((e) => e.category !== "Installed" || e.widgets.length > 0), [m, g]),
|
|
320
|
-
if (!
|
|
321
|
-
let e =
|
|
322
|
-
return
|
|
320
|
+
}).filter((e) => e.category !== "Installed" || e.widgets.length > 0), [m, g]), k = a(() => {
|
|
321
|
+
if (!v.trim()) return O;
|
|
322
|
+
let e = v.toLowerCase();
|
|
323
|
+
return O.map((t) => ({
|
|
323
324
|
...t,
|
|
324
325
|
widgets: t.widgets.filter((t) => t.name.toLowerCase().includes(e) || t.description.toLowerCase().includes(e) || t.tags.some((t) => t.includes(e)))
|
|
325
326
|
})).filter((e) => e.widgets.length > 0);
|
|
326
|
-
}, [
|
|
327
|
-
|
|
327
|
+
}, [O, v]), F = i((e) => {
|
|
328
|
+
C((t) => {
|
|
328
329
|
let n = new Set(t);
|
|
329
330
|
return n.has(e) ? n.delete(e) : n.add(e), n;
|
|
330
331
|
});
|
|
331
|
-
}, []),
|
|
332
|
+
}, []), R = i((e, t) => {
|
|
332
333
|
e.dataTransfer.setData("application/json", JSON.stringify({
|
|
333
334
|
type: t.type,
|
|
334
335
|
name: t.name,
|
|
@@ -340,118 +341,118 @@ var I = {
|
|
|
340
341
|
n.style.cssText = "\n position: absolute;\n top: -1000px;\n left: -1000px;\n padding: 8px 12px;\n background: var(--color-bg-surface);\n border: 2px solid var(--color-action-primary-bg);\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--color-text-primary);\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n ", n.textContent = t.name, document.body.appendChild(n), e.dataTransfer.setDragImage(n, 0, 0), setTimeout(() => {
|
|
341
342
|
document.body.removeChild(n);
|
|
342
343
|
}, 0), l?.(t.type, t);
|
|
343
|
-
}, [l]),
|
|
344
|
+
}, [l]), z = i(() => {
|
|
344
345
|
f?.();
|
|
345
|
-
}, [f]),
|
|
346
|
+
}, [f]), B = i((e) => {
|
|
346
347
|
c?.(e.type, e);
|
|
347
|
-
}, [c]),
|
|
348
|
+
}, [c]), V = i(() => {
|
|
348
349
|
if (typeof window > "u") return;
|
|
349
350
|
let e = `${window.location.origin}/bigconsole/store${window.location.search}`;
|
|
350
351
|
window.open(e, "_blank", "noopener,noreferrer");
|
|
351
352
|
}, []);
|
|
352
|
-
return r ? /* @__PURE__ */
|
|
353
|
-
style:
|
|
353
|
+
return r ? /* @__PURE__ */ P("div", {
|
|
354
|
+
style: L.container,
|
|
354
355
|
children: [
|
|
355
|
-
/* @__PURE__ */
|
|
356
|
-
style:
|
|
357
|
-
children: [/* @__PURE__ */
|
|
358
|
-
style:
|
|
359
|
-
children: [/* @__PURE__ */
|
|
360
|
-
style:
|
|
361
|
-
children: [/* @__PURE__ */
|
|
362
|
-
style:
|
|
363
|
-
children: /* @__PURE__ */
|
|
356
|
+
/* @__PURE__ */ P("div", {
|
|
357
|
+
style: L.header,
|
|
358
|
+
children: [/* @__PURE__ */ P("div", {
|
|
359
|
+
style: L.headerTop,
|
|
360
|
+
children: [/* @__PURE__ */ P("div", {
|
|
361
|
+
style: L.headerTitle,
|
|
362
|
+
children: [/* @__PURE__ */ N("div", {
|
|
363
|
+
style: L.headerIcon,
|
|
364
|
+
children: /* @__PURE__ */ N(b, { style: {
|
|
364
365
|
width: "18px",
|
|
365
366
|
height: "18px",
|
|
366
367
|
color: "var(--color-action-primary-text)"
|
|
367
368
|
} })
|
|
368
|
-
}), /* @__PURE__ */
|
|
369
|
-
style:
|
|
370
|
-
children: "Widgets"
|
|
371
|
-
}), /* @__PURE__ */
|
|
372
|
-
style:
|
|
373
|
-
children: "Drag or click to add"
|
|
369
|
+
}), /* @__PURE__ */ P("div", { children: [/* @__PURE__ */ N("h3", {
|
|
370
|
+
style: L.title,
|
|
371
|
+
children: _("bigconsole.dashboards.widgetPalette.title", "Widgets")
|
|
372
|
+
}), /* @__PURE__ */ N("p", {
|
|
373
|
+
style: L.subtitle,
|
|
374
|
+
children: _("bigconsole.dashboards.widgetPalette.subtitle", "Drag or click to add")
|
|
374
375
|
})] })]
|
|
375
|
-
}), /* @__PURE__ */
|
|
376
|
+
}), /* @__PURE__ */ N("button", {
|
|
376
377
|
type: "button",
|
|
377
378
|
onClick: s,
|
|
378
|
-
style:
|
|
379
|
+
style: L.closeButton,
|
|
379
380
|
onMouseOver: (e) => e.currentTarget.style.backgroundColor = "var(--color-bg-hover)",
|
|
380
381
|
onMouseOut: (e) => e.currentTarget.style.backgroundColor = "transparent",
|
|
381
|
-
children: /* @__PURE__ */
|
|
382
|
+
children: /* @__PURE__ */ N(A, { style: {
|
|
382
383
|
width: "16px",
|
|
383
384
|
height: "16px"
|
|
384
385
|
} })
|
|
385
386
|
})]
|
|
386
|
-
}), /* @__PURE__ */
|
|
387
|
-
style:
|
|
388
|
-
children: [/* @__PURE__ */
|
|
387
|
+
}), /* @__PURE__ */ P("div", {
|
|
388
|
+
style: L.searchContainer,
|
|
389
|
+
children: [/* @__PURE__ */ N(T, { style: L.searchIcon }), /* @__PURE__ */ N(M, {
|
|
389
390
|
type: "text",
|
|
390
|
-
placeholder: "Search widgets...",
|
|
391
|
-
value:
|
|
392
|
-
onChange: (e) =>
|
|
393
|
-
style:
|
|
391
|
+
placeholder: _("bigconsole.dashboards.widgetPalette.searchPlaceholder", "Search widgets..."),
|
|
392
|
+
value: v,
|
|
393
|
+
onChange: (e) => x(e.target.value),
|
|
394
|
+
style: L.searchInput
|
|
394
395
|
})]
|
|
395
396
|
})]
|
|
396
397
|
}),
|
|
397
|
-
/* @__PURE__ */
|
|
398
|
-
style:
|
|
399
|
-
children: /* @__PURE__ */
|
|
400
|
-
style:
|
|
401
|
-
children: [
|
|
402
|
-
style:
|
|
403
|
-
children: [/* @__PURE__ */
|
|
398
|
+
/* @__PURE__ */ N("div", {
|
|
399
|
+
style: L.content,
|
|
400
|
+
children: /* @__PURE__ */ P("div", {
|
|
401
|
+
style: L.scrollArea,
|
|
402
|
+
children: [k.map((e) => /* @__PURE__ */ P("div", {
|
|
403
|
+
style: L.categoryContainer,
|
|
404
|
+
children: [/* @__PURE__ */ P("button", {
|
|
404
405
|
type: "button",
|
|
405
|
-
onClick: () =>
|
|
406
|
-
style:
|
|
406
|
+
onClick: () => F(e.category),
|
|
407
|
+
style: L.categoryHeader,
|
|
407
408
|
onMouseOver: (e) => e.currentTarget.style.backgroundColor = "var(--color-bg-hover)",
|
|
408
409
|
onMouseOut: (e) => e.currentTarget.style.backgroundColor = "transparent",
|
|
409
410
|
children: [
|
|
410
|
-
|
|
411
|
-
/* @__PURE__ */
|
|
412
|
-
style:
|
|
411
|
+
S.has(e.category) ? /* @__PURE__ */ N(u, { style: L.categoryChevron }) : /* @__PURE__ */ N(d, { style: L.categoryChevron }),
|
|
412
|
+
/* @__PURE__ */ N("span", {
|
|
413
|
+
style: L.categoryLabel,
|
|
413
414
|
children: e.label
|
|
414
415
|
}),
|
|
415
|
-
/* @__PURE__ */
|
|
416
|
-
style:
|
|
416
|
+
/* @__PURE__ */ N("span", {
|
|
417
|
+
style: L.categoryCount,
|
|
417
418
|
children: e.widgets.length
|
|
418
419
|
})
|
|
419
420
|
]
|
|
420
|
-
}),
|
|
421
|
-
style:
|
|
422
|
-
children: [h && e.category === "Installed" && /* @__PURE__ */
|
|
421
|
+
}), S.has(e.category) && /* @__PURE__ */ P("div", {
|
|
422
|
+
style: L.widgetList,
|
|
423
|
+
children: [h && e.category === "Installed" && /* @__PURE__ */ N("div", {
|
|
423
424
|
style: {
|
|
424
425
|
fontSize: "var(--font-size-body-xs)",
|
|
425
426
|
color: "var(--color-text-muted)",
|
|
426
427
|
padding: "var(--space-controlGap)"
|
|
427
428
|
},
|
|
428
|
-
children: "Loading..."
|
|
429
|
+
children: _("bigconsole.dashboards.widgetPalette.loading", "Loading...")
|
|
429
430
|
}), e.widgets.map((e) => {
|
|
430
|
-
let t =
|
|
431
|
-
return /* @__PURE__ */
|
|
431
|
+
let t = I(e.icon), r = n(e), i = w === r;
|
|
432
|
+
return /* @__PURE__ */ P("div", {
|
|
432
433
|
draggable: !0,
|
|
433
|
-
onDragStart: (t) =>
|
|
434
|
-
onDragEnd:
|
|
435
|
-
onClick: () =>
|
|
436
|
-
onMouseEnter: () =>
|
|
437
|
-
onMouseLeave: () =>
|
|
434
|
+
onDragStart: (t) => R(t, e),
|
|
435
|
+
onDragEnd: z,
|
|
436
|
+
onClick: () => B(e),
|
|
437
|
+
onMouseEnter: () => D(r),
|
|
438
|
+
onMouseLeave: () => D(null),
|
|
438
439
|
style: {
|
|
439
|
-
...
|
|
440
|
-
...i ?
|
|
440
|
+
...L.widgetCard,
|
|
441
|
+
...i ? L.widgetCardHover : {}
|
|
441
442
|
},
|
|
442
443
|
children: [
|
|
443
|
-
/* @__PURE__ */
|
|
444
|
-
/* @__PURE__ */ M("div", {
|
|
445
|
-
style: I.widgetIcon,
|
|
446
|
-
children: /* @__PURE__ */ M(t, { style: I.widgetIconInner })
|
|
447
|
-
}),
|
|
444
|
+
/* @__PURE__ */ N(y, { style: L.dragHandle }),
|
|
448
445
|
/* @__PURE__ */ N("div", {
|
|
449
|
-
style:
|
|
450
|
-
children:
|
|
451
|
-
|
|
446
|
+
style: L.widgetIcon,
|
|
447
|
+
children: /* @__PURE__ */ N(t, { style: L.widgetIconInner })
|
|
448
|
+
}),
|
|
449
|
+
/* @__PURE__ */ P("div", {
|
|
450
|
+
style: L.widgetText,
|
|
451
|
+
children: [/* @__PURE__ */ N("div", {
|
|
452
|
+
style: L.widgetName,
|
|
452
453
|
children: e.name
|
|
453
|
-
}), /* @__PURE__ */
|
|
454
|
-
style:
|
|
454
|
+
}), /* @__PURE__ */ N("div", {
|
|
455
|
+
style: L.widgetDescription,
|
|
455
456
|
children: e.description
|
|
456
457
|
})]
|
|
457
458
|
})
|
|
@@ -459,41 +460,42 @@ var I = {
|
|
|
459
460
|
}, r);
|
|
460
461
|
})]
|
|
461
462
|
})]
|
|
462
|
-
}, e.category)),
|
|
463
|
-
style:
|
|
463
|
+
}, e.category)), k.length === 0 && /* @__PURE__ */ P("div", {
|
|
464
|
+
style: L.emptyState,
|
|
464
465
|
children: [
|
|
465
|
-
/* @__PURE__ */
|
|
466
|
-
style:
|
|
467
|
-
children: /* @__PURE__ */
|
|
466
|
+
/* @__PURE__ */ N("div", {
|
|
467
|
+
style: L.emptyIcon,
|
|
468
|
+
children: /* @__PURE__ */ N(T, { style: {
|
|
468
469
|
width: "24px",
|
|
469
470
|
height: "24px",
|
|
470
471
|
color: "var(--color-text-muted)"
|
|
471
472
|
} })
|
|
472
473
|
}),
|
|
473
|
-
/* @__PURE__ */
|
|
474
|
-
style:
|
|
474
|
+
/* @__PURE__ */ P("p", {
|
|
475
|
+
style: L.emptyText,
|
|
475
476
|
children: [
|
|
476
|
-
"No widgets found for
|
|
477
|
-
|
|
477
|
+
_("bigconsole.dashboards.widgetPalette.noResultsBefore", "No widgets found for"),
|
|
478
|
+
" \"",
|
|
479
|
+
/* @__PURE__ */ N("strong", { children: v }),
|
|
478
480
|
"\""
|
|
479
481
|
]
|
|
480
482
|
}),
|
|
481
|
-
/* @__PURE__ */
|
|
483
|
+
/* @__PURE__ */ N("button", {
|
|
482
484
|
type: "button",
|
|
483
|
-
onClick: () =>
|
|
484
|
-
style:
|
|
485
|
-
children: "Clear search"
|
|
485
|
+
onClick: () => x(""),
|
|
486
|
+
style: L.clearButton,
|
|
487
|
+
children: _("bigconsole.dashboards.widgetPalette.clearSearch", "Clear search")
|
|
486
488
|
})
|
|
487
489
|
]
|
|
488
490
|
})]
|
|
489
491
|
})
|
|
490
492
|
}),
|
|
491
|
-
/* @__PURE__ */
|
|
492
|
-
style:
|
|
493
|
-
children: [/* @__PURE__ */
|
|
493
|
+
/* @__PURE__ */ P("div", {
|
|
494
|
+
style: L.footer,
|
|
495
|
+
children: [/* @__PURE__ */ P("button", {
|
|
494
496
|
type: "button",
|
|
495
|
-
onClick:
|
|
496
|
-
style:
|
|
497
|
+
onClick: V,
|
|
498
|
+
style: L.browseStoreButton,
|
|
497
499
|
onMouseOver: (e) => {
|
|
498
500
|
e.currentTarget.style.borderColor = "var(--color-action-primary-bg)", e.currentTarget.style.color = "var(--color-action-primary-text)";
|
|
499
501
|
},
|
|
@@ -501,26 +503,26 @@ var I = {
|
|
|
501
503
|
e.currentTarget.style.borderColor = "var(--color-border)", e.currentTarget.style.color = "var(--color-text-secondary)";
|
|
502
504
|
},
|
|
503
505
|
children: [
|
|
504
|
-
/* @__PURE__ */
|
|
506
|
+
/* @__PURE__ */ N(E, { style: {
|
|
505
507
|
width: "15px",
|
|
506
508
|
height: "15px"
|
|
507
509
|
} }),
|
|
508
|
-
"Browse widget store",
|
|
509
|
-
/* @__PURE__ */
|
|
510
|
+
_("bigconsole.dashboards.widgetPalette.browseStore", "Browse widget store"),
|
|
511
|
+
/* @__PURE__ */ N(p, { style: {
|
|
510
512
|
width: "13px",
|
|
511
513
|
height: "13px",
|
|
512
514
|
opacity: .7
|
|
513
515
|
} })
|
|
514
516
|
]
|
|
515
|
-
}), /* @__PURE__ */
|
|
516
|
-
style:
|
|
517
|
-
children: "Drag widgets to position them on the canvas"
|
|
517
|
+
}), /* @__PURE__ */ N("p", {
|
|
518
|
+
style: L.footerText,
|
|
519
|
+
children: _("bigconsole.dashboards.widgetPalette.footerHint", "Drag widgets to position them on the canvas")
|
|
518
520
|
})]
|
|
519
521
|
})
|
|
520
522
|
]
|
|
521
523
|
}) : null;
|
|
522
524
|
});
|
|
523
525
|
//#endregion
|
|
524
|
-
export {
|
|
526
|
+
export { R as default };
|
|
525
527
|
|
|
526
528
|
//# sourceMappingURL=WidgetPalette.js.map
|