@burdenoff/microfe-bigconsole 2026.1001.4 → 2026.1004.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/bigconsole/components/dashboard/CreateDashboardDialog.d.ts.map +1 -1
  2. package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js +220 -161
  3. package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js.map +1 -1
  4. package/dist/bigconsole/components/dashboard/TemplateInstallOptions.d.ts +11 -0
  5. package/dist/bigconsole/components/dashboard/TemplateInstallOptions.d.ts.map +1 -0
  6. package/dist/bigconsole/components/dashboard/TemplateInstallOptions.js +208 -0
  7. package/dist/bigconsole/components/dashboard/TemplateInstallOptions.js.map +1 -0
  8. package/dist/bigconsole/components/dashboard/TemplateLayoutPreview.d.ts +7 -0
  9. package/dist/bigconsole/components/dashboard/TemplateLayoutPreview.d.ts.map +1 -0
  10. package/dist/bigconsole/components/dashboard/TemplateLayoutPreview.js +51 -0
  11. package/dist/bigconsole/components/dashboard/TemplateLayoutPreview.js.map +1 -0
  12. package/dist/bigconsole/hooks/useStoreDashboardTemplates.d.ts +2 -0
  13. package/dist/bigconsole/hooks/useStoreDashboardTemplates.d.ts.map +1 -1
  14. package/dist/bigconsole/hooks/useStoreDashboardTemplates.js +91 -90
  15. package/dist/bigconsole/hooks/useStoreDashboardTemplates.js.map +1 -1
  16. package/dist/bigconsole/pages/DashboardsPage.d.ts.map +1 -1
  17. package/dist/bigconsole/pages/DashboardsPage.js +25 -20
  18. package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
  19. package/dist/bigconsole/pages/DataSinkBuilderPage.js +1 -0
  20. package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
  21. package/dist/bigconsole/pages/InsightsPage.js +1 -0
  22. package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
  23. package/dist/bigconsole/pages/ParserBuilderPage.js +1 -0
  24. package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
  25. package/dist/bigconsole/pages/WorkflowsPage.js +1 -0
  26. package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
  27. package/dist/bigconsole/utils/dashboardTemplateContent.d.ts +10 -0
  28. package/dist/bigconsole/utils/dashboardTemplateContent.d.ts.map +1 -0
  29. package/dist/bigconsole/utils/dashboardTemplateContent.js +36 -0
  30. package/dist/bigconsole/utils/dashboardTemplateContent.js.map +1 -0
  31. package/dist/bigconsole/utils/templateInstallInputs.d.ts +5 -0
  32. package/dist/bigconsole/utils/templateInstallInputs.d.ts.map +1 -0
  33. package/dist/bigconsole/utils/templateInstallInputs.js +22 -0
  34. package/dist/bigconsole/utils/templateInstallInputs.js.map +1 -0
  35. package/dist/generated/global-operations.d.ts +1 -0
  36. package/dist/generated/global-operations.d.ts.map +1 -1
  37. package/dist/generated/global-operations.js +1 -0
  38. package/dist/generated/global-operations.js.map +1 -1
  39. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"CreateDashboardDialog.js","names":[],"sources":["../../../../src/bigconsole/components/dashboard/CreateDashboardDialog.tsx"],"sourcesContent":["/**\n * CreateDashboardDialog Component\n *\n * Modal dialog for creating a new dashboard with name and description.\n * Uses fe-libs shared UI components and semantic tokens for consistent styling.\n * Phase 2: Added TemplatePicker integration for creating from templates.\n */\n\nimport { type FC, memo, useState, useCallback, useEffect, useRef, type KeyboardEvent } from 'react';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@burdenoff/fe-libs/ui';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { Textarea } from '@burdenoff/fe-libs/ui';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { Badge } from '@burdenoff/fe-libs/ui';\nimport { Plus, LayoutDashboard, Copy, X, Tag } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { StoreTemplatePicker } from './StoreTemplatePicker';\nimport { Section } from '../common';\nimport { useStoreDashboardTemplates, type StoreDashboardTemplate } from '../../hooks/useStoreDashboardTemplates';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface CreateDashboardDialogProps {\n isOpen: boolean;\n isCreating?: boolean;\n onClose: () => void;\n onCreate: (data: {\n name: string;\n description: string;\n category: string;\n tags?: string[];\n templateId?: string;\n }) => void | Promise<void>;\n /** Whether to show the template picker option */\n showTemplates?: boolean;\n /**\n * Called after a store template has been installed. Receives the new\n * dashboard id and how many widgets still need a data source, so the host can\n * navigate and surface the \"connect your data\" prompts.\n */\n onTemplateInstalled?: (result: { dashboardId: string; widgetsNeedingData: number }) => void;\n}\n\ntype CreateMode = 'blank' | 'template';\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const CreateDashboardDialog: FC<CreateDashboardDialogProps> = memo(function CreateDashboardDialog({\n isOpen,\n isCreating = false,\n onClose,\n onCreate,\n showTemplates = true,\n onTemplateInstalled,\n}) {\n const { t } = useI18n();\n const {\n templates,\n loading: templatesLoading,\n error: templatesError,\n fetchTemplateContent,\n installTemplate,\n } = useStoreDashboardTemplates({ autoLoad: showTemplates });\n const [installing, setInstalling] = useState(false);\n const [mode, setMode] = useState<CreateMode>('blank');\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [tags, setTags] = useState<string[]>([]);\n const [tagInput, setTagInput] = useState('');\n const [selectedTemplate, setSelectedTemplate] = useState<StoreDashboardTemplate | null>(null);\n const [error, setError] = useState<string | null>(null);\n const nameInputRef = useRef<HTMLInputElement>(null);\n\n // Reset form when dialog opens\n useEffect(() => {\n if (isOpen) {\n setMode('blank');\n setName('');\n setDescription('');\n setTags([]);\n setTagInput('');\n setSelectedTemplate(null);\n setError(null);\n setTimeout(() => {\n nameInputRef.current?.focus();\n }, 100);\n }\n }, [isOpen]);\n\n // Handle adding a tag\n const handleAddTag = useCallback(() => {\n const trimmedTag = tagInput.trim().toLowerCase();\n if (trimmedTag && !tags.includes(trimmedTag) && tags.length < 10) {\n setTags((prev) => [...prev, trimmedTag]);\n setTagInput('');\n }\n }, [tagInput, tags]);\n\n // Handle removing a tag\n const handleRemoveTag = useCallback((tagToRemove: string) => {\n setTags((prev) => prev.filter((tag) => tag !== tagToRemove));\n }, []);\n\n // Handle tag input key press\n const handleTagKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n handleAddTag();\n } else if (e.key === 'Backspace' && !tagInput && tags.length > 0) {\n // Remove last tag when backspace is pressed on empty input\n setTags((prev) => prev.slice(0, -1));\n }\n },\n [handleAddTag, tagInput, tags.length]\n );\n\n // Handle template selection\n const handleTemplateSelect = useCallback((template: StoreDashboardTemplate) => {\n setSelectedTemplate(template);\n // Pre-fill name and description from template\n setName(template.name);\n setDescription(template.description || '');\n }, []);\n\n // Handle form submission\n const handleSubmit = useCallback(\n async (e: React.FormEvent) => {\n e.preventDefault();\n\n // For template mode without selection, show error\n if (mode === 'template' && !selectedTemplate) {\n setError(t('bigconsole.dashboards.createDialog.error.selectTemplate', 'Please select a template'));\n return;\n }\n\n const trimmedName = name.trim();\n if (!trimmedName) {\n setError(t('bigconsole.dashboards.createDialog.error.nameRequired', 'Dashboard name is required'));\n nameInputRef.current?.focus();\n return;\n }\n\n if (trimmedName.length < 3) {\n setError(\n t('bigconsole.dashboards.createDialog.error.nameTooShort', 'Dashboard name must be at least 3 characters')\n );\n nameInputRef.current?.focus();\n return;\n }\n\n if (trimmedName.length > 100) {\n setError(\n t('bigconsole.dashboards.createDialog.error.nameTooLong', 'Dashboard name must be less than 100 characters')\n );\n nameInputRef.current?.focus();\n return;\n }\n\n setError(null);\n\n // Store templates are installed here rather than through onCreate: the\n // install carries data-sink bindings and returns which slots are still\n // unconnected, neither of which the plain create path models.\n if (mode === 'template' && selectedTemplate) {\n setInstalling(true);\n try {\n const content = await fetchTemplateContent(selectedTemplate.id);\n if (!content) {\n setError(\n t(\n 'bigconsole.dashboards.createDialog.error.noDefinition',\n 'This template has no dashboard definition attached and cannot be installed.'\n )\n );\n return;\n }\n\n const result = await installTemplate({\n templateId: selectedTemplate.id,\n templateName: selectedTemplate.name,\n content,\n name: trimmedName,\n });\n\n if (!result.success) {\n setError(\n result.errorMessage ??\n t('bigconsole.dashboards.createDialog.error.installFailed', 'Failed to create dashboard from template.')\n );\n return;\n }\n\n if (result.dashboardId) {\n onTemplateInstalled?.({\n dashboardId: result.dashboardId,\n widgetsNeedingData: result.widgetsNeedingData,\n });\n }\n onClose();\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : t('bigconsole.dashboards.createDialog.error.installFailed', 'Failed to create dashboard from template.')\n );\n } finally {\n setInstalling(false);\n }\n return;\n }\n\n try {\n await onCreate({\n name: trimmedName,\n description: description.trim(),\n category: 'CUSTOM',\n tags: tags.length > 0 ? tags : undefined,\n });\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : t(\n 'bigconsole.dashboards.createDialog.error.createFailed',\n 'Failed to create dashboard. Please try again.'\n )\n );\n }\n },\n [\n name,\n description,\n tags,\n mode,\n selectedTemplate,\n onCreate,\n onClose,\n fetchTemplateContent,\n installTemplate,\n onTemplateInstalled,\n t,\n ]\n );\n\n return (\n <Dialog open={isOpen} onOpenChange={(open) => !open && !isCreating && onClose()}>\n <DialogContent style={{ maxWidth: mode === 'template' ? '900px' : '480px', width: '100%', padding: 0 }}>\n {/* Header */}\n <DialogHeader style={{ padding: 'var(--space-pagePadding) var(--space-pagePadding) 0' }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-formGap)' }}>\n <div\n style={{\n display: 'flex',\n height: 'var(--size-controlHeight-lg)',\n width: 'var(--size-controlHeight-lg)',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n borderRadius: 'var(--radius-card)',\n backgroundColor: 'var(--color-bg-accentSubtle)',\n }}\n >\n <LayoutDashboard\n aria-hidden=\"true\"\n style={{\n height: 'var(--size-icon-lg)',\n width: 'var(--size-icon-lg)',\n color: 'var(--color-action-primary-bg)',\n }}\n />\n </div>\n <div>\n <DialogTitle\n style={{\n fontSize: 'var(--font-size-heading-h4)',\n fontWeight: 'var(--font-weight-bold)',\n color: 'var(--color-text-primary)',\n margin: 0,\n }}\n >\n {t('bigconsole.dashboards.createDialog.title', 'Create New Dashboard')}\n </DialogTitle>\n <DialogDescription\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-secondary)',\n margin: 'var(--space-controlGap) 0 0 0',\n }}\n >\n {t('bigconsole.dashboards.createDialog.subtitle', 'Create a new dashboard to visualize your data')}\n </DialogDescription>\n </div>\n </div>\n </DialogHeader>\n\n <form onSubmit={handleSubmit}>\n {/* Mode Selection Tabs */}\n {showTemplates && (\n <div style={{ padding: 'var(--space-pagePadding) var(--space-pagePadding) 0' }}>\n <div\n role=\"group\"\n aria-label=\"How to start\"\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: 'var(--space-controlGap)',\n padding: 'var(--space-controlGap)',\n backgroundColor: 'var(--color-bg-sunken)',\n borderRadius: 'var(--radius-button)',\n }}\n >\n <button\n type=\"button\"\n onClick={() => {\n setMode('blank');\n setSelectedTemplate(null);\n }}\n style={{\n flex: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 'var(--space-iconGap)',\n padding: 'var(--space-controlGap) var(--space-formGap)',\n borderRadius: 'var(--radius-button)',\n border: 'none',\n backgroundColor: mode === 'blank' ? 'var(--color-bg-surface)' : 'transparent',\n color: mode === 'blank' ? 'var(--color-text-primary)' : 'var(--color-text-secondary)',\n fontWeight: mode === 'blank' ? 'var(--font-weight-semibold)' : 'var(--font-weight-regular)',\n fontSize: 'var(--font-size-body-sm)',\n cursor: 'pointer',\n boxShadow: mode === 'blank' ? 'var(--shadow-elevation-1)' : 'none',\n transition: 'all 0.15s ease',\n }}\n >\n <Plus style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n {t('bigconsole.dashboards.createDialog.tab.blank', 'Blank Dashboard')}\n </button>\n <button\n type=\"button\"\n onClick={() => setMode('template')}\n style={{\n flex: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 'var(--space-iconGap)',\n padding: 'var(--space-controlGap) var(--space-formGap)',\n borderRadius: 'var(--radius-button)',\n border: 'none',\n backgroundColor: mode === 'template' ? 'var(--color-bg-surface)' : 'transparent',\n color: mode === 'template' ? 'var(--color-text-primary)' : 'var(--color-text-secondary)',\n fontWeight: mode === 'template' ? 'var(--font-weight-semibold)' : 'var(--font-weight-regular)',\n fontSize: 'var(--font-size-body-sm)',\n cursor: 'pointer',\n boxShadow: mode === 'template' ? 'var(--shadow-elevation-1)' : 'none',\n transition: 'all 0.15s ease',\n }}\n >\n <Copy style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n {t('bigconsole.dashboards.createDialog.tab.template', 'From Template')}\n </button>\n </div>\n </div>\n )}\n\n {/* Template Picker (when in template mode) */}\n {mode === 'template' && (\n <div style={{ padding: 'var(--space-pagePadding)', maxHeight: '400px', overflowY: 'auto' }}>\n <StoreTemplatePicker\n templates={templates}\n loading={templatesLoading}\n error={templatesError}\n selectedTemplateId={selectedTemplate?.id}\n onSelect={handleTemplateSelect}\n />\n </div>\n )}\n\n {/* Form Content */}\n <div style={{ padding: 'var(--space-pagePadding)' }}>\n {/*\n The fields carry no surface of their own — the dialog is already a\n raised surface — but they still need a name, so the group is a `bare`\n section. It gives the form a heading screen readers can land on and\n tells the eye where the template picker ends and the form begins.\n */}\n <Section\n headingLevel={3}\n emphasis=\"bare\"\n padding=\"none\"\n title=\"Dashboard details\"\n description=\"Name it now — everything else can change later.\"\n data-testid=\"create-dashboard-details\"\n >\n {/* Name Field */}\n <div style={{ marginBottom: 'var(--space-formGap)' }}>\n <label\n htmlFor=\"dashboard-name\"\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n {t('bigconsole.dashboards.createDialog.field.name', 'Dashboard Name')}\n <span style={{ color: 'var(--color-status-error-text)', marginLeft: 'var(--space-controlGap)' }}>\n *\n </span>\n </label>\n <Input\n ref={nameInputRef}\n id=\"dashboard-name\"\n type=\"text\"\n value={name}\n onChange={(e) => {\n setName(e.target.value);\n if (error) setError(null);\n }}\n placeholder={t('bigconsole.dashboards.createDialog.field.namePlaceholder', 'Enter dashboard name')}\n disabled={isCreating || installing}\n style={{\n height: 'var(--size-controlHeight-md)',\n fontSize: 'var(--font-size-body-sm)',\n borderColor: error ? 'var(--color-status-error-border)' : undefined,\n }}\n />\n {error && (\n <p\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-status-error-text)',\n marginTop: 'var(--space-controlGap)',\n fontWeight: 'var(--font-weight-medium)',\n }}\n >\n {error}\n </p>\n )}\n </div>\n\n {/* Description Field */}\n <div style={{ marginBottom: 'var(--space-formGap)' }}>\n <label\n htmlFor=\"dashboard-description\"\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n {t('bigconsole.dashboards.createDialog.field.description', 'Description')}\n <span\n style={{\n color: 'var(--color-text-muted)',\n fontWeight: 'var(--font-weight-regular)',\n marginLeft: 'var(--space-controlGap)',\n }}\n >\n {t('bigconsole.dashboards.createDialog.field.optional', '(optional)')}\n </span>\n </label>\n <Textarea\n id=\"dashboard-description\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder={t(\n 'bigconsole.dashboards.createDialog.field.descriptionPlaceholder',\n 'Enter a brief description for this dashboard'\n )}\n rows={3}\n disabled={isCreating || installing}\n style={{\n fontSize: 'var(--font-size-body-sm)',\n resize: 'none',\n }}\n />\n </div>\n\n {/* Tags Field */}\n <div>\n <label\n htmlFor=\"dashboard-tags\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-iconGap)',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n <Tag style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n {t('bigconsole.dashboards.createDialog.field.tags', 'Tags')}\n <span\n style={{\n color: 'var(--color-text-muted)',\n fontWeight: 'var(--font-weight-regular)',\n }}\n >\n {t('bigconsole.dashboards.createDialog.field.tagsOptional', '(optional, max 10)')}\n </span>\n </label>\n {/* Tag chips display */}\n {tags.length > 0 && (\n <div\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: 'var(--space-controlGap)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n {tags.map((tag) => (\n <Badge\n key={tag}\n variant=\"secondary\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n paddingRight: '4px',\n }}\n >\n {tag}\n <button\n type=\"button\"\n onClick={() => handleRemoveTag(tag)}\n disabled={isCreating || installing}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: '2px',\n borderRadius: '50%',\n color: 'inherit',\n opacity: 0.7,\n }}\n onMouseOver={(e) => (e.currentTarget.style.opacity = '1')}\n onMouseOut={(e) => (e.currentTarget.style.opacity = '0.7')}\n >\n <X style={{ height: '12px', width: '12px' }} />\n </button>\n </Badge>\n ))}\n </div>\n )}\n {/* Tag input */}\n <div style={{ display: 'flex', gap: 'var(--space-controlGap)' }}>\n <Input\n id=\"dashboard-tags\"\n type=\"text\"\n value={tagInput}\n onChange={(e) => setTagInput(e.target.value)}\n onKeyDown={handleTagKeyDown}\n placeholder={\n tags.length >= 10\n ? t('bigconsole.dashboards.createDialog.field.tagsMaxReached', 'Max tags reached')\n : t(\n 'bigconsole.dashboards.createDialog.field.tagsInputPlaceholder',\n 'Type a tag and press Enter'\n )\n }\n disabled={isCreating || installing || tags.length >= 10}\n style={{\n flex: 1,\n height: 'var(--size-controlHeight-md)',\n fontSize: 'var(--font-size-body-sm)',\n }}\n />\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={handleAddTag}\n disabled={isCreating || installing || !tagInput.trim() || tags.length >= 10}\n style={{ height: 'var(--size-controlHeight-md)' }}\n >\n {t('bigconsole.dashboards.createDialog.action.addTag', 'Add')}\n </Button>\n </div>\n <p\n style={{\n // `--font-size-body-xs` is not a real token — the declaration is\n // dropped and the hint inherits body size. `--font-size-xs` is.\n fontSize: 'var(--font-size-xs)',\n color: 'var(--color-text-muted)',\n marginTop: 'var(--space-controlGap)',\n }}\n >\n {t('bigconsole.dashboards.createDialog.field.tagsHelp', 'Press Enter to add a tag, or click Add')}\n </p>\n </div>\n </Section>\n </div>\n\n {/* Footer */}\n <DialogFooter\n style={{\n padding: 'var(--space-formGap) var(--space-pagePadding)',\n borderTop: '1px solid var(--color-border)',\n backgroundColor: 'var(--color-bg-sunken)',\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 'var(--space-controlGap)',\n }}\n >\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={onClose}\n disabled={isCreating || installing}\n style={{ height: 'var(--size-controlHeight-md)' }}\n >\n {t('bigconsole.dashboards.createDialog.action.cancel', 'Cancel')}\n </Button>\n <Button\n type=\"submit\"\n disabled={isCreating || installing || !name.trim()}\n style={{\n height: 'var(--size-controlHeight-md)',\n backgroundColor: 'var(--color-action-primary-bg)',\n }}\n >\n {isCreating || installing ? (\n <span style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <Spinner style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n {t('bigconsole.dashboards.createDialog.action.creating', 'Creating...')}\n </span>\n ) : (\n <span style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <Plus style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n {t('bigconsole.dashboards.createDialog.action.create', 'Create Dashboard')}\n </span>\n )}\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n );\n});\n\nexport default CreateDashboardDialog;\n"],"mappings":"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"}
1
+ {"version":3,"file":"CreateDashboardDialog.js","names":[],"sources":["../../../../src/bigconsole/components/dashboard/CreateDashboardDialog.tsx"],"sourcesContent":["/**\n * CreateDashboardDialog Component\n *\n * Modal dialog for creating a new dashboard with name and description.\n * Uses fe-libs shared UI components and semantic tokens for consistent styling.\n * Phase 2: Added TemplatePicker integration for creating from templates.\n */\n\nimport { type FC, memo, useState, useCallback, useEffect, useRef, type KeyboardEvent } from 'react';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@burdenoff/fe-libs/ui';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { Textarea } from '@burdenoff/fe-libs/ui';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { Badge } from '@burdenoff/fe-libs/ui';\nimport { Plus, LayoutDashboard, Copy, X, Tag } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { StoreTemplatePicker } from './StoreTemplatePicker';\nimport { TemplateInstallOptions } from './TemplateInstallOptions';\nimport { TemplateLayoutPreview } from './TemplateLayoutPreview';\nimport { templateInputDefaults, templateInputError } from '../../utils/templateInstallInputs';\nimport type { DashboardTemplateContent } from '../../hooks/useStoreDashboardTemplates';\nimport { useActiveContext } from '@burdenoff/fe-libs/shared/providers/shell/ActiveContextProvider';\nimport { Section } from '../common';\nimport { useStoreDashboardTemplates, type StoreDashboardTemplate } from '../../hooks/useStoreDashboardTemplates';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface CreateDashboardDialogProps {\n isOpen: boolean;\n isCreating?: boolean;\n onClose: () => void;\n onCreate: (data: {\n name: string;\n description: string;\n category: string;\n tags?: string[];\n templateId?: string;\n }) => void | Promise<void>;\n /** Whether to show the template picker option */\n showTemplates?: boolean;\n /**\n * Called after a store template has been installed. Receives the new\n * dashboard id and how many widgets still need a data source, so the host can\n * navigate and surface the \"connect your data\" prompts.\n */\n onTemplateInstalled?: (result: { dashboardId: string; widgetsNeedingData: number }) => void;\n}\n\ntype CreateMode = 'blank' | 'template';\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const CreateDashboardDialog: FC<CreateDashboardDialogProps> = memo(function CreateDashboardDialog({\n isOpen,\n isCreating = false,\n onClose,\n onCreate,\n showTemplates = true,\n onTemplateInstalled,\n}) {\n const { t } = useI18n();\n const {\n templates,\n loading: templatesLoading,\n error: templatesError,\n fetchTemplateContent,\n installTemplate,\n } = useStoreDashboardTemplates({ autoLoad: showTemplates });\n const [installing, setInstalling] = useState(false);\n const { workspaceId } = useActiveContext();\n const activeWorkspaceRef = useRef(workspaceId);\n activeWorkspaceRef.current = workspaceId;\n const [templateContent, setTemplateContent] = useState<DashboardTemplateContent | null>(null);\n const [contentOwner, setContentOwner] = useState<string | null>(null);\n const [contentLoading, setContentLoading] = useState(false);\n const [dataSinkBindings, setDataSinkBindings] = useState<Record<string, string>>({});\n const [inputValues, setInputValues] = useState<Record<string, unknown>>({});\n const [mode, setMode] = useState<CreateMode>('blank');\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [tags, setTags] = useState<string[]>([]);\n const [tagInput, setTagInput] = useState('');\n const [selectedTemplate, setSelectedTemplate] = useState<StoreDashboardTemplate | null>(null);\n const [error, setError] = useState<string | null>(null);\n const nameInputRef = useRef<HTMLInputElement>(null);\n const ownedContent = contentOwner === `${selectedTemplate?.id}:${workspaceId}` ? templateContent : null;\n\n // Reset form when dialog opens\n useEffect(() => {\n if (isOpen) {\n setMode('blank');\n setName('');\n setDescription('');\n setTags([]);\n setTagInput('');\n setSelectedTemplate(null);\n setError(null);\n setTimeout(() => {\n nameInputRef.current?.focus();\n }, 100);\n }\n }, [isOpen]);\n\n // Handle adding a tag\n const handleAddTag = useCallback(() => {\n const trimmedTag = tagInput.trim().toLowerCase();\n if (trimmedTag && !tags.includes(trimmedTag) && tags.length < 10) {\n setTags((prev) => [...prev, trimmedTag]);\n setTagInput('');\n }\n }, [tagInput, tags]);\n\n useEffect(() => {\n let cancelled = false;\n setTemplateContent(null);\n setDataSinkBindings({});\n setInputValues({});\n setContentLoading(Boolean(selectedTemplate));\n if (!selectedTemplate || !isOpen) return;\n void fetchTemplateContent(selectedTemplate.id).then((content) => {\n if (cancelled) return;\n setTemplateContent(content);\n setContentOwner(`${selectedTemplate.id}:${workspaceId}`);\n setContentLoading(false);\n setInputValues(content ? templateInputDefaults(content.requiredInputs) : {});\n if (!content)\n setError(\n t(\n 'bigconsole.dashboards.createDialog.error.noDefinition',\n 'This template has no dashboard definition attached and cannot be installed.'\n )\n );\n });\n return () => {\n cancelled = true;\n };\n }, [selectedTemplate, fetchTemplateContent, workspaceId, isOpen, t]);\n\n // Handle removing a tag\n const handleRemoveTag = useCallback((tagToRemove: string) => {\n setTags((prev) => prev.filter((tag) => tag !== tagToRemove));\n }, []);\n\n // Handle tag input key press\n const handleTagKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n handleAddTag();\n } else if (e.key === 'Backspace' && !tagInput && tags.length > 0) {\n // Remove last tag when backspace is pressed on empty input\n setTags((prev) => prev.slice(0, -1));\n }\n },\n [handleAddTag, tagInput, tags.length]\n );\n\n // Handle template selection\n const handleTemplateSelect = useCallback((template: StoreDashboardTemplate) => {\n setSelectedTemplate(template);\n setError(null);\n // Pre-fill name and description from template\n setName(template.name);\n setDescription(template.description || '');\n }, []);\n\n // Handle form submission\n const handleSubmit = useCallback(\n async (e: React.FormEvent) => {\n e.preventDefault();\n\n // For template mode without selection, show error\n if (mode === 'template' && !selectedTemplate) {\n setError(t('bigconsole.dashboards.createDialog.error.selectTemplate', 'Please select a template'));\n return;\n }\n\n const trimmedName = name.trim();\n if (!trimmedName) {\n setError(t('bigconsole.dashboards.createDialog.error.nameRequired', 'Dashboard name is required'));\n nameInputRef.current?.focus();\n return;\n }\n\n if (trimmedName.length < 3) {\n setError(\n t('bigconsole.dashboards.createDialog.error.nameTooShort', 'Dashboard name must be at least 3 characters')\n );\n nameInputRef.current?.focus();\n return;\n }\n\n if (trimmedName.length > 100) {\n setError(\n t('bigconsole.dashboards.createDialog.error.nameTooLong', 'Dashboard name must be less than 100 characters')\n );\n nameInputRef.current?.focus();\n return;\n }\n\n setError(null);\n\n // Store templates are installed here rather than through onCreate: the\n // install carries data-sink bindings and returns which slots are still\n // unconnected, neither of which the plain create path models.\n if (mode === 'template' && selectedTemplate) {\n setInstalling(true);\n try {\n const content = await fetchTemplateContent(selectedTemplate.id);\n if (activeWorkspaceRef.current !== workspaceId) {\n setError(\n t(\n 'bigconsole.dashboards.templateSetup.workspaceChanged',\n 'The workspace changed. Review the template setup before creating your dashboard.'\n )\n );\n return;\n }\n if (!content) {\n setError(\n t(\n 'bigconsole.dashboards.createDialog.error.noDefinition',\n 'This template has no dashboard definition attached and cannot be installed.'\n )\n );\n return;\n }\n\n const inputError = templateInputError(content.requiredInputs, inputValues, t);\n if (inputError) {\n setError(inputError);\n return;\n }\n const result = await installTemplate({\n templateId: selectedTemplate.id,\n templateName: selectedTemplate.name,\n content,\n name: trimmedName,\n description: description.trim(),\n tags,\n dataSinkBindings: Object.entries(dataSinkBindings)\n .filter(([, id]) => id)\n .map(([slot, dataSinkId]) => ({ slot, dataSinkId })),\n inputValues,\n });\n\n if (!result.success) {\n setError(\n result.errorMessage ??\n t('bigconsole.dashboards.createDialog.error.installFailed', 'Failed to create dashboard from template.')\n );\n return;\n }\n\n if (result.dashboardId) {\n onTemplateInstalled?.({\n dashboardId: result.dashboardId,\n widgetsNeedingData: result.widgetsNeedingData,\n });\n }\n onClose();\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : t('bigconsole.dashboards.createDialog.error.installFailed', 'Failed to create dashboard from template.')\n );\n } finally {\n setInstalling(false);\n }\n return;\n }\n\n try {\n await onCreate({\n name: trimmedName,\n description: description.trim(),\n category: 'CUSTOM',\n tags: tags.length > 0 ? tags : undefined,\n });\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : t(\n 'bigconsole.dashboards.createDialog.error.createFailed',\n 'Failed to create dashboard. Please try again.'\n )\n );\n }\n },\n [\n name,\n description,\n tags,\n mode,\n selectedTemplate,\n workspaceId,\n dataSinkBindings,\n inputValues,\n onCreate,\n onClose,\n fetchTemplateContent,\n installTemplate,\n onTemplateInstalled,\n t,\n ]\n );\n\n return (\n <Dialog open={isOpen} onOpenChange={(open) => !open && !isCreating && !installing && onClose()}>\n <DialogContent style={{ maxWidth: mode === 'template' ? '900px' : '480px', width: '100%', padding: 0 }}>\n {/* Header */}\n <DialogHeader style={{ padding: 'var(--space-pagePadding) var(--space-pagePadding) 0' }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-formGap)' }}>\n <div\n style={{\n display: 'flex',\n height: 'var(--size-controlHeight-lg)',\n width: 'var(--size-controlHeight-lg)',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n borderRadius: 'var(--radius-card)',\n backgroundColor: 'var(--color-bg-accentSubtle)',\n }}\n >\n <LayoutDashboard\n aria-hidden=\"true\"\n style={{\n height: 'var(--size-icon-lg)',\n width: 'var(--size-icon-lg)',\n color: 'var(--color-action-primary-bg)',\n }}\n />\n </div>\n <div>\n <DialogTitle\n style={{\n fontSize: 'var(--font-size-heading-h4)',\n fontWeight: 'var(--font-weight-bold)',\n color: 'var(--color-text-primary)',\n margin: 0,\n }}\n >\n {t('bigconsole.dashboards.createDialog.title', 'Create New Dashboard')}\n </DialogTitle>\n <DialogDescription\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-secondary)',\n margin: 'var(--space-controlGap) 0 0 0',\n }}\n >\n {t('bigconsole.dashboards.createDialog.subtitle', 'Create a new dashboard to visualize your data')}\n </DialogDescription>\n </div>\n </div>\n </DialogHeader>\n\n <form onSubmit={handleSubmit}>\n {/* Mode Selection Tabs */}\n {showTemplates && (\n <div style={{ padding: 'var(--space-pagePadding) var(--space-pagePadding) 0' }}>\n <div\n role=\"group\"\n aria-label=\"How to start\"\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: 'var(--space-controlGap)',\n padding: 'var(--space-controlGap)',\n backgroundColor: 'var(--color-bg-sunken)',\n borderRadius: 'var(--radius-button)',\n }}\n >\n <button\n type=\"button\"\n disabled={isCreating || installing}\n onClick={() => {\n setMode('blank');\n setSelectedTemplate(null);\n }}\n style={{\n flex: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 'var(--space-iconGap)',\n padding: 'var(--space-controlGap) var(--space-formGap)',\n borderRadius: 'var(--radius-button)',\n border: 'none',\n backgroundColor: mode === 'blank' ? 'var(--color-bg-surface)' : 'transparent',\n color: mode === 'blank' ? 'var(--color-text-primary)' : 'var(--color-text-secondary)',\n fontWeight: mode === 'blank' ? 'var(--font-weight-semibold)' : 'var(--font-weight-regular)',\n fontSize: 'var(--font-size-body-sm)',\n cursor: 'pointer',\n boxShadow: mode === 'blank' ? 'var(--shadow-elevation-1)' : 'none',\n transition: 'all 0.15s ease',\n }}\n >\n <Plus style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n {t('bigconsole.dashboards.createDialog.tab.blank', 'Blank Dashboard')}\n </button>\n <button\n type=\"button\"\n disabled={isCreating || installing}\n onClick={() => setMode('template')}\n style={{\n flex: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 'var(--space-iconGap)',\n padding: 'var(--space-controlGap) var(--space-formGap)',\n borderRadius: 'var(--radius-button)',\n border: 'none',\n backgroundColor: mode === 'template' ? 'var(--color-bg-surface)' : 'transparent',\n color: mode === 'template' ? 'var(--color-text-primary)' : 'var(--color-text-secondary)',\n fontWeight: mode === 'template' ? 'var(--font-weight-semibold)' : 'var(--font-weight-regular)',\n fontSize: 'var(--font-size-body-sm)',\n cursor: 'pointer',\n boxShadow: mode === 'template' ? 'var(--shadow-elevation-1)' : 'none',\n transition: 'all 0.15s ease',\n }}\n >\n <Copy style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n {t('bigconsole.dashboards.createDialog.tab.template', 'From Template')}\n </button>\n </div>\n </div>\n )}\n\n {/* Template Picker (when in template mode) */}\n {mode === 'template' && (\n <div style={{ padding: 'var(--space-pagePadding)', maxHeight: '400px', overflowY: 'auto' }}>\n <StoreTemplatePicker\n templates={templates}\n loading={templatesLoading}\n error={templatesError}\n selectedTemplateId={selectedTemplate?.id}\n onSelect={handleTemplateSelect}\n />\n </div>\n )}\n\n {mode === 'template' && selectedTemplate && (\n <div style={{ padding: 'var(--space-pagePadding)' }}>\n {contentLoading && <Spinner />}\n {ownedContent && (\n <>\n <TemplateLayoutPreview content={ownedContent} />\n <TemplateInstallOptions\n content={ownedContent}\n bindings={dataSinkBindings}\n onBindingChange={(slot, id) => setDataSinkBindings((current) => ({ ...current, [slot]: id }))}\n inputValues={inputValues}\n onInputChange={(name, value) => setInputValues((current) => ({ ...current, [name]: value }))}\n disabled={isCreating || installing}\n />\n </>\n )}\n </div>\n )}\n\n {/* Form Content */}\n <div style={{ padding: 'var(--space-pagePadding)' }}>\n {/*\n The fields carry no surface of their own — the dialog is already a\n raised surface — but they still need a name, so the group is a `bare`\n section. It gives the form a heading screen readers can land on and\n tells the eye where the template picker ends and the form begins.\n */}\n <Section\n headingLevel={3}\n emphasis=\"bare\"\n padding=\"none\"\n title=\"Dashboard details\"\n description=\"Name it now — everything else can change later.\"\n data-testid=\"create-dashboard-details\"\n >\n {/* Name Field */}\n <div style={{ marginBottom: 'var(--space-formGap)' }}>\n <label\n htmlFor=\"dashboard-name\"\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n {t('bigconsole.dashboards.createDialog.field.name', 'Dashboard Name')}\n <span style={{ color: 'var(--color-status-error-text)', marginLeft: 'var(--space-controlGap)' }}>\n *\n </span>\n </label>\n <Input\n ref={nameInputRef}\n id=\"dashboard-name\"\n type=\"text\"\n value={name}\n onChange={(e) => {\n setName(e.target.value);\n if (error) setError(null);\n }}\n placeholder={t('bigconsole.dashboards.createDialog.field.namePlaceholder', 'Enter dashboard name')}\n disabled={isCreating || installing}\n style={{\n height: 'var(--size-controlHeight-md)',\n fontSize: 'var(--font-size-body-sm)',\n borderColor: error ? 'var(--color-status-error-border)' : undefined,\n }}\n />\n {error && (\n <p\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-status-error-text)',\n marginTop: 'var(--space-controlGap)',\n fontWeight: 'var(--font-weight-medium)',\n }}\n >\n {error}\n </p>\n )}\n </div>\n\n {/* Description Field */}\n <div style={{ marginBottom: 'var(--space-formGap)' }}>\n <label\n htmlFor=\"dashboard-description\"\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n {t('bigconsole.dashboards.createDialog.field.description', 'Description')}\n <span\n style={{\n color: 'var(--color-text-muted)',\n fontWeight: 'var(--font-weight-regular)',\n marginLeft: 'var(--space-controlGap)',\n }}\n >\n {t('bigconsole.dashboards.createDialog.field.optional', '(optional)')}\n </span>\n </label>\n <Textarea\n id=\"dashboard-description\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder={t(\n 'bigconsole.dashboards.createDialog.field.descriptionPlaceholder',\n 'Enter a brief description for this dashboard'\n )}\n rows={3}\n disabled={isCreating || installing}\n style={{\n fontSize: 'var(--font-size-body-sm)',\n resize: 'none',\n }}\n />\n </div>\n\n {/* Tags Field */}\n <div>\n <label\n htmlFor=\"dashboard-tags\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-iconGap)',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n <Tag style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n {t('bigconsole.dashboards.createDialog.field.tags', 'Tags')}\n <span\n style={{\n color: 'var(--color-text-muted)',\n fontWeight: 'var(--font-weight-regular)',\n }}\n >\n {t('bigconsole.dashboards.createDialog.field.tagsOptional', '(optional, max 10)')}\n </span>\n </label>\n {/* Tag chips display */}\n {tags.length > 0 && (\n <div\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: 'var(--space-controlGap)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n {tags.map((tag) => (\n <Badge\n key={tag}\n variant=\"secondary\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n paddingRight: '4px',\n }}\n >\n {tag}\n <button\n type=\"button\"\n onClick={() => handleRemoveTag(tag)}\n disabled={isCreating || installing}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: '2px',\n borderRadius: '50%',\n color: 'inherit',\n opacity: 0.7,\n }}\n onMouseOver={(e) => (e.currentTarget.style.opacity = '1')}\n onMouseOut={(e) => (e.currentTarget.style.opacity = '0.7')}\n >\n <X style={{ height: '12px', width: '12px' }} />\n </button>\n </Badge>\n ))}\n </div>\n )}\n {/* Tag input */}\n <div style={{ display: 'flex', gap: 'var(--space-controlGap)' }}>\n <Input\n id=\"dashboard-tags\"\n type=\"text\"\n value={tagInput}\n onChange={(e) => setTagInput(e.target.value)}\n onKeyDown={handleTagKeyDown}\n placeholder={\n tags.length >= 10\n ? t('bigconsole.dashboards.createDialog.field.tagsMaxReached', 'Max tags reached')\n : t(\n 'bigconsole.dashboards.createDialog.field.tagsInputPlaceholder',\n 'Type a tag and press Enter'\n )\n }\n disabled={isCreating || installing || tags.length >= 10}\n style={{\n flex: 1,\n height: 'var(--size-controlHeight-md)',\n fontSize: 'var(--font-size-body-sm)',\n }}\n />\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={handleAddTag}\n disabled={isCreating || installing || !tagInput.trim() || tags.length >= 10}\n style={{ height: 'var(--size-controlHeight-md)' }}\n >\n {t('bigconsole.dashboards.createDialog.action.addTag', 'Add')}\n </Button>\n </div>\n <p\n style={{\n // `--font-size-body-xs` is not a real token — the declaration is\n // dropped and the hint inherits body size. `--font-size-xs` is.\n fontSize: 'var(--font-size-xs)',\n color: 'var(--color-text-muted)',\n marginTop: 'var(--space-controlGap)',\n }}\n >\n {t('bigconsole.dashboards.createDialog.field.tagsHelp', 'Press Enter to add a tag, or click Add')}\n </p>\n </div>\n </Section>\n </div>\n\n {/* Footer */}\n <DialogFooter\n style={{\n padding: 'var(--space-formGap) var(--space-pagePadding)',\n borderTop: '1px solid var(--color-border)',\n backgroundColor: 'var(--color-bg-sunken)',\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 'var(--space-controlGap)',\n }}\n >\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={onClose}\n disabled={isCreating || installing}\n style={{ height: 'var(--size-controlHeight-md)' }}\n >\n {t('bigconsole.dashboards.createDialog.action.cancel', 'Cancel')}\n </Button>\n <Button\n type=\"submit\"\n disabled={\n isCreating ||\n installing ||\n !name.trim() ||\n (mode === 'template' && (!selectedTemplate || !ownedContent || contentLoading))\n }\n style={{\n height: 'var(--size-controlHeight-md)',\n backgroundColor: 'var(--color-action-primary-bg)',\n }}\n >\n {isCreating || installing ? (\n <span style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <Spinner style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n {t('bigconsole.dashboards.createDialog.action.creating', 'Creating...')}\n </span>\n ) : (\n <span style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <Plus style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n {t('bigconsole.dashboards.createDialog.action.create', 'Create Dashboard')}\n </span>\n )}\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n );\n});\n\nexport default CreateDashboardDialog;\n"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { DashboardTemplateContent } from '../../hooks/useStoreDashboardTemplates';
2
+
3
+ export declare function TemplateInstallOptions({ content, bindings, onBindingChange, inputValues, onInputChange, disabled, }: {
4
+ content: DashboardTemplateContent;
5
+ bindings: Record<string, string>;
6
+ onBindingChange: (slot: string, id: string) => void;
7
+ inputValues: Record<string, unknown>;
8
+ onInputChange: (name: string, value: unknown) => void;
9
+ disabled: boolean;
10
+ }): import("react").JSX.Element;
11
+ //# sourceMappingURL=TemplateInstallOptions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TemplateInstallOptions.d.ts","sourceRoot":"","sources":["../../../../src/bigconsole/components/dashboard/TemplateInstallOptions.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAEvF,wBAAgB,sBAAsB,CAAC,EACrC,OAAO,EACP,QAAQ,EACR,eAAe,EACf,WAAW,EACX,aAAa,EACb,QAAQ,GACT,EAAE;IACD,OAAO,EAAE,wBAAwB,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACtD,QAAQ,EAAE,OAAO,CAAC;CACnB,+BAgNA"}
@@ -0,0 +1,208 @@
1
+ import { ListDataSinksDocument as e } from "../../../generated/wspace-operations.js";
2
+ import { BIGCONSOLE_PERMISSIONS as t } from "../../../constants/permissions.js";
3
+ import { useEffect as n, useId as r, useRef as i, useState as a } from "react";
4
+ import { Input as o } from "@burdenoff/fe-libs/ui";
5
+ import { useApolloClient as s } from "@apollo/client/react";
6
+ import { jsx as c, jsxs as l } from "react/jsx-runtime";
7
+ import { useI18n as u } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
8
+ import { useActiveContext as d } from "@burdenoff/fe-libs/shared/providers/shell/ActiveContextProvider";
9
+ import { usePermissions as f } from "@burdenoff/fe-libs/shared/providers/shell/PermissionProvider";
10
+ //#region src/bigconsole/components/dashboard/TemplateInstallOptions.tsx
11
+ function p({ content: p, bindings: m, onBindingChange: h, inputValues: g, onInputChange: _, disabled: v }) {
12
+ let y = r(), { t: b } = u(), x = s(), { workspaceId: S } = d(), { hasPermission: C, isLoading: w } = f(), T = !w && C(t.DATASINK_READ), E = p.requiredDataSinks.length > 0, D = `${S}:${T}:${E}`, O = i(D);
13
+ O.current = D;
14
+ let [k, A] = a(0), [j, M] = a(null), N = j?.owner === D ? j.cursor : void 0, [P, F] = a(null);
15
+ n(() => {
16
+ M(null), F(null);
17
+ }, [D]), n(() => {
18
+ let t = !1;
19
+ if (!(!S || !E || !T)) return F((e) => ({
20
+ ...e,
21
+ owner: D,
22
+ loading: !0,
23
+ error: !1
24
+ })), x.query({
25
+ query: e,
26
+ variables: {
27
+ isActive: !0,
28
+ first: 100,
29
+ ...N ? { after: N } : {}
30
+ },
31
+ fetchPolicy: "network-only"
32
+ }).then((e) => {
33
+ t || O.current !== D || F((t) => {
34
+ let n = e.data;
35
+ if (!n) return {
36
+ owner: D,
37
+ error: !0,
38
+ loading: !1
39
+ };
40
+ let r = N && t?.owner === D ? t.data?.listDataSinks.edges ?? [] : [], i = [...new Map([...r, ...n.listDataSinks.edges].map((e) => [e.node.id, e])).values()];
41
+ return {
42
+ owner: D,
43
+ data: {
44
+ ...n,
45
+ listDataSinks: {
46
+ ...n.listDataSinks,
47
+ edges: i
48
+ }
49
+ },
50
+ loading: !1
51
+ };
52
+ });
53
+ }).catch(() => {
54
+ !t && O.current === D && F((e) => ({
55
+ ...e,
56
+ owner: D,
57
+ error: !0,
58
+ loading: !1
59
+ }));
60
+ }), () => {
61
+ t = !0;
62
+ };
63
+ }, [
64
+ x,
65
+ S,
66
+ E,
67
+ T,
68
+ D,
69
+ N,
70
+ k
71
+ ]);
72
+ let I = P?.owner === D ? P : null, L = !!(S && T && E && (!I || I.loading)), R = I?.error, z = I?.data?.listDataSinks.edges.map((e) => e.node).filter((e) => e.isActive) ?? [], B = {
73
+ width: "100%",
74
+ padding: "var(--space-controlGap)",
75
+ background: "var(--color-bg-surface)",
76
+ color: "var(--color-text-primary)",
77
+ border: "1px solid var(--color-border-default)",
78
+ borderRadius: "var(--radius-control)"
79
+ };
80
+ return /* @__PURE__ */ l("section", {
81
+ "aria-label": b("bigconsole.dashboards.templateSetup.title", "Template setup"),
82
+ className: "space-y-form-gap",
83
+ children: [p.requiredDataSinks.length > 0 && /* @__PURE__ */ l("div", { children: [
84
+ /* @__PURE__ */ c("h3", {
85
+ className: "text-sm font-medium",
86
+ children: b("bigconsole.dashboards.templateSetup.connect", "Connect your data")
87
+ }),
88
+ /* @__PURE__ */ c("p", {
89
+ className: "text-xs text-text-muted",
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
+ }),
92
+ !w && !T && /* @__PURE__ */ c("p", {
93
+ role: "status",
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
+ }),
96
+ R && /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("p", {
97
+ role: "alert",
98
+ children: b("bigconsole.dashboards.templateSetup.loadError", "Could not load data sources.")
99
+ }), /* @__PURE__ */ c("button", {
100
+ type: "button",
101
+ disabled: v,
102
+ onClick: () => A((e) => e + 1),
103
+ children: b("bigconsole.dashboards.templateSetup.retry", "Retry loading sources")
104
+ })] }),
105
+ p.requiredDataSinks.map((e, t) => /* @__PURE__ */ l("div", {
106
+ className: "mt-form-gap",
107
+ children: [
108
+ /* @__PURE__ */ c("label", {
109
+ htmlFor: `${y}-sink-${t}`,
110
+ className: "text-sm font-medium",
111
+ children: e.label
112
+ }),
113
+ e.description && /* @__PURE__ */ c("p", {
114
+ className: "text-xs text-text-muted",
115
+ children: e.description
116
+ }),
117
+ /* @__PURE__ */ l("select", {
118
+ id: `${y}-sink-${t}`,
119
+ value: m[e.slot] ?? "",
120
+ disabled: v || L || !S || !T,
121
+ style: B,
122
+ onChange: (t) => h(e.slot, t.target.value),
123
+ children: [/* @__PURE__ */ c("option", {
124
+ value: "",
125
+ children: b("bigconsole.dashboards.templateSetup.connectLater", "Connect later")
126
+ }), z.map((e) => /* @__PURE__ */ c("option", {
127
+ value: e.id,
128
+ children: e.name || e.key
129
+ }, e.id))]
130
+ }),
131
+ e.expectedFields.length > 0 && /* @__PURE__ */ c("p", {
132
+ className: "text-xs text-text-muted",
133
+ children: b("bigconsole.dashboards.templateSetup.expectedFields", "Expected fields: {fields}", { fields: e.expectedFields.map((e) => e.name).join(", ") })
134
+ }),
135
+ e.widgetTitles.length > 0 && /* @__PURE__ */ c("p", {
136
+ className: "text-xs text-text-muted",
137
+ children: b("bigconsole.dashboards.templateSetup.usedBy", "Used by: {widgets}", { widgets: e.widgetTitles.join(", ") })
138
+ })
139
+ ]
140
+ }, e.slot)),
141
+ I?.data?.listDataSinks.pageInfo.hasNextPage && /* @__PURE__ */ c("button", {
142
+ type: "button",
143
+ disabled: v || L,
144
+ onClick: () => M({
145
+ owner: D,
146
+ cursor: I.data?.listDataSinks.pageInfo.endCursor ?? void 0
147
+ }),
148
+ children: b("bigconsole.dashboards.templateSetup.loadMore", "Load more sources")
149
+ })
150
+ ] }), p.requiredInputs.map((e, t) => /* @__PURE__ */ l("div", { children: [
151
+ /* @__PURE__ */ l("label", {
152
+ htmlFor: `${y}-input-${t}`,
153
+ className: "text-sm font-medium",
154
+ children: [e.label, e.required ? " *" : ""]
155
+ }),
156
+ e.type === "boolean" ? /* @__PURE__ */ l("select", {
157
+ id: `${y}-input-${t}`,
158
+ value: typeof g[e.name] == "boolean" ? String(g[e.name]) : "",
159
+ style: B,
160
+ disabled: v,
161
+ onChange: (t) => _(e.name, t.target.value === "" ? void 0 : t.target.value === "true"),
162
+ children: [
163
+ /* @__PURE__ */ c("option", {
164
+ value: "",
165
+ children: b("bigconsole.dashboards.templateSetup.chooseValue", "Choose a value")
166
+ }),
167
+ /* @__PURE__ */ c("option", {
168
+ value: "true",
169
+ children: b("bigconsole.dashboards.templateSetup.true", "True")
170
+ }),
171
+ /* @__PURE__ */ c("option", {
172
+ value: "false",
173
+ children: b("bigconsole.dashboards.templateSetup.false", "False")
174
+ })
175
+ ]
176
+ }) : e.type === "select" ? /* @__PURE__ */ l("select", {
177
+ id: `${y}-input-${t}`,
178
+ value: typeof g[e.name] == "string" ? String(g[e.name]) : "",
179
+ style: B,
180
+ disabled: v,
181
+ onChange: (t) => _(e.name, t.target.value),
182
+ children: [/* @__PURE__ */ c("option", {
183
+ value: "",
184
+ children: b("bigconsole.dashboards.templateSetup.chooseValue", "Choose a value")
185
+ }), e.options?.map((e) => /* @__PURE__ */ c("option", {
186
+ value: e.value,
187
+ children: e.label
188
+ }, e.value))]
189
+ }) : /* @__PURE__ */ c(o, {
190
+ id: `${y}-input-${t}`,
191
+ type: e.type === "secret" ? "password" : e.type === "number" ? "number" : "text",
192
+ step: e.type === "number" ? "any" : void 0,
193
+ value: typeof g[e.name] == "string" || typeof g[e.name] == "number" ? String(g[e.name]) : "",
194
+ placeholder: e.placeholder,
195
+ disabled: v,
196
+ onChange: (t) => _(e.name, e.type === "number" ? t.target.value === "" ? void 0 : Number(t.target.value) : t.target.value)
197
+ }),
198
+ e.helpText && /* @__PURE__ */ c("p", {
199
+ className: "text-xs text-text-muted",
200
+ children: e.helpText
201
+ })
202
+ ] }, e.name))]
203
+ });
204
+ }
205
+ //#endregion
206
+ export { p as TemplateInstallOptions };
207
+
208
+ //# sourceMappingURL=TemplateInstallOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TemplateInstallOptions.js","names":[],"sources":["../../../../src/bigconsole/components/dashboard/TemplateInstallOptions.tsx"],"sourcesContent":["import { Input } from '@burdenoff/fe-libs/ui';\nimport { useEffect, useId, useRef, useState } from 'react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell/PermissionProvider';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { BIGCONSOLE_PERMISSIONS } from '../../../constants/permissions';\nimport { useApolloClient } from '@apollo/client/react';\nimport { useActiveContext } from '@burdenoff/fe-libs/shared/providers/shell/ActiveContextProvider';\nimport { ListDataSinksDocument, type ListDataSinksQuery } from '../../../generated/wspace-operations';\nimport type { DashboardTemplateContent } from '../../hooks/useStoreDashboardTemplates';\n\nexport function TemplateInstallOptions({\n content,\n bindings,\n onBindingChange,\n inputValues,\n onInputChange,\n disabled,\n}: {\n content: DashboardTemplateContent;\n bindings: Record<string, string>;\n onBindingChange: (slot: string, id: string) => void;\n inputValues: Record<string, unknown>;\n onInputChange: (name: string, value: unknown) => void;\n disabled: boolean;\n}) {\n const prefix = useId();\n const { t } = useI18n();\n const client = useApolloClient();\n const { workspaceId } = useActiveContext();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const canRead = !permissionsLoading && hasPermission(BIGCONSOLE_PERMISSIONS.DATASINK_READ);\n const hasSlots = content.requiredDataSinks.length > 0;\n const owner = `${workspaceId}:${canRead}:${hasSlots}`;\n const ownerRef = useRef(owner);\n ownerRef.current = owner;\n const [retry, setRetry] = useState(0);\n const [page, setPage] = useState<{ owner: string; cursor?: string } | null>(null);\n const cursor = page?.owner === owner ? page.cursor : undefined;\n const [result, setResult] = useState<{\n owner: string;\n data?: ListDataSinksQuery;\n error?: boolean;\n loading?: boolean;\n } | null>(null);\n useEffect(() => {\n setPage(null);\n setResult(null);\n }, [owner]);\n useEffect(() => {\n let cancelled = false;\n if (!workspaceId || !hasSlots || !canRead) return;\n setResult((previous) => ({ ...previous, owner, loading: true, error: false }));\n void client\n .query<ListDataSinksQuery>({\n query: ListDataSinksDocument,\n variables: { isActive: true, first: 100, ...(cursor ? { after: cursor } : {}) },\n fetchPolicy: 'network-only',\n })\n .then((response) => {\n if (cancelled || ownerRef.current !== owner) return;\n setResult((previous) => {\n const incoming = response.data;\n if (!incoming) return { owner, error: true, loading: false };\n const previousEdges = cursor && previous?.owner === owner ? (previous.data?.listDataSinks.edges ?? []) : [];\n const edges = [\n ...new Map(\n [...previousEdges, ...incoming.listDataSinks.edges].map((edge) => [edge.node.id, edge])\n ).values(),\n ];\n return { owner, data: { ...incoming, listDataSinks: { ...incoming.listDataSinks, edges } }, loading: false };\n });\n })\n .catch(() => {\n if (!cancelled && ownerRef.current === owner)\n setResult((previous) => ({ ...previous, owner, error: true, loading: false }));\n });\n return () => {\n cancelled = true;\n };\n }, [client, workspaceId, hasSlots, canRead, owner, cursor, retry]);\n const owned = result?.owner === owner ? result : null;\n const loading = Boolean(workspaceId && canRead && hasSlots && (!owned || owned.loading));\n const error = owned?.error;\n const available = owned?.data?.listDataSinks.edges.map((edge) => edge.node).filter((sink) => sink.isActive) ?? [];\n const selectStyle = {\n width: '100%',\n padding: 'var(--space-controlGap)',\n background: 'var(--color-bg-surface)',\n color: 'var(--color-text-primary)',\n border: '1px solid var(--color-border-default)',\n borderRadius: 'var(--radius-control)',\n };\n return (\n <section aria-label={t('bigconsole.dashboards.templateSetup.title', 'Template setup')} className=\"space-y-form-gap\">\n {content.requiredDataSinks.length > 0 && (\n <div>\n <h3 className=\"text-sm font-medium\">\n {t('bigconsole.dashboards.templateSetup.connect', 'Connect your data')}\n </h3>\n <p className=\"text-xs text-text-muted\">\n {t(\n 'bigconsole.dashboards.templateSetup.connectHelp',\n 'Choose a source for each group of widgets. You can also connect it later in the dashboard builder.'\n )}\n </p>\n {!permissionsLoading && !canRead && (\n <p role=\"status\">\n {t(\n 'bigconsole.dashboards.templateSetup.noReadPermission',\n 'You do not have access to browse data sources. You can connect a source later with help from your workspace admin.'\n )}\n </p>\n )}\n {error && (\n <div>\n <p role=\"alert\">{t('bigconsole.dashboards.templateSetup.loadError', 'Could not load data sources.')}</p>\n <button type=\"button\" disabled={disabled} onClick={() => setRetry((value) => value + 1)}>\n {t('bigconsole.dashboards.templateSetup.retry', 'Retry loading sources')}\n </button>\n </div>\n )}\n {content.requiredDataSinks.map((slot, index) => (\n <div key={slot.slot} className=\"mt-form-gap\">\n <label htmlFor={`${prefix}-sink-${index}`} className=\"text-sm font-medium\">\n {slot.label}\n </label>\n {slot.description && <p className=\"text-xs text-text-muted\">{slot.description}</p>}\n <select\n id={`${prefix}-sink-${index}`}\n value={bindings[slot.slot] ?? ''}\n disabled={disabled || loading || !workspaceId || !canRead}\n style={selectStyle}\n onChange={(event) => onBindingChange(slot.slot, event.target.value)}\n >\n <option value=\"\">{t('bigconsole.dashboards.templateSetup.connectLater', 'Connect later')}</option>\n {available.map((sink) => (\n <option key={sink.id} value={sink.id}>\n {sink.name || sink.key}\n </option>\n ))}\n </select>\n {slot.expectedFields.length > 0 && (\n <p className=\"text-xs text-text-muted\">\n {t('bigconsole.dashboards.templateSetup.expectedFields', 'Expected fields: {fields}', {\n fields: slot.expectedFields.map((field) => field.name).join(', '),\n })}\n </p>\n )}\n {slot.widgetTitles.length > 0 && (\n <p className=\"text-xs text-text-muted\">\n {t('bigconsole.dashboards.templateSetup.usedBy', 'Used by: {widgets}', {\n widgets: slot.widgetTitles.join(', '),\n })}\n </p>\n )}\n </div>\n ))}\n {owned?.data?.listDataSinks.pageInfo.hasNextPage && (\n <button\n type=\"button\"\n disabled={disabled || loading}\n onClick={() => setPage({ owner, cursor: owned.data?.listDataSinks.pageInfo.endCursor ?? undefined })}\n >\n {t('bigconsole.dashboards.templateSetup.loadMore', 'Load more sources')}\n </button>\n )}\n </div>\n )}\n {content.requiredInputs.map((input, index) => (\n <div key={input.name}>\n <label htmlFor={`${prefix}-input-${index}`} className=\"text-sm font-medium\">\n {input.label}\n {input.required ? ' *' : ''}\n </label>\n {input.type === 'boolean' ? (\n <select\n id={`${prefix}-input-${index}`}\n value={typeof inputValues[input.name] === 'boolean' ? String(inputValues[input.name]) : ''}\n style={selectStyle}\n disabled={disabled}\n onChange={(event) =>\n onInputChange(input.name, event.target.value === '' ? undefined : event.target.value === 'true')\n }\n >\n <option value=\"\">{t('bigconsole.dashboards.templateSetup.chooseValue', 'Choose a value')}</option>\n <option value=\"true\">{t('bigconsole.dashboards.templateSetup.true', 'True')}</option>\n <option value=\"false\">{t('bigconsole.dashboards.templateSetup.false', 'False')}</option>\n </select>\n ) : input.type === 'select' ? (\n <select\n id={`${prefix}-input-${index}`}\n value={typeof inputValues[input.name] === 'string' ? String(inputValues[input.name]) : ''}\n style={selectStyle}\n disabled={disabled}\n onChange={(event) => onInputChange(input.name, event.target.value)}\n >\n <option value=\"\">{t('bigconsole.dashboards.templateSetup.chooseValue', 'Choose a value')}</option>\n {input.options?.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n ) : (\n <Input\n id={`${prefix}-input-${index}`}\n type={input.type === 'secret' ? 'password' : input.type === 'number' ? 'number' : 'text'}\n step={input.type === 'number' ? 'any' : undefined}\n value={\n typeof inputValues[input.name] === 'string' || typeof inputValues[input.name] === 'number'\n ? String(inputValues[input.name])\n : ''\n }\n placeholder={input.placeholder}\n disabled={disabled}\n onChange={(event) =>\n onInputChange(\n input.name,\n input.type === 'number'\n ? event.target.value === ''\n ? undefined\n : Number(event.target.value)\n : event.target.value\n )\n }\n />\n )}\n {input.helpText && <p className=\"text-xs text-text-muted\">{input.helpText}</p>}\n </div>\n ))}\n </section>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { DashboardTemplateContent } from '../../hooks/useStoreDashboardTemplates';
2
+
3
+ /** Show the publisher's actual page/widget structure without running actions. */
4
+ export declare function TemplateLayoutPreview({ content }: {
5
+ content: DashboardTemplateContent;
6
+ }): import("react").JSX.Element | null;
7
+ //# sourceMappingURL=TemplateLayoutPreview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TemplateLayoutPreview.d.ts","sourceRoot":"","sources":["../../../../src/bigconsole/components/dashboard/TemplateLayoutPreview.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAMvF,iFAAiF;AACjF,wBAAgB,qBAAqB,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,wBAAwB,CAAA;CAAE,sCA6DvF"}
@@ -0,0 +1,51 @@
1
+ import { jsx as e, jsxs as t } from "react/jsx-runtime";
2
+ import { useI18n as n } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
3
+ //#region src/bigconsole/components/dashboard/TemplateLayoutPreview.tsx
4
+ function r(e) {
5
+ return typeof e == "object" && !!e && !Array.isArray(e);
6
+ }
7
+ function i({ content: i }) {
8
+ let { t: a } = n();
9
+ return !r(i.definition) || !Array.isArray(i.definition.pages) ? null : /* @__PURE__ */ t("section", {
10
+ "aria-label": a("bigconsole.dashboards.templatePreview.label", "Template layout preview"),
11
+ className: "mb-form-gap space-y-control-gap",
12
+ children: [
13
+ /* @__PURE__ */ e("h3", {
14
+ className: "text-sm font-medium",
15
+ children: a("bigconsole.dashboards.templatePreview.title", "Layout preview")
16
+ }),
17
+ i.definition.pages.filter(r).map((n, i) => /* @__PURE__ */ t("div", { children: [/* @__PURE__ */ e("p", {
18
+ className: "text-xs text-text-muted",
19
+ children: typeof n.name == "string" ? n.name : a("bigconsole.dashboards.templatePreview.page", "Page {number}", { number: i + 1 })
20
+ }), /* @__PURE__ */ e("div", {
21
+ style: {
22
+ display: "grid",
23
+ gridTemplateColumns: "repeat(12, minmax(0, 1fr))",
24
+ gap: "var(--space-controlGap)"
25
+ },
26
+ children: Array.isArray(n.widgets) && n.widgets.filter(r).map((n, i) => {
27
+ let o = r(n.config) ? n.config : {}, s = typeof o.chartType == "string" ? a("bigconsole.dashboards.templatePreview.chartType", "{type} chart", { type: o.chartType }) : typeof n.type == "string" ? n.type.toLowerCase().replaceAll("_", " ") : a("bigconsole.dashboards.templatePreview.widgetType", "Widget"), c = r(n.position) ? n.position : {};
28
+ return /* @__PURE__ */ t("div", {
29
+ className: "rounded-card border border-border-default bg-bg-sunken p-3",
30
+ style: { gridColumn: `span ${typeof c.width == "number" ? Math.min(12, Math.max(1, Math.round(c.width))) : 6}` },
31
+ children: [/* @__PURE__ */ e("p", {
32
+ className: "truncate text-xs font-medium",
33
+ children: typeof n.title == "string" ? n.title : a("bigconsole.dashboards.templatePreview.widget", "Widget {number}", { number: i + 1 })
34
+ }), /* @__PURE__ */ e("p", {
35
+ className: "truncate text-xs text-text-muted",
36
+ children: s
37
+ })]
38
+ }, i);
39
+ })
40
+ })] }, i)),
41
+ /* @__PURE__ */ e("p", {
42
+ className: "text-xs text-text-muted",
43
+ children: a("bigconsole.dashboards.templatePreview.help", "Data appears after you connect a source. The dashboard uses these saved widgets and layouts.")
44
+ })
45
+ ]
46
+ });
47
+ }
48
+ //#endregion
49
+ export { i as TemplateLayoutPreview };
50
+
51
+ //# sourceMappingURL=TemplateLayoutPreview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TemplateLayoutPreview.js","names":[],"sources":["../../../../src/bigconsole/components/dashboard/TemplateLayoutPreview.tsx"],"sourcesContent":["import { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport type { DashboardTemplateContent } from '../../hooks/useStoreDashboardTemplates';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\n/** Show the publisher's actual page/widget structure without running actions. */\nexport function TemplateLayoutPreview({ content }: { content: DashboardTemplateContent }) {\n const { t } = useI18n();\n if (!isRecord(content.definition) || !Array.isArray(content.definition.pages)) return null;\n return (\n <section\n aria-label={t('bigconsole.dashboards.templatePreview.label', 'Template layout preview')}\n className=\"mb-form-gap space-y-control-gap\"\n >\n <h3 className=\"text-sm font-medium\">{t('bigconsole.dashboards.templatePreview.title', 'Layout preview')}</h3>\n {content.definition.pages.filter(isRecord).map((page, pageIndex) => (\n <div key={pageIndex}>\n <p className=\"text-xs text-text-muted\">\n {typeof page.name === 'string'\n ? page.name\n : t('bigconsole.dashboards.templatePreview.page', 'Page {number}', { number: pageIndex + 1 })}\n </p>\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(12, minmax(0, 1fr))',\n gap: 'var(--space-controlGap)',\n }}\n >\n {Array.isArray(page.widgets) &&\n page.widgets.filter(isRecord).map((widget, index) => {\n const config = isRecord(widget.config) ? widget.config : {};\n const typeLabel =\n typeof config.chartType === 'string'\n ? t('bigconsole.dashboards.templatePreview.chartType', '{type} chart', { type: config.chartType })\n : typeof widget.type === 'string'\n ? widget.type.toLowerCase().replaceAll('_', ' ')\n : t('bigconsole.dashboards.templatePreview.widgetType', 'Widget');\n const position = isRecord(widget.position) ? widget.position : {};\n const width =\n typeof position.width === 'number' ? Math.min(12, Math.max(1, Math.round(position.width))) : 6;\n return (\n <div\n key={index}\n className=\"rounded-card border border-border-default bg-bg-sunken p-3\"\n style={{ gridColumn: `span ${width}` }}\n >\n <p className=\"truncate text-xs font-medium\">\n {typeof widget.title === 'string'\n ? widget.title\n : t('bigconsole.dashboards.templatePreview.widget', 'Widget {number}', { number: index + 1 })}\n </p>\n <p className=\"truncate text-xs text-text-muted\">{typeLabel}</p>\n </div>\n );\n })}\n </div>\n </div>\n ))}\n <p className=\"text-xs text-text-muted\">\n {t(\n 'bigconsole.dashboards.templatePreview.help',\n 'Data appears after you connect a source. The dashboard uses these saved widgets and layouts.'\n )}\n </p>\n </section>\n );\n}\n"],"mappings":";;;AAGA,SAAS,EAAS,GAAkD;AAClE,QAAyB,OAAO,KAAU,cAAnC,KAA+C,CAAC,MAAM,QAAQ,EAAM;;AAI7E,SAAgB,EAAsB,EAAE,cAAkD;CACxF,IAAM,EAAE,SAAM,GAAS;AAEvB,QADI,CAAC,EAAS,EAAQ,WAAW,IAAI,CAAC,MAAM,QAAQ,EAAQ,WAAW,MAAM,GAAS,OAEpF,kBAAC,WAAD;EACE,cAAY,EAAE,+CAA+C,0BAA0B;EACvF,WAAU;YAFZ;GAIE,kBAAC,MAAD;IAAI,WAAU;cAAuB,EAAE,+CAA+C,iBAAiB;IAAM,CAAA;GAC5G,EAAQ,WAAW,MAAM,OAAO,EAAS,CAAC,KAAK,GAAM,MACpD,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;IAAG,WAAU;cACV,OAAO,EAAK,QAAS,WAClB,EAAK,OACL,EAAE,8CAA8C,iBAAiB,EAAE,QAAQ,IAAY,GAAG,CAAC;IAC7F,CAAA,EACJ,kBAAC,OAAD;IACE,OAAO;KACL,SAAS;KACT,qBAAqB;KACrB,KAAK;KACN;cAEA,MAAM,QAAQ,EAAK,QAAQ,IAC1B,EAAK,QAAQ,OAAO,EAAS,CAAC,KAAK,GAAQ,MAAU;KACnD,IAAM,IAAS,EAAS,EAAO,OAAO,GAAG,EAAO,SAAS,EAAE,EACrD,IACJ,OAAO,EAAO,aAAc,WACxB,EAAE,mDAAmD,gBAAgB,EAAE,MAAM,EAAO,WAAW,CAAC,GAChG,OAAO,EAAO,QAAS,WACrB,EAAO,KAAK,aAAa,CAAC,WAAW,KAAK,IAAI,GAC9C,EAAE,oDAAoD,SAAS,EACjE,IAAW,EAAS,EAAO,SAAS,GAAG,EAAO,WAAW,EAAE;AAGjE,YACE,kBAAC,OAAD;MAEE,WAAU;MACV,OAAO,EAAE,YAAY,QALvB,OAAO,EAAS,SAAU,WAAW,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,EAAS,MAAM,CAAC,CAAC,GAAG,KAKrD;gBAHxC,CAKE,kBAAC,KAAD;OAAG,WAAU;iBACV,OAAO,EAAO,SAAU,WACrB,EAAO,QACP,EAAE,gDAAgD,mBAAmB,EAAE,QAAQ,IAAQ,GAAG,CAAC;OAC7F,CAAA,EACJ,kBAAC,KAAD;OAAG,WAAU;iBAAoC;OAAc,CAAA,CAC3D;QAVC,EAUD;MAER;IACA,CAAA,CACF,EAAA,EAzCI,EAyCJ,CACN;GACF,kBAAC,KAAD;IAAG,WAAU;cACV,EACC,8CACA,+FACD;IACC,CAAA;GACI"}
@@ -64,6 +64,8 @@ export interface InstallTemplateArgs {
64
64
  content: DashboardTemplateContent;
65
65
  name?: string;
66
66
  visibility?: string;
67
+ description?: string;
68
+ tags?: string[];
67
69
  dataSinkBindings?: {
68
70
  slot: string;
69
71
  dataSinkId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"useStoreDashboardTemplates.d.ts","sourceRoot":"","sources":["../../../src/bigconsole/hooks/useStoreDashboardTemplates.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useStoreDashboardTemplates.d.ts","sourceRoot":"","sources":["../../../src/bigconsole/hooks/useStoreDashboardTemplates.ts"],"names":[],"mappings":"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"}