@burdenoff/microfe-bigconsole 2026.608.1 → 2026.610.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.
@@ -25,7 +25,7 @@ var w = t(function({ isOpen: t, isCreating: w = !1, onClose: T, onCreate: E, sho
25
25
  P.length
26
26
  ]), K = n((e) => {
27
27
  z(e), j(e.name), N(e.description || "");
28
- }, []), q = n((e) => {
28
+ }, []), q = n(async (e) => {
29
29
  if (e.preventDefault(), O === "template" && !R) {
30
30
  V("Please select a template");
31
31
  return;
@@ -43,13 +43,18 @@ var w = t(function({ isOpen: t, isCreating: w = !1, onClose: T, onCreate: E, sho
43
43
  V("Dashboard name must be less than 100 characters"), H.current?.focus();
44
44
  return;
45
45
  }
46
- V(null), E({
47
- name: t,
48
- description: M.trim(),
49
- category: "CUSTOM",
50
- tags: P.length > 0 ? P : void 0,
51
- templateId: R?.id
52
- });
46
+ V(null);
47
+ try {
48
+ await E({
49
+ name: t,
50
+ description: M.trim(),
51
+ category: "CUSTOM",
52
+ tags: P.length > 0 ? P : void 0,
53
+ templateId: R?.id
54
+ });
55
+ } catch (e) {
56
+ V(e instanceof Error ? e.message : "Failed to create dashboard. Please try again.");
57
+ }
53
58
  }, [
54
59
  A,
55
60
  M,
@@ -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 { TemplatePicker } from './TemplatePicker';\nimport type { DashboardTemplateListItem } from '../../hooks';\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;\n /** Whether to show the template picker option */\n showTemplates?: boolean;\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}) {\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<DashboardTemplateListItem | 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: DashboardTemplateListItem) => {\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 (e: React.FormEvent) => {\n e.preventDefault();\n\n // For template mode without selection, show error\n if (mode === 'template' && !selectedTemplate) {\n setError('Please select a template');\n return;\n }\n\n const trimmedName = name.trim();\n if (!trimmedName) {\n setError('Dashboard name is required');\n nameInputRef.current?.focus();\n return;\n }\n\n if (trimmedName.length < 3) {\n setError('Dashboard name must be at least 3 characters');\n nameInputRef.current?.focus();\n return;\n }\n\n if (trimmedName.length > 100) {\n setError('Dashboard name must be less than 100 characters');\n nameInputRef.current?.focus();\n return;\n }\n\n setError(null);\n onCreate({\n name: trimmedName,\n description: description.trim(),\n category: 'CUSTOM',\n tags: tags.length > 0 ? tags : undefined,\n templateId: selectedTemplate?.id,\n });\n },\n [name, description, tags, mode, selectedTemplate, onCreate]\n );\n\n return (\n <Dialog open={isOpen} onOpenChange={(open) => !open && !isCreating && onClose()}>\n <DialogContent\n style={{ maxWidth: mode === 'template' ? '900px' : '480px', padding: 0, transition: 'max-width 0.2s ease' }}\n >\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 borderRadius: 'var(--radius-card)',\n backgroundColor: 'var(--color-action-primary-bg)',\n boxShadow: 'var(--shadow-elevation-2)',\n }}\n >\n <LayoutDashboard\n style={{\n height: 'var(--size-icon-lg)',\n width: 'var(--size-icon-lg)',\n color: 'var(--color-action-primary-text)',\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 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 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 style={{\n display: 'flex',\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 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 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 <TemplatePicker selectedTemplateId={selectedTemplate?.id} onSelect={handleTemplateSelect} compact />\n </div>\n )}\n\n {/* Form Content */}\n <div style={{ padding: 'var(--space-pagePadding)' }}>\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 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=\"Enter dashboard name\"\n disabled={isCreating}\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 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 (optional)\n </span>\n </label>\n <Textarea\n id=\"dashboard-description\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Enter a brief description for this dashboard\"\n rows={3}\n disabled={isCreating}\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 Tags\n <span\n style={{\n color: 'var(--color-text-muted)',\n fontWeight: 'var(--font-weight-regular)',\n }}\n >\n (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}\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={tags.length >= 10 ? 'Max tags reached' : 'Type a tag and press Enter'}\n disabled={isCreating || 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 || !tagInput.trim() || tags.length >= 10}\n style={{ height: 'var(--size-controlHeight-md)' }}\n >\n Add\n </Button>\n </div>\n <p\n style={{\n fontSize: 'var(--font-size-body-xs)',\n color: 'var(--color-text-muted)',\n marginTop: 'var(--space-controlGap)',\n }}\n >\n Press Enter to add a tag, or click Add\n </p>\n </div>\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}\n style={{ height: 'var(--size-controlHeight-md)' }}\n >\n Cancel\n </Button>\n <Button\n type=\"submit\"\n disabled={isCreating || !name.trim()}\n style={{\n height: 'var(--size-controlHeight-md)',\n backgroundColor: 'var(--color-action-primary-bg)',\n }}\n >\n {isCreating ? (\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 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 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 { TemplatePicker } from './TemplatePicker';\nimport type { DashboardTemplateListItem } from '../../hooks';\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\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}) {\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<DashboardTemplateListItem | 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: DashboardTemplateListItem) => {\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('Please select a template');\n return;\n }\n\n const trimmedName = name.trim();\n if (!trimmedName) {\n setError('Dashboard name is required');\n nameInputRef.current?.focus();\n return;\n }\n\n if (trimmedName.length < 3) {\n setError('Dashboard name must be at least 3 characters');\n nameInputRef.current?.focus();\n return;\n }\n\n if (trimmedName.length > 100) {\n setError('Dashboard name must be less than 100 characters');\n nameInputRef.current?.focus();\n return;\n }\n\n setError(null);\n try {\n await onCreate({\n name: trimmedName,\n description: description.trim(),\n category: 'CUSTOM',\n tags: tags.length > 0 ? tags : undefined,\n templateId: selectedTemplate?.id,\n });\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to create dashboard. Please try again.');\n }\n },\n [name, description, tags, mode, selectedTemplate, onCreate]\n );\n\n return (\n <Dialog open={isOpen} onOpenChange={(open) => !open && !isCreating && onClose()}>\n <DialogContent\n style={{ maxWidth: mode === 'template' ? '900px' : '480px', padding: 0, transition: 'max-width 0.2s ease' }}\n >\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 borderRadius: 'var(--radius-card)',\n backgroundColor: 'var(--color-action-primary-bg)',\n boxShadow: 'var(--shadow-elevation-2)',\n }}\n >\n <LayoutDashboard\n style={{\n height: 'var(--size-icon-lg)',\n width: 'var(--size-icon-lg)',\n color: 'var(--color-action-primary-text)',\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 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 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 style={{\n display: 'flex',\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 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 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 <TemplatePicker selectedTemplateId={selectedTemplate?.id} onSelect={handleTemplateSelect} compact />\n </div>\n )}\n\n {/* Form Content */}\n <div style={{ padding: 'var(--space-pagePadding)' }}>\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 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=\"Enter dashboard name\"\n disabled={isCreating}\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 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 (optional)\n </span>\n </label>\n <Textarea\n id=\"dashboard-description\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Enter a brief description for this dashboard\"\n rows={3}\n disabled={isCreating}\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 Tags\n <span\n style={{\n color: 'var(--color-text-muted)',\n fontWeight: 'var(--font-weight-regular)',\n }}\n >\n (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}\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={tags.length >= 10 ? 'Max tags reached' : 'Type a tag and press Enter'}\n disabled={isCreating || 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 || !tagInput.trim() || tags.length >= 10}\n style={{ height: 'var(--size-controlHeight-md)' }}\n >\n Add\n </Button>\n </div>\n <p\n style={{\n fontSize: 'var(--font-size-body-xs)',\n color: 'var(--color-text-muted)',\n marginTop: 'var(--space-controlGap)',\n }}\n >\n Press Enter to add a tag, or click Add\n </p>\n </div>\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}\n style={{ height: 'var(--size-controlHeight-md)' }}\n >\n Cancel\n </Button>\n <Button\n type=\"submit\"\n disabled={isCreating || !name.trim()}\n style={{\n height: 'var(--size-controlHeight-md)',\n backgroundColor: 'var(--color-action-primary-bg)',\n }}\n >\n {isCreating ? (\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 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 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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"}
@@ -136,7 +136,7 @@ function c({ isOpen: c, onClose: f, onSelectTemplate: p, selectedTemplateId: m,
136
136
  }) : /* @__PURE__ */ i("div", {
137
137
  style: {
138
138
  display: "grid",
139
- gridTemplateColumns: "repeat(auto-fill, minmax(200px, 1fr))",
139
+ gridTemplateColumns: "repeat(auto-fill, minmax(min(200px, 100%), 1fr))",
140
140
  gap: "12px"
141
141
  },
142
142
  children: W.map((e) => /* @__PURE__ */ i(d, {
@@ -1 +1 @@
1
- {"version":3,"file":"TemplatePicker.js","names":[],"sources":["../../../../../src/bigconsole/components/dashboard/TemplatePicker/TemplatePicker.tsx"],"sourcesContent":["/**\n * TemplatePicker Component\n *\n * Grid/List view for browsing and selecting dashboard templates.\n */\n\nimport React, { useState, useEffect, useCallback } from 'react';\nimport {\n useDashboardTemplates,\n type DashboardTemplateListItem,\n type DashboardCategory,\n type TemplateComplexity,\n} from '../../../hooks';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TemplatePickerProps {\n /** Modal mode: whether the modal is open */\n isOpen?: boolean;\n /** Modal mode: callback to close the modal */\n onClose?: () => void;\n /** Modal mode: callback when template is selected with name and placeholders */\n onSelectTemplate?: (templateId: string, name: string, placeholderValues: Record<string, unknown>) => void;\n /** Embedded mode: currently selected template ID */\n selectedTemplateId?: string;\n /** Embedded mode: callback when template is selected */\n onSelect?: (template: DashboardTemplateListItem) => void;\n /** Embedded mode: compact display without modal wrapper */\n compact?: boolean;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst CATEGORY_LABELS: Record<DashboardCategory, string> = {\n ANALYTICS: 'Analytics',\n OPERATIONS: 'Operations',\n SALES: 'Sales',\n MARKETING: 'Marketing',\n FINANCE: 'Finance',\n HR: 'Human Resources',\n CUSTOM: 'Custom',\n};\n\nconst COMPLEXITY_COLORS: Record<TemplateComplexity, string> = {\n BEGINNER: '#22c55e',\n INTERMEDIATE: '#f59e0b',\n ADVANCED: '#ef4444',\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport function TemplatePicker({\n isOpen,\n onClose,\n onSelectTemplate,\n selectedTemplateId,\n onSelect,\n compact = false,\n}: TemplatePickerProps) {\n const { templates, featuredTemplates, categories, loading, fetchTemplates, fetchFeaturedTemplates, searchTemplates } =\n useDashboardTemplates();\n\n const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid');\n const [searchQuery, setSearchQuery] = useState('');\n const [selectedCategory, setSelectedCategory] = useState<DashboardCategory | ''>('');\n const [selectedComplexity, setSelectedComplexity] = useState<TemplateComplexity | ''>('');\n const [selectedTemplate, setSelectedTemplate] = useState<DashboardTemplateListItem | null>(null);\n const [showDetailsModal, setShowDetailsModal] = useState(false);\n const [dashboardName, setDashboardName] = useState('');\n const [placeholderValues, setPlaceholderValues] = useState<Record<string, unknown>>({});\n\n // Determine if we should be active (modal mode uses isOpen, compact mode is always active)\n const isActive = compact || isOpen;\n\n // Fetch templates on mount/activation\n useEffect(() => {\n if (isActive) {\n fetchTemplates();\n fetchFeaturedTemplates();\n }\n }, [isActive, fetchTemplates, fetchFeaturedTemplates]);\n\n // Handle search\n useEffect(() => {\n if (searchQuery) {\n const debounce = setTimeout(() => {\n searchTemplates(searchQuery, selectedCategory || undefined, selectedComplexity || undefined);\n }, 300);\n return () => clearTimeout(debounce);\n } else if (isActive) {\n fetchTemplates({\n category: selectedCategory || undefined,\n complexity: selectedComplexity || undefined,\n });\n }\n }, [searchQuery, selectedCategory, selectedComplexity, isActive, searchTemplates, fetchTemplates]);\n\n // Handle template selection\n const handleSelectTemplate = useCallback(\n (template: DashboardTemplateListItem) => {\n // In compact/embedded mode, just call onSelect\n if (compact && onSelect) {\n onSelect(template);\n return;\n }\n\n // In modal mode, show details modal\n setSelectedTemplate(template);\n setDashboardName(`${template.name} Dashboard`);\n setShowDetailsModal(true);\n },\n [compact, onSelect]\n );\n\n // Handle create from template\n const handleCreateFromTemplate = useCallback(async () => {\n if (!selectedTemplate || !dashboardName.trim()) return;\n\n onSelectTemplate?.(selectedTemplate.id, dashboardName.trim(), placeholderValues);\n setShowDetailsModal(false);\n setSelectedTemplate(null);\n setDashboardName('');\n setPlaceholderValues({});\n onClose?.();\n }, [selectedTemplate, dashboardName, placeholderValues, onSelectTemplate, onClose]);\n\n // Render star rating\n const renderRating = (rating: number | undefined, count: number) => {\n if (!rating) return null;\n return (\n <div style={{ display: 'flex', alignItems: 'center', gap: '4px' }}>\n <span style={{ color: '#f59e0b' }}>★</span>\n <span style={{ fontSize: '12px', color: 'var(--text-secondary)' }}>\n {rating.toFixed(1)} ({count})\n </span>\n </div>\n );\n };\n\n if (!isActive) return null;\n\n const displayTemplates = searchQuery || selectedCategory || selectedComplexity ? templates : featuredTemplates;\n\n // Compact/Embedded mode - render just the content without modal wrapper\n if (compact) {\n return (\n <div>\n {/* Compact Filters Bar */}\n <div style={{ display: 'flex', gap: '8px', marginBottom: '12px', flexWrap: 'wrap' }}>\n <input\n type=\"text\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n placeholder=\"Search templates...\"\n style={{\n flex: '1 1 150px',\n padding: '6px 10px',\n border: '1px solid var(--border-color)',\n borderRadius: '4px',\n fontSize: '12px',\n }}\n />\n <select\n value={selectedCategory}\n onChange={(e) => setSelectedCategory(e.target.value as DashboardCategory | '')}\n style={{\n padding: '6px 10px',\n border: '1px solid var(--border-color)',\n borderRadius: '4px',\n fontSize: '12px',\n backgroundColor: 'var(--bg-primary)',\n }}\n >\n <option value=\"\">All Categories</option>\n {categories.map((cat) => (\n <option key={cat} value={cat}>\n {CATEGORY_LABELS[cat]}\n </option>\n ))}\n </select>\n </div>\n\n {/* Compact Template Grid */}\n {loading && displayTemplates.length === 0 ? (\n <div style={{ textAlign: 'center', padding: '20px', color: 'var(--text-secondary)', fontSize: '13px' }}>\n Loading templates...\n </div>\n ) : displayTemplates.length === 0 ? (\n <div style={{ textAlign: 'center', padding: '20px', color: 'var(--text-secondary)', fontSize: '13px' }}>\n No templates found\n </div>\n ) : (\n <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))', gap: '12px' }}>\n {displayTemplates.map((template) => (\n <CompactTemplateCard\n key={template.id}\n template={template}\n isSelected={selectedTemplateId === template.id}\n onSelect={() => handleSelectTemplate(template)}\n />\n ))}\n </div>\n )}\n </div>\n );\n }\n\n // Modal mode - full modal wrapper\n return (\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.5)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 9999,\n }}\n onClick={onClose}\n >\n <div\n style={{\n width: '90%',\n maxWidth: '1000px',\n maxHeight: '85vh',\n backgroundColor: 'var(--bg-primary)',\n borderRadius: '12px',\n boxShadow: '0 8px 32px rgba(0, 0, 0, 0.2)',\n overflow: 'hidden',\n display: 'flex',\n flexDirection: 'column',\n }}\n onClick={(e) => e.stopPropagation()}\n >\n {/* Header */}\n <div\n style={{\n padding: '20px 24px',\n borderBottom: '1px solid var(--border-color)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n }}\n >\n <div>\n <h2 style={{ margin: 0, fontSize: '20px', fontWeight: 600 }}>Choose a Template</h2>\n <p style={{ margin: '4px 0 0', fontSize: '13px', color: 'var(--text-secondary)' }}>\n Start with a pre-built dashboard template\n </p>\n </div>\n <button\n onClick={onClose}\n style={{\n background: 'none',\n border: 'none',\n fontSize: '24px',\n cursor: 'pointer',\n color: 'var(--text-secondary)',\n }}\n >\n x\n </button>\n </div>\n\n {/* Filters Bar */}\n <div\n style={{\n padding: '16px 24px',\n borderBottom: '1px solid var(--border-color)',\n display: 'flex',\n gap: '12px',\n alignItems: 'center',\n flexWrap: 'wrap',\n }}\n >\n {/* Search */}\n <input\n type=\"text\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n placeholder=\"Search templates...\"\n style={{\n flex: '1 1 200px',\n padding: '8px 12px',\n border: '1px solid var(--border-color)',\n borderRadius: '6px',\n fontSize: '13px',\n }}\n />\n\n {/* Category Filter */}\n <select\n value={selectedCategory}\n onChange={(e) => setSelectedCategory(e.target.value as DashboardCategory | '')}\n style={{\n padding: '8px 12px',\n border: '1px solid var(--border-color)',\n borderRadius: '6px',\n fontSize: '13px',\n backgroundColor: 'var(--bg-primary)',\n }}\n >\n <option value=\"\">All Categories</option>\n {categories.map((cat) => (\n <option key={cat} value={cat}>\n {CATEGORY_LABELS[cat]}\n </option>\n ))}\n </select>\n\n {/* Complexity Filter */}\n <select\n value={selectedComplexity}\n onChange={(e) => setSelectedComplexity(e.target.value as TemplateComplexity | '')}\n style={{\n padding: '8px 12px',\n border: '1px solid var(--border-color)',\n borderRadius: '6px',\n fontSize: '13px',\n backgroundColor: 'var(--bg-primary)',\n }}\n >\n <option value=\"\">All Levels</option>\n <option value=\"BEGINNER\">Beginner</option>\n <option value=\"INTERMEDIATE\">Intermediate</option>\n <option value=\"ADVANCED\">Advanced</option>\n </select>\n\n {/* View Toggle */}\n <div style={{ display: 'flex', border: '1px solid var(--border-color)', borderRadius: '6px' }}>\n <button\n onClick={() => setViewMode('grid')}\n style={{\n padding: '8px 12px',\n backgroundColor: viewMode === 'grid' ? 'var(--bg-secondary)' : 'transparent',\n border: 'none',\n cursor: 'pointer',\n fontSize: '13px',\n }}\n >\n Grid\n </button>\n <button\n onClick={() => setViewMode('list')}\n style={{\n padding: '8px 12px',\n backgroundColor: viewMode === 'list' ? 'var(--bg-secondary)' : 'transparent',\n border: 'none',\n cursor: 'pointer',\n fontSize: '13px',\n }}\n >\n List\n </button>\n </div>\n </div>\n\n {/* Templates Content */}\n <div style={{ flex: 1, overflowY: 'auto', padding: '24px' }}>\n {loading && displayTemplates.length === 0 ? (\n <div style={{ textAlign: 'center', padding: '40px', color: 'var(--text-secondary)' }}>\n Loading templates...\n </div>\n ) : displayTemplates.length === 0 ? (\n <div style={{ textAlign: 'center', padding: '40px', color: 'var(--text-secondary)' }}>\n No templates found. Try adjusting your filters.\n </div>\n ) : viewMode === 'grid' ? (\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))',\n gap: '20px',\n }}\n >\n {displayTemplates.map((template) => (\n <TemplateCard\n key={template.id}\n template={template}\n onSelect={() => handleSelectTemplate(template)}\n renderRating={renderRating}\n />\n ))}\n </div>\n ) : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>\n {displayTemplates.map((template) => (\n <TemplateListItem\n key={template.id}\n template={template}\n onSelect={() => handleSelectTemplate(template)}\n renderRating={renderRating}\n />\n ))}\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div\n style={{\n padding: '16px 24px',\n borderTop: '1px solid var(--border-color)',\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n }}\n >\n <span style={{ fontSize: '13px', color: 'var(--text-secondary)' }}>\n {displayTemplates.length} templates available\n </span>\n <button\n onClick={onClose}\n style={{\n padding: '10px 20px',\n backgroundColor: 'transparent',\n border: '1px solid var(--border-color)',\n borderRadius: '6px',\n cursor: 'pointer',\n fontSize: '14px',\n }}\n >\n Cancel\n </button>\n </div>\n </div>\n\n {/* Template Details Modal */}\n {showDetailsModal && selectedTemplate && (\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.5)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 10000,\n }}\n onClick={() => setShowDetailsModal(false)}\n >\n <div\n style={{\n width: '500px',\n backgroundColor: 'var(--bg-primary)',\n borderRadius: '12px',\n boxShadow: '0 8px 32px rgba(0, 0, 0, 0.2)',\n overflow: 'hidden',\n }}\n onClick={(e) => e.stopPropagation()}\n >\n <div\n style={{\n padding: '20px 24px',\n borderBottom: '1px solid var(--border-color)',\n }}\n >\n <h3 style={{ margin: 0, fontSize: '18px', fontWeight: 600 }}>Create from Template</h3>\n <p style={{ margin: '4px 0 0', fontSize: '13px', color: 'var(--text-secondary)' }}>\n {selectedTemplate.name}\n </p>\n </div>\n <div style={{ padding: '24px' }}>\n <div style={{ marginBottom: '20px' }}>\n <label\n style={{\n display: 'block',\n marginBottom: '8px',\n fontSize: '13px',\n fontWeight: 500,\n }}\n >\n Dashboard Name *\n </label>\n <input\n type=\"text\"\n value={dashboardName}\n onChange={(e) => setDashboardName(e.target.value)}\n placeholder=\"Enter dashboard name...\"\n style={{\n width: '100%',\n padding: '10px 12px',\n border: '1px solid var(--border-color)',\n borderRadius: '6px',\n fontSize: '14px',\n }}\n />\n </div>\n\n {/* Template Info */}\n <div\n style={{\n padding: '16px',\n backgroundColor: 'var(--bg-secondary)',\n borderRadius: '8px',\n }}\n >\n <div style={{ fontSize: '13px', color: 'var(--text-secondary)', marginBottom: '8px' }}>\n Template Details\n </div>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '16px' }}>\n <div>\n <div style={{ fontSize: '11px', color: 'var(--text-tertiary)' }}>Category</div>\n <div style={{ fontSize: '13px' }}>{CATEGORY_LABELS[selectedTemplate.category]}</div>\n </div>\n <div>\n <div style={{ fontSize: '11px', color: 'var(--text-tertiary)' }}>Complexity</div>\n <div\n style={{\n fontSize: '13px',\n color: COMPLEXITY_COLORS[selectedTemplate.complexity],\n }}\n >\n {selectedTemplate.complexity}\n </div>\n </div>\n <div>\n <div style={{ fontSize: '11px', color: 'var(--text-tertiary)' }}>Used</div>\n <div style={{ fontSize: '13px' }}>{selectedTemplate.usageCount} times</div>\n </div>\n </div>\n </div>\n </div>\n <div\n style={{\n padding: '16px 24px',\n borderTop: '1px solid var(--border-color)',\n display: 'flex',\n justifyContent: 'flex-end',\n gap: '12px',\n }}\n >\n <button\n onClick={() => setShowDetailsModal(false)}\n style={{\n padding: '10px 20px',\n backgroundColor: 'transparent',\n border: '1px solid var(--border-color)',\n borderRadius: '6px',\n cursor: 'pointer',\n fontSize: '14px',\n }}\n >\n Cancel\n </button>\n <button\n onClick={handleCreateFromTemplate}\n disabled={!dashboardName.trim()}\n style={{\n padding: '10px 20px',\n backgroundColor: dashboardName.trim() ? 'var(--primary)' : 'var(--bg-tertiary)',\n color: dashboardName.trim() ? 'white' : 'var(--text-secondary)',\n border: 'none',\n borderRadius: '6px',\n cursor: dashboardName.trim() ? 'pointer' : 'not-allowed',\n fontSize: '14px',\n fontWeight: 500,\n }}\n >\n Create Dashboard\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n\n// ============================================================================\n// Sub-components\n// ============================================================================\n\ninterface TemplateCardProps {\n template: DashboardTemplateListItem;\n onSelect: () => void;\n renderRating: (rating: number | undefined, count: number) => React.ReactNode;\n}\n\nfunction TemplateCard({ template, onSelect, renderRating }: TemplateCardProps) {\n return (\n <div\n onClick={onSelect}\n style={{\n backgroundColor: 'var(--bg-secondary)',\n border: '1px solid var(--border-color)',\n borderRadius: '10px',\n overflow: 'hidden',\n cursor: 'pointer',\n transition: 'transform 0.15s, box-shadow 0.15s',\n }}\n onMouseOver={(e) => {\n (e.currentTarget as HTMLDivElement).style.transform = 'translateY(-2px)';\n (e.currentTarget as HTMLDivElement).style.boxShadow = '0 4px 12px rgba(0,0,0,0.1)';\n }}\n onMouseOut={(e) => {\n (e.currentTarget as HTMLDivElement).style.transform = 'none';\n (e.currentTarget as HTMLDivElement).style.boxShadow = 'none';\n }}\n >\n {/* Thumbnail */}\n <div\n style={{\n height: '140px',\n backgroundColor: 'var(--bg-tertiary)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderBottom: '1px solid var(--border-color)',\n }}\n >\n {template.previewUrl ? (\n <img\n src={template.previewUrl}\n alt={template.name}\n style={{ width: '100%', height: '100%', objectFit: 'cover' }}\n />\n ) : (\n <span style={{ fontSize: '40px', color: 'var(--text-tertiary)' }}>📊</span>\n )}\n </div>\n\n {/* Content */}\n <div style={{ padding: '16px' }}>\n <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: '8px' }}>\n <h3 style={{ margin: 0, fontSize: '14px', fontWeight: 600, lineHeight: '1.3' }}>{template.name}</h3>\n {template.isFeatured && (\n <span\n style={{\n fontSize: '9px',\n padding: '2px 6px',\n backgroundColor: '#fef3c7',\n color: '#92400e',\n borderRadius: '4px',\n fontWeight: 600,\n flexShrink: 0,\n }}\n >\n FEATURED\n </span>\n )}\n </div>\n\n {template.description && (\n <p\n style={{\n margin: '8px 0 0',\n fontSize: '12px',\n color: 'var(--text-secondary)',\n lineHeight: '1.4',\n display: '-webkit-box',\n WebkitLineClamp: 2,\n WebkitBoxOrient: 'vertical',\n overflow: 'hidden',\n }}\n >\n {template.description}\n </p>\n )}\n\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginTop: '12px', flexWrap: 'wrap' }}>\n <span\n style={{\n fontSize: '10px',\n padding: '2px 6px',\n backgroundColor: 'var(--bg-tertiary)',\n borderRadius: '4px',\n color: 'var(--text-secondary)',\n }}\n >\n {CATEGORY_LABELS[template.category]}\n </span>\n <span\n style={{\n fontSize: '10px',\n padding: '2px 6px',\n backgroundColor: `${COMPLEXITY_COLORS[template.complexity]}20`,\n color: COMPLEXITY_COLORS[template.complexity],\n borderRadius: '4px',\n fontWeight: 500,\n }}\n >\n {template.complexity}\n </span>\n {renderRating(template.rating, template.ratingCount)}\n </div>\n </div>\n </div>\n );\n}\n\ninterface TemplateListItemProps {\n template: DashboardTemplateListItem;\n onSelect: () => void;\n renderRating: (rating: number | undefined, count: number) => React.ReactNode;\n}\n\nfunction TemplateListItem({ template, onSelect, renderRating }: TemplateListItemProps) {\n return (\n <div\n onClick={onSelect}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '16px',\n padding: '16px',\n backgroundColor: 'var(--bg-secondary)',\n border: '1px solid var(--border-color)',\n borderRadius: '8px',\n cursor: 'pointer',\n transition: 'background-color 0.15s',\n }}\n >\n {/* Thumbnail */}\n <div\n style={{\n width: '80px',\n height: '60px',\n backgroundColor: 'var(--bg-tertiary)',\n borderRadius: '6px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}\n >\n {template.previewUrl ? (\n <img\n src={template.previewUrl}\n alt={template.name}\n style={{ width: '100%', height: '100%', objectFit: 'cover', borderRadius: '6px' }}\n />\n ) : (\n <span style={{ fontSize: '24px', color: 'var(--text-tertiary)' }}>📊</span>\n )}\n </div>\n\n {/* Content */}\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>\n <h3 style={{ margin: 0, fontSize: '14px', fontWeight: 600 }}>{template.name}</h3>\n {template.isFeatured && (\n <span\n style={{\n fontSize: '9px',\n padding: '2px 6px',\n backgroundColor: '#fef3c7',\n color: '#92400e',\n borderRadius: '4px',\n fontWeight: 600,\n }}\n >\n FEATURED\n </span>\n )}\n </div>\n {template.description && (\n <p\n style={{\n margin: '4px 0 0',\n fontSize: '12px',\n color: 'var(--text-secondary)',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {template.description}\n </p>\n )}\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginTop: '8px' }}>\n <span\n style={{\n fontSize: '10px',\n padding: '2px 6px',\n backgroundColor: 'var(--bg-tertiary)',\n borderRadius: '4px',\n }}\n >\n {CATEGORY_LABELS[template.category]}\n </span>\n <span\n style={{\n fontSize: '10px',\n padding: '2px 6px',\n backgroundColor: `${COMPLEXITY_COLORS[template.complexity]}20`,\n color: COMPLEXITY_COLORS[template.complexity],\n borderRadius: '4px',\n }}\n >\n {template.complexity}\n </span>\n {renderRating(template.rating, template.ratingCount)}\n <span style={{ fontSize: '11px', color: 'var(--text-tertiary)' }}>{template.usageCount} uses</span>\n </div>\n </div>\n\n {/* Action */}\n <button\n style={{\n padding: '8px 16px',\n backgroundColor: 'var(--primary)',\n color: 'white',\n border: 'none',\n borderRadius: '6px',\n cursor: 'pointer',\n fontSize: '13px',\n fontWeight: 500,\n flexShrink: 0,\n }}\n >\n Use Template\n </button>\n </div>\n );\n}\n\n// Compact template card for embedded mode\ninterface CompactTemplateCardProps {\n template: DashboardTemplateListItem;\n isSelected: boolean;\n onSelect: () => void;\n}\n\nfunction CompactTemplateCard({ template, isSelected, onSelect }: CompactTemplateCardProps) {\n return (\n <div\n onClick={onSelect}\n style={{\n backgroundColor: isSelected ? 'var(--color-action-primary-bg-subtle, #e0f2fe)' : 'var(--bg-secondary)',\n border: `2px solid ${isSelected ? 'var(--color-action-primary-border, #3b82f6)' : 'var(--border-color)'}`,\n borderRadius: '8px',\n overflow: 'hidden',\n cursor: 'pointer',\n transition: 'all 0.15s ease',\n }}\n >\n {/* Thumbnail */}\n <div\n style={{\n height: '80px',\n backgroundColor: 'var(--bg-tertiary)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderBottom: '1px solid var(--border-color)',\n }}\n >\n {template.previewUrl ? (\n <img\n src={template.previewUrl}\n alt={template.name}\n style={{ width: '100%', height: '100%', objectFit: 'cover' }}\n />\n ) : (\n <span style={{ fontSize: '28px', color: 'var(--text-tertiary)' }}>📊</span>\n )}\n </div>\n\n {/* Content */}\n <div style={{ padding: '10px' }}>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '4px' }}>\n <h4\n style={{\n margin: 0,\n fontSize: '12px',\n fontWeight: 600,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {template.name}\n </h4>\n {isSelected && (\n <span style={{ color: 'var(--color-action-primary-text, #3b82f6)', fontSize: '14px' }}>✓</span>\n )}\n </div>\n <div style={{ display: 'flex', gap: '4px', marginTop: '6px', flexWrap: 'wrap' }}>\n <span\n style={{\n fontSize: '9px',\n padding: '1px 4px',\n backgroundColor: 'var(--bg-tertiary)',\n borderRadius: '3px',\n color: 'var(--text-secondary)',\n }}\n >\n {CATEGORY_LABELS[template.category]}\n </span>\n <span\n style={{\n fontSize: '9px',\n padding: '1px 4px',\n backgroundColor: `${COMPLEXITY_COLORS[template.complexity]}20`,\n color: COMPLEXITY_COLORS[template.complexity],\n borderRadius: '3px',\n }}\n >\n {template.complexity}\n </span>\n </div>\n </div>\n </div>\n );\n}\n\nexport default TemplatePicker;\n"],"mappings":"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"}
1
+ {"version":3,"file":"TemplatePicker.js","names":[],"sources":["../../../../../src/bigconsole/components/dashboard/TemplatePicker/TemplatePicker.tsx"],"sourcesContent":["/**\n * TemplatePicker Component\n *\n * Grid/List view for browsing and selecting dashboard templates.\n */\n\nimport React, { useState, useEffect, useCallback } from 'react';\nimport {\n useDashboardTemplates,\n type DashboardTemplateListItem,\n type DashboardCategory,\n type TemplateComplexity,\n} from '../../../hooks';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TemplatePickerProps {\n /** Modal mode: whether the modal is open */\n isOpen?: boolean;\n /** Modal mode: callback to close the modal */\n onClose?: () => void;\n /** Modal mode: callback when template is selected with name and placeholders */\n onSelectTemplate?: (templateId: string, name: string, placeholderValues: Record<string, unknown>) => void;\n /** Embedded mode: currently selected template ID */\n selectedTemplateId?: string;\n /** Embedded mode: callback when template is selected */\n onSelect?: (template: DashboardTemplateListItem) => void;\n /** Embedded mode: compact display without modal wrapper */\n compact?: boolean;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst CATEGORY_LABELS: Record<DashboardCategory, string> = {\n ANALYTICS: 'Analytics',\n OPERATIONS: 'Operations',\n SALES: 'Sales',\n MARKETING: 'Marketing',\n FINANCE: 'Finance',\n HR: 'Human Resources',\n CUSTOM: 'Custom',\n};\n\nconst COMPLEXITY_COLORS: Record<TemplateComplexity, string> = {\n BEGINNER: '#22c55e',\n INTERMEDIATE: '#f59e0b',\n ADVANCED: '#ef4444',\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport function TemplatePicker({\n isOpen,\n onClose,\n onSelectTemplate,\n selectedTemplateId,\n onSelect,\n compact = false,\n}: TemplatePickerProps) {\n const { templates, featuredTemplates, categories, loading, fetchTemplates, fetchFeaturedTemplates, searchTemplates } =\n useDashboardTemplates();\n\n const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid');\n const [searchQuery, setSearchQuery] = useState('');\n const [selectedCategory, setSelectedCategory] = useState<DashboardCategory | ''>('');\n const [selectedComplexity, setSelectedComplexity] = useState<TemplateComplexity | ''>('');\n const [selectedTemplate, setSelectedTemplate] = useState<DashboardTemplateListItem | null>(null);\n const [showDetailsModal, setShowDetailsModal] = useState(false);\n const [dashboardName, setDashboardName] = useState('');\n const [placeholderValues, setPlaceholderValues] = useState<Record<string, unknown>>({});\n\n // Determine if we should be active (modal mode uses isOpen, compact mode is always active)\n const isActive = compact || isOpen;\n\n // Fetch templates on mount/activation\n useEffect(() => {\n if (isActive) {\n fetchTemplates();\n fetchFeaturedTemplates();\n }\n }, [isActive, fetchTemplates, fetchFeaturedTemplates]);\n\n // Handle search\n useEffect(() => {\n if (searchQuery) {\n const debounce = setTimeout(() => {\n searchTemplates(searchQuery, selectedCategory || undefined, selectedComplexity || undefined);\n }, 300);\n return () => clearTimeout(debounce);\n } else if (isActive) {\n fetchTemplates({\n category: selectedCategory || undefined,\n complexity: selectedComplexity || undefined,\n });\n }\n }, [searchQuery, selectedCategory, selectedComplexity, isActive, searchTemplates, fetchTemplates]);\n\n // Handle template selection\n const handleSelectTemplate = useCallback(\n (template: DashboardTemplateListItem) => {\n // In compact/embedded mode, just call onSelect\n if (compact && onSelect) {\n onSelect(template);\n return;\n }\n\n // In modal mode, show details modal\n setSelectedTemplate(template);\n setDashboardName(`${template.name} Dashboard`);\n setShowDetailsModal(true);\n },\n [compact, onSelect]\n );\n\n // Handle create from template\n const handleCreateFromTemplate = useCallback(async () => {\n if (!selectedTemplate || !dashboardName.trim()) return;\n\n onSelectTemplate?.(selectedTemplate.id, dashboardName.trim(), placeholderValues);\n setShowDetailsModal(false);\n setSelectedTemplate(null);\n setDashboardName('');\n setPlaceholderValues({});\n onClose?.();\n }, [selectedTemplate, dashboardName, placeholderValues, onSelectTemplate, onClose]);\n\n // Render star rating\n const renderRating = (rating: number | undefined, count: number) => {\n if (!rating) return null;\n return (\n <div style={{ display: 'flex', alignItems: 'center', gap: '4px' }}>\n <span style={{ color: '#f59e0b' }}>★</span>\n <span style={{ fontSize: '12px', color: 'var(--text-secondary)' }}>\n {rating.toFixed(1)} ({count})\n </span>\n </div>\n );\n };\n\n if (!isActive) return null;\n\n const displayTemplates = searchQuery || selectedCategory || selectedComplexity ? templates : featuredTemplates;\n\n // Compact/Embedded mode - render just the content without modal wrapper\n if (compact) {\n return (\n <div>\n {/* Compact Filters Bar */}\n <div style={{ display: 'flex', gap: '8px', marginBottom: '12px', flexWrap: 'wrap' }}>\n <input\n type=\"text\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n placeholder=\"Search templates...\"\n style={{\n flex: '1 1 150px',\n padding: '6px 10px',\n border: '1px solid var(--border-color)',\n borderRadius: '4px',\n fontSize: '12px',\n }}\n />\n <select\n value={selectedCategory}\n onChange={(e) => setSelectedCategory(e.target.value as DashboardCategory | '')}\n style={{\n padding: '6px 10px',\n border: '1px solid var(--border-color)',\n borderRadius: '4px',\n fontSize: '12px',\n backgroundColor: 'var(--bg-primary)',\n }}\n >\n <option value=\"\">All Categories</option>\n {categories.map((cat) => (\n <option key={cat} value={cat}>\n {CATEGORY_LABELS[cat]}\n </option>\n ))}\n </select>\n </div>\n\n {/* Compact Template Grid */}\n {loading && displayTemplates.length === 0 ? (\n <div style={{ textAlign: 'center', padding: '20px', color: 'var(--text-secondary)', fontSize: '13px' }}>\n Loading templates...\n </div>\n ) : displayTemplates.length === 0 ? (\n <div style={{ textAlign: 'center', padding: '20px', color: 'var(--text-secondary)', fontSize: '13px' }}>\n No templates found\n </div>\n ) : (\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fill, minmax(min(200px, 100%), 1fr))',\n gap: '12px',\n }}\n >\n {displayTemplates.map((template) => (\n <CompactTemplateCard\n key={template.id}\n template={template}\n isSelected={selectedTemplateId === template.id}\n onSelect={() => handleSelectTemplate(template)}\n />\n ))}\n </div>\n )}\n </div>\n );\n }\n\n // Modal mode - full modal wrapper\n return (\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.5)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 9999,\n }}\n onClick={onClose}\n >\n <div\n style={{\n width: '90%',\n maxWidth: '1000px',\n maxHeight: '85vh',\n backgroundColor: 'var(--bg-primary)',\n borderRadius: '12px',\n boxShadow: '0 8px 32px rgba(0, 0, 0, 0.2)',\n overflow: 'hidden',\n display: 'flex',\n flexDirection: 'column',\n }}\n onClick={(e) => e.stopPropagation()}\n >\n {/* Header */}\n <div\n style={{\n padding: '20px 24px',\n borderBottom: '1px solid var(--border-color)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n }}\n >\n <div>\n <h2 style={{ margin: 0, fontSize: '20px', fontWeight: 600 }}>Choose a Template</h2>\n <p style={{ margin: '4px 0 0', fontSize: '13px', color: 'var(--text-secondary)' }}>\n Start with a pre-built dashboard template\n </p>\n </div>\n <button\n onClick={onClose}\n style={{\n background: 'none',\n border: 'none',\n fontSize: '24px',\n cursor: 'pointer',\n color: 'var(--text-secondary)',\n }}\n >\n x\n </button>\n </div>\n\n {/* Filters Bar */}\n <div\n style={{\n padding: '16px 24px',\n borderBottom: '1px solid var(--border-color)',\n display: 'flex',\n gap: '12px',\n alignItems: 'center',\n flexWrap: 'wrap',\n }}\n >\n {/* Search */}\n <input\n type=\"text\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n placeholder=\"Search templates...\"\n style={{\n flex: '1 1 200px',\n padding: '8px 12px',\n border: '1px solid var(--border-color)',\n borderRadius: '6px',\n fontSize: '13px',\n }}\n />\n\n {/* Category Filter */}\n <select\n value={selectedCategory}\n onChange={(e) => setSelectedCategory(e.target.value as DashboardCategory | '')}\n style={{\n padding: '8px 12px',\n border: '1px solid var(--border-color)',\n borderRadius: '6px',\n fontSize: '13px',\n backgroundColor: 'var(--bg-primary)',\n }}\n >\n <option value=\"\">All Categories</option>\n {categories.map((cat) => (\n <option key={cat} value={cat}>\n {CATEGORY_LABELS[cat]}\n </option>\n ))}\n </select>\n\n {/* Complexity Filter */}\n <select\n value={selectedComplexity}\n onChange={(e) => setSelectedComplexity(e.target.value as TemplateComplexity | '')}\n style={{\n padding: '8px 12px',\n border: '1px solid var(--border-color)',\n borderRadius: '6px',\n fontSize: '13px',\n backgroundColor: 'var(--bg-primary)',\n }}\n >\n <option value=\"\">All Levels</option>\n <option value=\"BEGINNER\">Beginner</option>\n <option value=\"INTERMEDIATE\">Intermediate</option>\n <option value=\"ADVANCED\">Advanced</option>\n </select>\n\n {/* View Toggle */}\n <div style={{ display: 'flex', border: '1px solid var(--border-color)', borderRadius: '6px' }}>\n <button\n onClick={() => setViewMode('grid')}\n style={{\n padding: '8px 12px',\n backgroundColor: viewMode === 'grid' ? 'var(--bg-secondary)' : 'transparent',\n border: 'none',\n cursor: 'pointer',\n fontSize: '13px',\n }}\n >\n Grid\n </button>\n <button\n onClick={() => setViewMode('list')}\n style={{\n padding: '8px 12px',\n backgroundColor: viewMode === 'list' ? 'var(--bg-secondary)' : 'transparent',\n border: 'none',\n cursor: 'pointer',\n fontSize: '13px',\n }}\n >\n List\n </button>\n </div>\n </div>\n\n {/* Templates Content */}\n <div style={{ flex: 1, overflowY: 'auto', padding: '24px' }}>\n {loading && displayTemplates.length === 0 ? (\n <div style={{ textAlign: 'center', padding: '40px', color: 'var(--text-secondary)' }}>\n Loading templates...\n </div>\n ) : displayTemplates.length === 0 ? (\n <div style={{ textAlign: 'center', padding: '40px', color: 'var(--text-secondary)' }}>\n No templates found. Try adjusting your filters.\n </div>\n ) : viewMode === 'grid' ? (\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))',\n gap: '20px',\n }}\n >\n {displayTemplates.map((template) => (\n <TemplateCard\n key={template.id}\n template={template}\n onSelect={() => handleSelectTemplate(template)}\n renderRating={renderRating}\n />\n ))}\n </div>\n ) : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>\n {displayTemplates.map((template) => (\n <TemplateListItem\n key={template.id}\n template={template}\n onSelect={() => handleSelectTemplate(template)}\n renderRating={renderRating}\n />\n ))}\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div\n style={{\n padding: '16px 24px',\n borderTop: '1px solid var(--border-color)',\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n }}\n >\n <span style={{ fontSize: '13px', color: 'var(--text-secondary)' }}>\n {displayTemplates.length} templates available\n </span>\n <button\n onClick={onClose}\n style={{\n padding: '10px 20px',\n backgroundColor: 'transparent',\n border: '1px solid var(--border-color)',\n borderRadius: '6px',\n cursor: 'pointer',\n fontSize: '14px',\n }}\n >\n Cancel\n </button>\n </div>\n </div>\n\n {/* Template Details Modal */}\n {showDetailsModal && selectedTemplate && (\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.5)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 10000,\n }}\n onClick={() => setShowDetailsModal(false)}\n >\n <div\n style={{\n width: '500px',\n backgroundColor: 'var(--bg-primary)',\n borderRadius: '12px',\n boxShadow: '0 8px 32px rgba(0, 0, 0, 0.2)',\n overflow: 'hidden',\n }}\n onClick={(e) => e.stopPropagation()}\n >\n <div\n style={{\n padding: '20px 24px',\n borderBottom: '1px solid var(--border-color)',\n }}\n >\n <h3 style={{ margin: 0, fontSize: '18px', fontWeight: 600 }}>Create from Template</h3>\n <p style={{ margin: '4px 0 0', fontSize: '13px', color: 'var(--text-secondary)' }}>\n {selectedTemplate.name}\n </p>\n </div>\n <div style={{ padding: '24px' }}>\n <div style={{ marginBottom: '20px' }}>\n <label\n style={{\n display: 'block',\n marginBottom: '8px',\n fontSize: '13px',\n fontWeight: 500,\n }}\n >\n Dashboard Name *\n </label>\n <input\n type=\"text\"\n value={dashboardName}\n onChange={(e) => setDashboardName(e.target.value)}\n placeholder=\"Enter dashboard name...\"\n style={{\n width: '100%',\n padding: '10px 12px',\n border: '1px solid var(--border-color)',\n borderRadius: '6px',\n fontSize: '14px',\n }}\n />\n </div>\n\n {/* Template Info */}\n <div\n style={{\n padding: '16px',\n backgroundColor: 'var(--bg-secondary)',\n borderRadius: '8px',\n }}\n >\n <div style={{ fontSize: '13px', color: 'var(--text-secondary)', marginBottom: '8px' }}>\n Template Details\n </div>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '16px' }}>\n <div>\n <div style={{ fontSize: '11px', color: 'var(--text-tertiary)' }}>Category</div>\n <div style={{ fontSize: '13px' }}>{CATEGORY_LABELS[selectedTemplate.category]}</div>\n </div>\n <div>\n <div style={{ fontSize: '11px', color: 'var(--text-tertiary)' }}>Complexity</div>\n <div\n style={{\n fontSize: '13px',\n color: COMPLEXITY_COLORS[selectedTemplate.complexity],\n }}\n >\n {selectedTemplate.complexity}\n </div>\n </div>\n <div>\n <div style={{ fontSize: '11px', color: 'var(--text-tertiary)' }}>Used</div>\n <div style={{ fontSize: '13px' }}>{selectedTemplate.usageCount} times</div>\n </div>\n </div>\n </div>\n </div>\n <div\n style={{\n padding: '16px 24px',\n borderTop: '1px solid var(--border-color)',\n display: 'flex',\n justifyContent: 'flex-end',\n gap: '12px',\n }}\n >\n <button\n onClick={() => setShowDetailsModal(false)}\n style={{\n padding: '10px 20px',\n backgroundColor: 'transparent',\n border: '1px solid var(--border-color)',\n borderRadius: '6px',\n cursor: 'pointer',\n fontSize: '14px',\n }}\n >\n Cancel\n </button>\n <button\n onClick={handleCreateFromTemplate}\n disabled={!dashboardName.trim()}\n style={{\n padding: '10px 20px',\n backgroundColor: dashboardName.trim() ? 'var(--primary)' : 'var(--bg-tertiary)',\n color: dashboardName.trim() ? 'white' : 'var(--text-secondary)',\n border: 'none',\n borderRadius: '6px',\n cursor: dashboardName.trim() ? 'pointer' : 'not-allowed',\n fontSize: '14px',\n fontWeight: 500,\n }}\n >\n Create Dashboard\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n\n// ============================================================================\n// Sub-components\n// ============================================================================\n\ninterface TemplateCardProps {\n template: DashboardTemplateListItem;\n onSelect: () => void;\n renderRating: (rating: number | undefined, count: number) => React.ReactNode;\n}\n\nfunction TemplateCard({ template, onSelect, renderRating }: TemplateCardProps) {\n return (\n <div\n onClick={onSelect}\n style={{\n backgroundColor: 'var(--bg-secondary)',\n border: '1px solid var(--border-color)',\n borderRadius: '10px',\n overflow: 'hidden',\n cursor: 'pointer',\n transition: 'transform 0.15s, box-shadow 0.15s',\n }}\n onMouseOver={(e) => {\n (e.currentTarget as HTMLDivElement).style.transform = 'translateY(-2px)';\n (e.currentTarget as HTMLDivElement).style.boxShadow = '0 4px 12px rgba(0,0,0,0.1)';\n }}\n onMouseOut={(e) => {\n (e.currentTarget as HTMLDivElement).style.transform = 'none';\n (e.currentTarget as HTMLDivElement).style.boxShadow = 'none';\n }}\n >\n {/* Thumbnail */}\n <div\n style={{\n height: '140px',\n backgroundColor: 'var(--bg-tertiary)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderBottom: '1px solid var(--border-color)',\n }}\n >\n {template.previewUrl ? (\n <img\n src={template.previewUrl}\n alt={template.name}\n style={{ width: '100%', height: '100%', objectFit: 'cover' }}\n />\n ) : (\n <span style={{ fontSize: '40px', color: 'var(--text-tertiary)' }}>📊</span>\n )}\n </div>\n\n {/* Content */}\n <div style={{ padding: '16px' }}>\n <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: '8px' }}>\n <h3 style={{ margin: 0, fontSize: '14px', fontWeight: 600, lineHeight: '1.3' }}>{template.name}</h3>\n {template.isFeatured && (\n <span\n style={{\n fontSize: '9px',\n padding: '2px 6px',\n backgroundColor: '#fef3c7',\n color: '#92400e',\n borderRadius: '4px',\n fontWeight: 600,\n flexShrink: 0,\n }}\n >\n FEATURED\n </span>\n )}\n </div>\n\n {template.description && (\n <p\n style={{\n margin: '8px 0 0',\n fontSize: '12px',\n color: 'var(--text-secondary)',\n lineHeight: '1.4',\n display: '-webkit-box',\n WebkitLineClamp: 2,\n WebkitBoxOrient: 'vertical',\n overflow: 'hidden',\n }}\n >\n {template.description}\n </p>\n )}\n\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginTop: '12px', flexWrap: 'wrap' }}>\n <span\n style={{\n fontSize: '10px',\n padding: '2px 6px',\n backgroundColor: 'var(--bg-tertiary)',\n borderRadius: '4px',\n color: 'var(--text-secondary)',\n }}\n >\n {CATEGORY_LABELS[template.category]}\n </span>\n <span\n style={{\n fontSize: '10px',\n padding: '2px 6px',\n backgroundColor: `${COMPLEXITY_COLORS[template.complexity]}20`,\n color: COMPLEXITY_COLORS[template.complexity],\n borderRadius: '4px',\n fontWeight: 500,\n }}\n >\n {template.complexity}\n </span>\n {renderRating(template.rating, template.ratingCount)}\n </div>\n </div>\n </div>\n );\n}\n\ninterface TemplateListItemProps {\n template: DashboardTemplateListItem;\n onSelect: () => void;\n renderRating: (rating: number | undefined, count: number) => React.ReactNode;\n}\n\nfunction TemplateListItem({ template, onSelect, renderRating }: TemplateListItemProps) {\n return (\n <div\n onClick={onSelect}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '16px',\n padding: '16px',\n backgroundColor: 'var(--bg-secondary)',\n border: '1px solid var(--border-color)',\n borderRadius: '8px',\n cursor: 'pointer',\n transition: 'background-color 0.15s',\n }}\n >\n {/* Thumbnail */}\n <div\n style={{\n width: '80px',\n height: '60px',\n backgroundColor: 'var(--bg-tertiary)',\n borderRadius: '6px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}\n >\n {template.previewUrl ? (\n <img\n src={template.previewUrl}\n alt={template.name}\n style={{ width: '100%', height: '100%', objectFit: 'cover', borderRadius: '6px' }}\n />\n ) : (\n <span style={{ fontSize: '24px', color: 'var(--text-tertiary)' }}>📊</span>\n )}\n </div>\n\n {/* Content */}\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>\n <h3 style={{ margin: 0, fontSize: '14px', fontWeight: 600 }}>{template.name}</h3>\n {template.isFeatured && (\n <span\n style={{\n fontSize: '9px',\n padding: '2px 6px',\n backgroundColor: '#fef3c7',\n color: '#92400e',\n borderRadius: '4px',\n fontWeight: 600,\n }}\n >\n FEATURED\n </span>\n )}\n </div>\n {template.description && (\n <p\n style={{\n margin: '4px 0 0',\n fontSize: '12px',\n color: 'var(--text-secondary)',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {template.description}\n </p>\n )}\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginTop: '8px' }}>\n <span\n style={{\n fontSize: '10px',\n padding: '2px 6px',\n backgroundColor: 'var(--bg-tertiary)',\n borderRadius: '4px',\n }}\n >\n {CATEGORY_LABELS[template.category]}\n </span>\n <span\n style={{\n fontSize: '10px',\n padding: '2px 6px',\n backgroundColor: `${COMPLEXITY_COLORS[template.complexity]}20`,\n color: COMPLEXITY_COLORS[template.complexity],\n borderRadius: '4px',\n }}\n >\n {template.complexity}\n </span>\n {renderRating(template.rating, template.ratingCount)}\n <span style={{ fontSize: '11px', color: 'var(--text-tertiary)' }}>{template.usageCount} uses</span>\n </div>\n </div>\n\n {/* Action */}\n <button\n style={{\n padding: '8px 16px',\n backgroundColor: 'var(--primary)',\n color: 'white',\n border: 'none',\n borderRadius: '6px',\n cursor: 'pointer',\n fontSize: '13px',\n fontWeight: 500,\n flexShrink: 0,\n }}\n >\n Use Template\n </button>\n </div>\n );\n}\n\n// Compact template card for embedded mode\ninterface CompactTemplateCardProps {\n template: DashboardTemplateListItem;\n isSelected: boolean;\n onSelect: () => void;\n}\n\nfunction CompactTemplateCard({ template, isSelected, onSelect }: CompactTemplateCardProps) {\n return (\n <div\n onClick={onSelect}\n style={{\n backgroundColor: isSelected ? 'var(--color-action-primary-bg-subtle, #e0f2fe)' : 'var(--bg-secondary)',\n border: `2px solid ${isSelected ? 'var(--color-action-primary-border, #3b82f6)' : 'var(--border-color)'}`,\n borderRadius: '8px',\n overflow: 'hidden',\n cursor: 'pointer',\n transition: 'all 0.15s ease',\n }}\n >\n {/* Thumbnail */}\n <div\n style={{\n height: '80px',\n backgroundColor: 'var(--bg-tertiary)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderBottom: '1px solid var(--border-color)',\n }}\n >\n {template.previewUrl ? (\n <img\n src={template.previewUrl}\n alt={template.name}\n style={{ width: '100%', height: '100%', objectFit: 'cover' }}\n />\n ) : (\n <span style={{ fontSize: '28px', color: 'var(--text-tertiary)' }}>📊</span>\n )}\n </div>\n\n {/* Content */}\n <div style={{ padding: '10px' }}>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '4px' }}>\n <h4\n style={{\n margin: 0,\n fontSize: '12px',\n fontWeight: 600,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {template.name}\n </h4>\n {isSelected && (\n <span style={{ color: 'var(--color-action-primary-text, #3b82f6)', fontSize: '14px' }}>✓</span>\n )}\n </div>\n <div style={{ display: 'flex', gap: '4px', marginTop: '6px', flexWrap: 'wrap' }}>\n <span\n style={{\n fontSize: '9px',\n padding: '1px 4px',\n backgroundColor: 'var(--bg-tertiary)',\n borderRadius: '3px',\n color: 'var(--text-secondary)',\n }}\n >\n {CATEGORY_LABELS[template.category]}\n </span>\n <span\n style={{\n fontSize: '9px',\n padding: '1px 4px',\n backgroundColor: `${COMPLEXITY_COLORS[template.complexity]}20`,\n color: COMPLEXITY_COLORS[template.complexity],\n borderRadius: '3px',\n }}\n >\n {template.complexity}\n </span>\n </div>\n </div>\n </div>\n );\n}\n\nexport default TemplatePicker;\n"],"mappings":";;;;;AAqCA,IAAM,IAAqD;CACzD,WAAW;CACX,YAAY;CACZ,OAAO;CACP,WAAW;CACX,SAAS;CACT,IAAI;CACJ,QAAQ;CACT,EAEK,IAAwD;CAC5D,UAAU;CACV,cAAc;CACd,UAAU;CACX;AAMD,SAAgB,EAAe,EAC7B,WACA,YACA,qBACA,uBACA,aACA,aAAU,MACY;CACtB,IAAM,EAAE,cAAW,sBAAmB,eAAY,YAAS,mBAAgB,2BAAwB,uBACjG,GAAuB,EAEnB,CAAC,GAAU,KAAe,EAA0B,OAAO,EAC3D,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,CAAC,GAAkB,KAAuB,EAAiC,GAAG,EAC9E,CAAC,GAAoB,KAAyB,EAAkC,GAAG,EACnF,CAAC,GAAkB,KAAuB,EAA2C,KAAK,EAC1F,CAAC,GAAkB,KAAuB,EAAS,GAAM,EACzD,CAAC,GAAe,KAAoB,EAAS,GAAG,EAChD,CAAC,GAAmB,KAAwB,EAAkC,EAAE,CAAC,EAGjF,IAAW,KAAW;AAW5B,CARA,QAAgB;AACd,EAAI,MACF,GAAgB,EAChB,GAAwB;IAEzB;EAAC;EAAU;EAAgB;EAAuB,CAAC,EAGtD,QAAgB;AACd,MAAI,GAAa;GACf,IAAM,IAAW,iBAAiB;AAChC,MAAgB,GAAa,KAAoB,KAAA,GAAW,KAAsB,KAAA,EAAU;MAC3F,IAAI;AACP,gBAAa,aAAa,EAAS;SAC1B,KACT,EAAe;GACb,UAAU,KAAoB,KAAA;GAC9B,YAAY,KAAsB,KAAA;GACnC,CAAC;IAEH;EAAC;EAAa;EAAkB;EAAoB;EAAU;EAAiB;EAAe,CAAC;CAGlG,IAAM,IAAuB,GAC1B,MAAwC;AAEvC,MAAI,KAAW,GAAU;AACvB,KAAS,EAAS;AAClB;;AAMF,EAFA,EAAoB,EAAS,EAC7B,EAAiB,GAAG,EAAS,KAAK,YAAY,EAC9C,EAAoB,GAAK;IAE3B,CAAC,GAAS,EAAS,CACpB,EAGK,IAA2B,EAAY,YAAY;AACnD,GAAC,KAAoB,CAAC,EAAc,MAAM,KAE9C,IAAmB,EAAiB,IAAI,EAAc,MAAM,EAAE,EAAkB,EAChF,EAAoB,GAAM,EAC1B,EAAoB,KAAK,EACzB,EAAiB,GAAG,EACpB,EAAqB,EAAE,CAAC,EACxB,KAAW;IACV;EAAC;EAAkB;EAAe;EAAmB;EAAkB;EAAQ,CAAC,EAG7E,KAAgB,GAA4B,MAC3C,IAEH,kBAAC,OAAD;EAAK,OAAO;GAAE,SAAS;GAAQ,YAAY;GAAU,KAAK;GAAO;YAAjE,CACE,kBAAC,QAAD;GAAM,OAAO,EAAE,OAAO,WAAW;aAAE;GAAQ,CAAA,EAC3C,kBAAC,QAAD;GAAM,OAAO;IAAE,UAAU;IAAQ,OAAO;IAAyB;aAAjE;IACG,EAAO,QAAQ,EAAE;IAAC;IAAG;IAAM;IACvB;KACH;MAPY;AAWtB,KAAI,CAAC,EAAU,QAAO;CAEtB,IAAM,IAAmB,KAAe,KAAoB,IAAqB,IAAY;AAyE7F,QAtEI,IAEA,kBAAC,OAAD,EAAA,UAAA,CAEE,kBAAC,OAAD;EAAK,OAAO;GAAE,SAAS;GAAQ,KAAK;GAAO,cAAc;GAAQ,UAAU;GAAQ;YAAnF,CACE,kBAAC,SAAD;GACE,MAAK;GACL,OAAO;GACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAM;GAC/C,aAAY;GACZ,OAAO;IACL,MAAM;IACN,SAAS;IACT,QAAQ;IACR,cAAc;IACd,UAAU;IACX;GACD,CAAA,EACF,kBAAC,UAAD;GACE,OAAO;GACP,WAAW,MAAM,EAAoB,EAAE,OAAO,MAAgC;GAC9E,OAAO;IACL,SAAS;IACT,QAAQ;IACR,cAAc;IACd,UAAU;IACV,iBAAiB;IAClB;aATH,CAWE,kBAAC,UAAD;IAAQ,OAAM;cAAG;IAAuB,CAAA,EACvC,EAAW,KAAK,MACf,kBAAC,UAAD;IAAkB,OAAO;cACtB,EAAgB;IACV,EAFI,EAEJ,CACT,CACK;KACL;KAGL,KAAW,EAAiB,WAAW,IACtC,kBAAC,OAAD;EAAK,OAAO;GAAE,WAAW;GAAU,SAAS;GAAQ,OAAO;GAAyB,UAAU;GAAQ;YAAE;EAElG,CAAA,GACJ,EAAiB,WAAW,IAC9B,kBAAC,OAAD;EAAK,OAAO;GAAE,WAAW;GAAU,SAAS;GAAQ,OAAO;GAAyB,UAAU;GAAQ;YAAE;EAElG,CAAA,GAEN,kBAAC,OAAD;EACE,OAAO;GACL,SAAS;GACT,qBAAqB;GACrB,KAAK;GACN;YAEA,EAAiB,KAAK,MACrB,kBAAC,GAAD;GAEY;GACV,YAAY,MAAuB,EAAS;GAC5C,gBAAgB,EAAqB,EAAS;GAC9C,EAJK,EAAS,GAId,CACF;EACE,CAAA,CAEJ,EAAA,CAAA,GAMR,kBAAC,OAAD;EACE,OAAO;GACL,UAAU;GACV,KAAK;GACL,MAAM;GACN,OAAO;GACP,QAAQ;GACR,iBAAiB;GACjB,SAAS;GACT,YAAY;GACZ,gBAAgB;GAChB,QAAQ;GACT;EACD,SAAS;YAbX,CAeE,kBAAC,OAAD;GACE,OAAO;IACL,OAAO;IACP,UAAU;IACV,WAAW;IACX,iBAAiB;IACjB,cAAc;IACd,WAAW;IACX,UAAU;IACV,SAAS;IACT,eAAe;IAChB;GACD,UAAU,MAAM,EAAE,iBAAiB;aAZrC;IAeE,kBAAC,OAAD;KACE,OAAO;MACL,SAAS;MACT,cAAc;MACd,SAAS;MACT,YAAY;MACZ,gBAAgB;MACjB;eAPH,CASE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;MAAI,OAAO;OAAE,QAAQ;OAAG,UAAU;OAAQ,YAAY;OAAK;gBAAE;MAAsB,CAAA,EACnF,kBAAC,KAAD;MAAG,OAAO;OAAE,QAAQ;OAAW,UAAU;OAAQ,OAAO;OAAyB;gBAAE;MAE/E,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,UAAD;MACE,SAAS;MACT,OAAO;OACL,YAAY;OACZ,QAAQ;OACR,UAAU;OACV,QAAQ;OACR,OAAO;OACR;gBACF;MAEQ,CAAA,CACL;;IAGN,kBAAC,OAAD;KACE,OAAO;MACL,SAAS;MACT,cAAc;MACd,SAAS;MACT,KAAK;MACL,YAAY;MACZ,UAAU;MACX;eARH;MAWE,kBAAC,SAAD;OACE,MAAK;OACL,OAAO;OACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAM;OAC/C,aAAY;OACZ,OAAO;QACL,MAAM;QACN,SAAS;QACT,QAAQ;QACR,cAAc;QACd,UAAU;QACX;OACD,CAAA;MAGF,kBAAC,UAAD;OACE,OAAO;OACP,WAAW,MAAM,EAAoB,EAAE,OAAO,MAAgC;OAC9E,OAAO;QACL,SAAS;QACT,QAAQ;QACR,cAAc;QACd,UAAU;QACV,iBAAiB;QAClB;iBATH,CAWE,kBAAC,UAAD;QAAQ,OAAM;kBAAG;QAAuB,CAAA,EACvC,EAAW,KAAK,MACf,kBAAC,UAAD;QAAkB,OAAO;kBACtB,EAAgB;QACV,EAFI,EAEJ,CACT,CACK;;MAGT,kBAAC,UAAD;OACE,OAAO;OACP,WAAW,MAAM,EAAsB,EAAE,OAAO,MAAiC;OACjF,OAAO;QACL,SAAS;QACT,QAAQ;QACR,cAAc;QACd,UAAU;QACV,iBAAiB;QAClB;iBATH;QAWE,kBAAC,UAAD;SAAQ,OAAM;mBAAG;SAAmB,CAAA;QACpC,kBAAC,UAAD;SAAQ,OAAM;mBAAW;SAAiB,CAAA;QAC1C,kBAAC,UAAD;SAAQ,OAAM;mBAAe;SAAqB,CAAA;QAClD,kBAAC,UAAD;SAAQ,OAAM;mBAAW;SAAiB,CAAA;QACnC;;MAGT,kBAAC,OAAD;OAAK,OAAO;QAAE,SAAS;QAAQ,QAAQ;QAAiC,cAAc;QAAO;iBAA7F,CACE,kBAAC,UAAD;QACE,eAAe,EAAY,OAAO;QAClC,OAAO;SACL,SAAS;SACT,iBAAiB,MAAa,SAAS,wBAAwB;SAC/D,QAAQ;SACR,QAAQ;SACR,UAAU;SACX;kBACF;QAEQ,CAAA,EACT,kBAAC,UAAD;QACE,eAAe,EAAY,OAAO;QAClC,OAAO;SACL,SAAS;SACT,iBAAiB,MAAa,SAAS,wBAAwB;SAC/D,QAAQ;SACR,QAAQ;SACR,UAAU;SACX;kBACF;QAEQ,CAAA,CACL;;MACF;;IAGN,kBAAC,OAAD;KAAK,OAAO;MAAE,MAAM;MAAG,WAAW;MAAQ,SAAS;MAAQ;eACxD,KAAW,EAAiB,WAAW,IACtC,kBAAC,OAAD;MAAK,OAAO;OAAE,WAAW;OAAU,SAAS;OAAQ,OAAO;OAAyB;gBAAE;MAEhF,CAAA,GACJ,EAAiB,WAAW,IAC9B,kBAAC,OAAD;MAAK,OAAO;OAAE,WAAW;OAAU,SAAS;OAAQ,OAAO;OAAyB;gBAAE;MAEhF,CAAA,GACJ,MAAa,SACf,kBAAC,OAAD;MACE,OAAO;OACL,SAAS;OACT,qBAAqB;OACrB,KAAK;OACN;gBAEA,EAAiB,KAAK,MACrB,kBAAC,GAAD;OAEY;OACV,gBAAgB,EAAqB,EAAS;OAChC;OACd,EAJK,EAAS,GAId,CACF;MACE,CAAA,GAEN,kBAAC,OAAD;MAAK,OAAO;OAAE,SAAS;OAAQ,eAAe;OAAU,KAAK;OAAQ;gBAClE,EAAiB,KAAK,MACrB,kBAAC,GAAD;OAEY;OACV,gBAAgB,EAAqB,EAAS;OAChC;OACd,EAJK,EAAS,GAId,CACF;MACE,CAAA;KAEJ,CAAA;IAGN,kBAAC,OAAD;KACE,OAAO;MACL,SAAS;MACT,WAAW;MACX,SAAS;MACT,gBAAgB;MAChB,YAAY;MACb;eAPH,CASE,kBAAC,QAAD;MAAM,OAAO;OAAE,UAAU;OAAQ,OAAO;OAAyB;gBAAjE,CACG,EAAiB,QAAO,uBACpB;SACP,kBAAC,UAAD;MACE,SAAS;MACT,OAAO;OACL,SAAS;OACT,iBAAiB;OACjB,QAAQ;OACR,cAAc;OACd,QAAQ;OACR,UAAU;OACX;gBACF;MAEQ,CAAA,CACL;;IACF;MAGL,KAAoB,KACnB,kBAAC,OAAD;GACE,OAAO;IACL,UAAU;IACV,KAAK;IACL,MAAM;IACN,OAAO;IACP,QAAQ;IACR,iBAAiB;IACjB,SAAS;IACT,YAAY;IACZ,gBAAgB;IAChB,QAAQ;IACT;GACD,eAAe,EAAoB,GAAM;aAEzC,kBAAC,OAAD;IACE,OAAO;KACL,OAAO;KACP,iBAAiB;KACjB,cAAc;KACd,WAAW;KACX,UAAU;KACX;IACD,UAAU,MAAM,EAAE,iBAAiB;cARrC;KAUE,kBAAC,OAAD;MACE,OAAO;OACL,SAAS;OACT,cAAc;OACf;gBAJH,CAME,kBAAC,MAAD;OAAI,OAAO;QAAE,QAAQ;QAAG,UAAU;QAAQ,YAAY;QAAK;iBAAE;OAAyB,CAAA,EACtF,kBAAC,KAAD;OAAG,OAAO;QAAE,QAAQ;QAAW,UAAU;QAAQ,OAAO;QAAyB;iBAC9E,EAAiB;OAChB,CAAA,CACA;;KACN,kBAAC,OAAD;MAAK,OAAO,EAAE,SAAS,QAAQ;gBAA/B,CACE,kBAAC,OAAD;OAAK,OAAO,EAAE,cAAc,QAAQ;iBAApC,CACE,kBAAC,SAAD;QACE,OAAO;SACL,SAAS;SACT,cAAc;SACd,UAAU;SACV,YAAY;SACb;kBACF;QAEO,CAAA,EACR,kBAAC,SAAD;QACE,MAAK;QACL,OAAO;QACP,WAAW,MAAM,EAAiB,EAAE,OAAO,MAAM;QACjD,aAAY;QACZ,OAAO;SACL,OAAO;SACP,SAAS;SACT,QAAQ;SACR,cAAc;SACd,UAAU;SACX;QACD,CAAA,CACE;UAGN,kBAAC,OAAD;OACE,OAAO;QACL,SAAS;QACT,iBAAiB;QACjB,cAAc;QACf;iBALH,CAOE,kBAAC,OAAD;QAAK,OAAO;SAAE,UAAU;SAAQ,OAAO;SAAyB,cAAc;SAAO;kBAAE;QAEjF,CAAA,EACN,kBAAC,OAAD;QAAK,OAAO;SAAE,SAAS;SAAQ,UAAU;SAAQ,KAAK;SAAQ;kBAA9D;SACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;UAAK,OAAO;WAAE,UAAU;WAAQ,OAAO;WAAwB;oBAAE;UAAc,CAAA,EAC/E,kBAAC,OAAD;UAAK,OAAO,EAAE,UAAU,QAAQ;oBAAG,EAAgB,EAAiB;UAAgB,CAAA,CAChF,EAAA,CAAA;SACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;UAAK,OAAO;WAAE,UAAU;WAAQ,OAAO;WAAwB;oBAAE;UAAgB,CAAA,EACjF,kBAAC,OAAD;UACE,OAAO;WACL,UAAU;WACV,OAAO,EAAkB,EAAiB;WAC3C;oBAEA,EAAiB;UACd,CAAA,CACF,EAAA,CAAA;SACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;UAAK,OAAO;WAAE,UAAU;WAAQ,OAAO;WAAwB;oBAAE;UAAU,CAAA,EAC3E,kBAAC,OAAD;UAAK,OAAO,EAAE,UAAU,QAAQ;oBAAhC,CAAmC,EAAiB,YAAW,SAAY;YACvE,EAAA,CAAA;SACF;UACF;SACF;;KACN,kBAAC,OAAD;MACE,OAAO;OACL,SAAS;OACT,WAAW;OACX,SAAS;OACT,gBAAgB;OAChB,KAAK;OACN;gBAPH,CASE,kBAAC,UAAD;OACE,eAAe,EAAoB,GAAM;OACzC,OAAO;QACL,SAAS;QACT,iBAAiB;QACjB,QAAQ;QACR,cAAc;QACd,QAAQ;QACR,UAAU;QACX;iBACF;OAEQ,CAAA,EACT,kBAAC,UAAD;OACE,SAAS;OACT,UAAU,CAAC,EAAc,MAAM;OAC/B,OAAO;QACL,SAAS;QACT,iBAAiB,EAAc,MAAM,GAAG,mBAAmB;QAC3D,OAAO,EAAc,MAAM,GAAG,UAAU;QACxC,QAAQ;QACR,cAAc;QACd,QAAQ,EAAc,MAAM,GAAG,YAAY;QAC3C,UAAU;QACV,YAAY;QACb;iBACF;OAEQ,CAAA,CACL;;KACF;;GACF,CAAA,CAEJ;;;AAcV,SAAS,EAAa,EAAE,aAAU,aAAU,mBAAmC;AAC7E,QACE,kBAAC,OAAD;EACE,SAAS;EACT,OAAO;GACL,iBAAiB;GACjB,QAAQ;GACR,cAAc;GACd,UAAU;GACV,QAAQ;GACR,YAAY;GACb;EACD,cAAc,MAAM;AAEjB,GADA,EAAE,cAAiC,MAAM,YAAY,oBACrD,EAAE,cAAiC,MAAM,YAAY;;EAExD,aAAa,MAAM;AAEhB,GADA,EAAE,cAAiC,MAAM,YAAY,QACrD,EAAE,cAAiC,MAAM,YAAY;;YAhB1D,CAoBE,kBAAC,OAAD;GACE,OAAO;IACL,QAAQ;IACR,iBAAiB;IACjB,SAAS;IACT,YAAY;IACZ,gBAAgB;IAChB,cAAc;IACf;aAEA,EAAS,aACR,kBAAC,OAAD;IACE,KAAK,EAAS;IACd,KAAK,EAAS;IACd,OAAO;KAAE,OAAO;KAAQ,QAAQ;KAAQ,WAAW;KAAS;IAC5D,CAAA,GAEF,kBAAC,QAAD;IAAM,OAAO;KAAE,UAAU;KAAQ,OAAO;KAAwB;cAAE;IAAS,CAAA;GAEzE,CAAA,EAGN,kBAAC,OAAD;GAAK,OAAO,EAAE,SAAS,QAAQ;aAA/B;IACE,kBAAC,OAAD;KAAK,OAAO;MAAE,SAAS;MAAQ,YAAY;MAAc,gBAAgB;MAAiB,KAAK;MAAO;eAAtG,CACE,kBAAC,MAAD;MAAI,OAAO;OAAE,QAAQ;OAAG,UAAU;OAAQ,YAAY;OAAK,YAAY;OAAO;gBAAG,EAAS;MAAU,CAAA,EACnG,EAAS,cACR,kBAAC,QAAD;MACE,OAAO;OACL,UAAU;OACV,SAAS;OACT,iBAAiB;OACjB,OAAO;OACP,cAAc;OACd,YAAY;OACZ,YAAY;OACb;gBACF;MAEM,CAAA,CAEL;;IAEL,EAAS,eACR,kBAAC,KAAD;KACE,OAAO;MACL,QAAQ;MACR,UAAU;MACV,OAAO;MACP,YAAY;MACZ,SAAS;MACT,iBAAiB;MACjB,iBAAiB;MACjB,UAAU;MACX;eAEA,EAAS;KACR,CAAA;IAGN,kBAAC,OAAD;KAAK,OAAO;MAAE,SAAS;MAAQ,YAAY;MAAU,KAAK;MAAO,WAAW;MAAQ,UAAU;MAAQ;eAAtG;MACE,kBAAC,QAAD;OACE,OAAO;QACL,UAAU;QACV,SAAS;QACT,iBAAiB;QACjB,cAAc;QACd,OAAO;QACR;iBAEA,EAAgB,EAAS;OACrB,CAAA;MACP,kBAAC,QAAD;OACE,OAAO;QACL,UAAU;QACV,SAAS;QACT,iBAAiB,GAAG,EAAkB,EAAS,YAAY;QAC3D,OAAO,EAAkB,EAAS;QAClC,cAAc;QACd,YAAY;QACb;iBAEA,EAAS;OACL,CAAA;MACN,EAAa,EAAS,QAAQ,EAAS,YAAY;MAChD;;IACF;KACF;;;AAUV,SAAS,EAAiB,EAAE,aAAU,aAAU,mBAAuC;AACrF,QACE,kBAAC,OAAD;EACE,SAAS;EACT,OAAO;GACL,SAAS;GACT,YAAY;GACZ,KAAK;GACL,SAAS;GACT,iBAAiB;GACjB,QAAQ;GACR,cAAc;GACd,QAAQ;GACR,YAAY;GACb;YAZH;GAeE,kBAAC,OAAD;IACE,OAAO;KACL,OAAO;KACP,QAAQ;KACR,iBAAiB;KACjB,cAAc;KACd,SAAS;KACT,YAAY;KACZ,gBAAgB;KAChB,YAAY;KACb;cAEA,EAAS,aACR,kBAAC,OAAD;KACE,KAAK,EAAS;KACd,KAAK,EAAS;KACd,OAAO;MAAE,OAAO;MAAQ,QAAQ;MAAQ,WAAW;MAAS,cAAc;MAAO;KACjF,CAAA,GAEF,kBAAC,QAAD;KAAM,OAAO;MAAE,UAAU;MAAQ,OAAO;MAAwB;eAAE;KAAS,CAAA;IAEzE,CAAA;GAGN,kBAAC,OAAD;IAAK,OAAO;KAAE,MAAM;KAAG,UAAU;KAAG;cAApC;KACE,kBAAC,OAAD;MAAK,OAAO;OAAE,SAAS;OAAQ,YAAY;OAAU,KAAK;OAAO;gBAAjE,CACE,kBAAC,MAAD;OAAI,OAAO;QAAE,QAAQ;QAAG,UAAU;QAAQ,YAAY;QAAK;iBAAG,EAAS;OAAU,CAAA,EAChF,EAAS,cACR,kBAAC,QAAD;OACE,OAAO;QACL,UAAU;QACV,SAAS;QACT,iBAAiB;QACjB,OAAO;QACP,cAAc;QACd,YAAY;QACb;iBACF;OAEM,CAAA,CAEL;;KACL,EAAS,eACR,kBAAC,KAAD;MACE,OAAO;OACL,QAAQ;OACR,UAAU;OACV,OAAO;OACP,YAAY;OACZ,UAAU;OACV,cAAc;OACf;gBAEA,EAAS;MACR,CAAA;KAEN,kBAAC,OAAD;MAAK,OAAO;OAAE,SAAS;OAAQ,YAAY;OAAU,KAAK;OAAO,WAAW;OAAO;gBAAnF;OACE,kBAAC,QAAD;QACE,OAAO;SACL,UAAU;SACV,SAAS;SACT,iBAAiB;SACjB,cAAc;SACf;kBAEA,EAAgB,EAAS;QACrB,CAAA;OACP,kBAAC,QAAD;QACE,OAAO;SACL,UAAU;SACV,SAAS;SACT,iBAAiB,GAAG,EAAkB,EAAS,YAAY;SAC3D,OAAO,EAAkB,EAAS;SAClC,cAAc;SACf;kBAEA,EAAS;QACL,CAAA;OACN,EAAa,EAAS,QAAQ,EAAS,YAAY;OACpD,kBAAC,QAAD;QAAM,OAAO;SAAE,UAAU;SAAQ,OAAO;SAAwB;kBAAhE,CAAmE,EAAS,YAAW,QAAY;;OAC/F;;KACF;;GAGN,kBAAC,UAAD;IACE,OAAO;KACL,SAAS;KACT,iBAAiB;KACjB,OAAO;KACP,QAAQ;KACR,cAAc;KACd,QAAQ;KACR,UAAU;KACV,YAAY;KACZ,YAAY;KACb;cACF;IAEQ,CAAA;GACL;;;AAWV,SAAS,EAAoB,EAAE,aAAU,eAAY,eAAsC;AACzF,QACE,kBAAC,OAAD;EACE,SAAS;EACT,OAAO;GACL,iBAAiB,IAAa,mDAAmD;GACjF,QAAQ,aAAa,IAAa,gDAAgD;GAClF,cAAc;GACd,UAAU;GACV,QAAQ;GACR,YAAY;GACb;YATH,CAYE,kBAAC,OAAD;GACE,OAAO;IACL,QAAQ;IACR,iBAAiB;IACjB,SAAS;IACT,YAAY;IACZ,gBAAgB;IAChB,cAAc;IACf;aAEA,EAAS,aACR,kBAAC,OAAD;IACE,KAAK,EAAS;IACd,KAAK,EAAS;IACd,OAAO;KAAE,OAAO;KAAQ,QAAQ;KAAQ,WAAW;KAAS;IAC5D,CAAA,GAEF,kBAAC,QAAD;IAAM,OAAO;KAAE,UAAU;KAAQ,OAAO;KAAwB;cAAE;IAAS,CAAA;GAEzE,CAAA,EAGN,kBAAC,OAAD;GAAK,OAAO,EAAE,SAAS,QAAQ;aAA/B,CACE,kBAAC,OAAD;IAAK,OAAO;KAAE,SAAS;KAAQ,YAAY;KAAU,gBAAgB;KAAiB,KAAK;KAAO;cAAlG,CACE,kBAAC,MAAD;KACE,OAAO;MACL,QAAQ;MACR,UAAU;MACV,YAAY;MACZ,YAAY;MACZ,UAAU;MACV,cAAc;MACf;eAEA,EAAS;KACP,CAAA,EACJ,KACC,kBAAC,QAAD;KAAM,OAAO;MAAE,OAAO;MAA6C,UAAU;MAAQ;eAAE;KAAQ,CAAA,CAE7F;OACN,kBAAC,OAAD;IAAK,OAAO;KAAE,SAAS;KAAQ,KAAK;KAAO,WAAW;KAAO,UAAU;KAAQ;cAA/E,CACE,kBAAC,QAAD;KACE,OAAO;MACL,UAAU;MACV,SAAS;MACT,iBAAiB;MACjB,cAAc;MACd,OAAO;MACR;eAEA,EAAgB,EAAS;KACrB,CAAA,EACP,kBAAC,QAAD;KACE,OAAO;MACL,UAAU;MACV,SAAS;MACT,iBAAiB,GAAG,EAAkB,EAAS,YAAY;MAC3D,OAAO,EAAkB,EAAS;MAClC,cAAc;MACf;eAEA,EAAS;KACL,CAAA,CACH;MACF;KACF"}
@@ -29,7 +29,9 @@ var A = c(function() {
29
29
  tags: e.tags
30
30
  });
31
31
  t && (F(!1), c(`/dashboards/${t.id}/builder`));
32
- } catch {} finally {
32
+ } catch (e) {
33
+ throw console.error("Failed to create dashboard:", e), i() && s("error"), e;
34
+ } finally {
33
35
  L(!1);
34
36
  }
35
37
  }, [U, c]), X = l((e) => {
@@ -118,13 +120,16 @@ var A = c(function() {
118
120
  style: {
119
121
  display: "flex",
120
122
  alignItems: "center",
121
- justifyContent: "space-between"
123
+ justifyContent: "space-between",
124
+ flexWrap: "wrap",
125
+ gap: "var(--space-formGap)"
122
126
  },
123
127
  children: [/* @__PURE__ */ C("div", {
124
128
  style: {
125
129
  display: "flex",
126
130
  alignItems: "center",
127
- gap: "var(--space-formGap)"
131
+ gap: "var(--space-formGap)",
132
+ minWidth: 0
128
133
  },
129
134
  children: [/* @__PURE__ */ S("div", {
130
135
  style: {
@@ -161,7 +166,8 @@ var A = c(function() {
161
166
  style: {
162
167
  display: "flex",
163
168
  alignItems: "center",
164
- gap: "var(--space-controlGap)"
169
+ gap: "var(--space-controlGap)",
170
+ flexWrap: "wrap"
165
171
  },
166
172
  children: [/* @__PURE__ */ C(T, {
167
173
  variant: "outline",
@@ -238,7 +244,7 @@ var A = c(function() {
238
244
  !B && K.length > 0 && /* @__PURE__ */ S("div", {
239
245
  style: {
240
246
  display: "grid",
241
- gridTemplateColumns: "repeat(auto-fill, minmax(320px, 1fr))",
247
+ gridTemplateColumns: "repeat(auto-fill, minmax(min(320px, 100%), 1fr))",
242
248
  gap: "var(--space-formGap)"
243
249
  },
244
250
  children: K.map((e) => /* @__PURE__ */ S(E, {
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardsPage.js","names":[],"sources":["../../../src/bigconsole/pages/DashboardsPage.tsx"],"sourcesContent":["/**\n * DashboardsPage\n *\n * List and manage dashboards - fetches data from real backend.\n * Uses fe-libs shared UI components and semantic tokens for consistent styling.\n */\n\nimport { type FC, memo, useState, useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useBigConsoleNavigate } from '../context';\nimport { isNative, nativeConfirm, nativeImpact, nativeNotify } from '../../utils/nativeBridge';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { Card, CardContent } from '@burdenoff/fe-libs/ui';\nimport { Badge } from '@burdenoff/fe-libs/ui';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport {\n Plus,\n Upload,\n Search,\n LayoutDashboard,\n Calendar,\n Layers,\n FileText,\n Pencil,\n Trash2,\n FolderOpen,\n} from 'lucide-react';\nimport { useDashboardOperations } from '../hooks';\nimport { CreateDashboardDialog } from '../components/dashboard/CreateDashboardDialog';\nimport { ImportDashboardDialog } from '../components/dashboard/ImportDashboardDialog';\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const DashboardsPage: FC = memo(function DashboardsPage() {\n const navigate = useBigConsoleNavigate();\n const { t } = useI18n();\n const tr = useCallback(\n (key: string, fallback: string) => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n },\n [t]\n );\n const [searchQuery, setSearchQuery] = useState('');\n const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);\n const [isCreating, setIsCreating] = useState(false);\n const [isImportDialogOpen, setIsImportDialogOpen] = useState(false);\n\n const { loading, error, dashboards, createDashboard, deleteDashboard, refetch } = useDashboardOperations();\n\n // Filter dashboards by search query\n const filteredDashboards = dashboards.filter(\n (d) =>\n d.name.toLowerCase().includes(searchQuery.toLowerCase()) ||\n d.description?.toLowerCase().includes(searchQuery.toLowerCase())\n );\n\n const handleOpenCreateDialog = useCallback(() => {\n setIsCreateDialogOpen(true);\n }, []);\n\n const handleCloseCreateDialog = useCallback(() => {\n if (!isCreating) {\n setIsCreateDialogOpen(false);\n }\n }, [isCreating]);\n\n const handleCreateDashboard = useCallback(\n async (data: { name: string; description: string; category: string; tags?: string[] }) => {\n setIsCreating(true);\n try {\n const newDashboard = await createDashboard({\n name: data.name,\n description: data.description,\n category: data.category,\n tags: data.tags,\n });\n\n if (newDashboard) {\n setIsCreateDialogOpen(false);\n navigate(`/dashboards/${newDashboard.id}/builder`);\n }\n } catch (err) {\n } finally {\n setIsCreating(false);\n }\n },\n [createDashboard, navigate]\n );\n\n const handleOpenDashboard = useCallback(\n (dashboardId: string) => {\n navigate(`/dashboards/${dashboardId}`);\n },\n [navigate]\n );\n\n const handleEditDashboard = useCallback(\n (dashboardId: string, e: React.MouseEvent) => {\n e.stopPropagation();\n navigate(`/dashboards/${dashboardId}/builder`);\n },\n [navigate]\n );\n\n const handleDeleteDashboard = useCallback(\n async (dashboardId: string, e: React.MouseEvent) => {\n e.stopPropagation();\n const msg = tr('bigconsole.dashboards.confirmDelete', 'Are you sure you want to delete this dashboard?');\n const native = await nativeConfirm({\n title: 'Delete dashboard?',\n message: msg,\n okButtonTitle: 'Delete',\n cancelButtonTitle: 'Cancel',\n });\n const ok = native === null ? window.confirm(msg) : native;\n if (ok) {\n nativeImpact('medium');\n try {\n await deleteDashboard(dashboardId);\n if (isNative()) void nativeNotify('success');\n } catch (err) {\n if (isNative()) void nativeNotify('error');\n throw err;\n }\n }\n },\n [deleteDashboard, tr]\n );\n\n const handleOpenImportDialog = useCallback(() => {\n setIsImportDialogOpen(true);\n }, []);\n\n const handleCloseImportDialog = useCallback(() => {\n setIsImportDialogOpen(false);\n }, []);\n\n const handleImportSuccess = useCallback(\n (dashboardId: string, dashboardName: string) => {\n refetch();\n },\n [refetch]\n );\n\n // Format relative date\n const formatRelativeDate = (dateStr: string) => {\n const date = new Date(dateStr);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffMins = Math.floor(diffMs / 60000);\n const diffHours = Math.floor(diffMs / 3600000);\n const diffDays = Math.floor(diffMs / 86400000);\n\n if (diffMins < 1) return tr('bigconsole.dashboards.time.justNow', 'Just now');\n if (diffMins < 60) return `${diffMins}${tr('bigconsole.dashboards.time.minutesAgoSuffix', 'm ago')}`;\n if (diffHours < 24) return `${diffHours}${tr('bigconsole.dashboards.time.hoursAgoSuffix', 'h ago')}`;\n if (diffDays < 7) return `${diffDays}${tr('bigconsole.dashboards.time.daysAgoSuffix', 'd ago')}`;\n\n return new Intl.DateTimeFormat('en-US', {\n month: 'short',\n day: 'numeric',\n year: date.getFullYear() !== now.getFullYear() ? 'numeric' : undefined,\n }).format(date);\n };\n\n // Get widget count - uses widgetCount field from backend\n const getWidgetCount = (dashboard: (typeof dashboards)[0]) => {\n return dashboard.widgetCount ?? 0;\n };\n\n // Get page count\n const getPageCount = (dashboard: (typeof dashboards)[0]) => {\n return dashboard.pages?.length || 0;\n };\n\n // Error state\n if (error) {\n return (\n <div style={{ padding: 'var(--space-pagePadding)' }}>\n <Card\n style={{\n borderColor: 'var(--color-status-error-border)',\n backgroundColor: 'var(--color-status-error-bgSubtle)',\n }}\n >\n <CardContent style={{ padding: 'var(--space-pagePadding)' }}>\n <h3\n style={{\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-status-error-text)',\n }}\n >\n {tr('bigconsole.dashboards.error.title', 'Error loading dashboards')}\n </h3>\n <p\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-secondary)',\n marginTop: 'var(--space-controlGap)',\n }}\n >\n {error.message}\n </p>\n <Button size=\"sm\" onClick={() => refetch()} style={{ marginTop: 'var(--space-formGap)' }}>\n {tr('bigconsole.dashboards.error.retry', 'Retry')}\n </Button>\n </CardContent>\n </Card>\n </div>\n );\n }\n\n return (\n <div style={{ minHeight: '100vh', backgroundColor: 'var(--color-bg-canvas)' }}>\n {/* Header Section */}\n <div style={{ borderBottom: '1px solid var(--color-border)', backgroundColor: 'var(--color-bg-surface)' }}>\n <div style={{ padding: 'var(--space-pagePadding)' }}>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>\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 borderRadius: 'var(--radius-card)',\n backgroundColor: 'var(--color-action-primary-bg)',\n }}\n >\n <LayoutDashboard\n style={{\n height: 'var(--size-icon-lg)',\n width: 'var(--size-icon-lg)',\n color: 'var(--color-action-primary-text)',\n }}\n />\n </div>\n <div>\n <h1\n style={{\n fontSize: 'var(--font-size-heading-h4)',\n fontWeight: 'var(--font-weight-bold)',\n margin: 0,\n color: 'var(--color-text-primary)',\n }}\n >\n {tr('bigconsole.dashboards.title', 'Dashboards')}\n </h1>\n <p style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-secondary)', margin: 0 }}>\n {tr('bigconsole.dashboards.subtitle', 'Create and manage your analytics dashboards')}\n </p>\n </div>\n </div>\n\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-controlGap)' }}>\n <Button variant=\"outline\" onClick={handleOpenImportDialog}>\n <Upload\n style={{\n marginRight: 'var(--space-iconGap)',\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n }}\n />\n {tr('bigconsole.dashboards.actions.import', 'Import')}\n </Button>\n <Button onClick={handleOpenCreateDialog}>\n <Plus\n style={{\n marginRight: 'var(--space-iconGap)',\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n }}\n />\n {tr('bigconsole.dashboards.actions.create', 'Create Dashboard')}\n </Button>\n </div>\n </div>\n </div>\n </div>\n\n {/* Main Content */}\n <div style={{ padding: 'var(--space-pagePadding)' }}>\n {/* Search Bar */}\n <div style={{ marginBottom: 'var(--space-sectionGap)' }}>\n <div style={{ position: 'relative', maxWidth: '400px' }}>\n <Search\n style={{\n position: 'absolute',\n left: 'var(--space-controlGap)',\n top: '50%',\n transform: 'translateY(-50%)',\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n color: 'var(--color-text-muted)',\n }}\n />\n <Input\n type=\"text\"\n placeholder={tr('bigconsole.dashboards.search.placeholder', 'Search dashboards...')}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n style={{ paddingLeft: 'var(--size-controlHeight-md)', height: 'var(--size-controlHeight-md)' }}\n />\n </div>\n </div>\n\n {/* Loading state */}\n {loading && dashboards.length === 0 && (\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '80px 0' }}>\n <div style={{ textAlign: 'center' }}>\n <Spinner\n style={{\n height: 'var(--size-icon-xl)',\n width: 'var(--size-icon-xl)',\n margin: '0 auto var(--space-formGap)',\n }}\n />\n <p style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-muted)' }}>\n {tr('bigconsole.dashboards.loading', 'Loading dashboards...')}\n </p>\n </div>\n </div>\n )}\n\n {/* Dashboard Grid */}\n {!loading && filteredDashboards.length > 0 && (\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fill, minmax(320px, 1fr))',\n gap: 'var(--space-formGap)',\n }}\n >\n {filteredDashboards.map((dashboard) => (\n <Card\n key={dashboard.id}\n onClick={() => handleOpenDashboard(dashboard.id)}\n style={{\n cursor: 'pointer',\n transition: 'all 0.2s ease',\n }}\n className=\"hover:shadow-md hover:border-primary/50\"\n >\n <CardContent style={{ padding: 'var(--space-cardPadding)' }}>\n {/* Card Header with Icon and Name */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n marginBottom: 'var(--space-formGap)',\n }}\n >\n <div\n style={{\n display: 'flex',\n height: 'var(--size-controlHeight-lg)',\n width: 'var(--size-controlHeight-lg)',\n flexShrink: 0,\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 'var(--radius-button)',\n backgroundColor: 'var(--color-action-primary-bg)',\n }}\n >\n <LayoutDashboard\n style={{\n height: 'var(--size-icon-md)',\n width: 'var(--size-icon-md)',\n color: 'var(--color-action-primary-text)',\n }}\n />\n </div>\n <div style={{ flex: 1, minWidth: 0 }}>\n <h3\n style={{\n fontWeight: 'var(--font-weight-bold)',\n fontSize: 'var(--font-size-body-md)',\n margin: 0,\n color: 'var(--color-text-primary)',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {dashboard.name}\n </h3>\n {dashboard.category && (\n <Badge\n variant=\"secondary\"\n style={{\n marginTop: 'var(--space-controlGap)',\n fontSize: '10px',\n fontWeight: 'var(--font-weight-semibold)',\n textTransform: 'uppercase',\n }}\n >\n {dashboard.category}\n </Badge>\n )}\n </div>\n </div>\n\n {/* Description */}\n <p\n style={{\n fontSize: 'var(--font-size-body-sm)',\n lineHeight: 'var(--font-lineHeight-normal)',\n color: 'var(--color-text-secondary)',\n margin: '0 0 var(--space-formGap) 0',\n minHeight: '40px',\n display: '-webkit-box',\n WebkitLineClamp: 2,\n WebkitBoxOrient: 'vertical',\n overflow: 'hidden',\n }}\n >\n {dashboard.description || tr('bigconsole.dashboards.card.noDescription', 'No description provided')}\n </p>\n\n {/* Stats Row */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-formGap)',\n marginBottom: 'var(--space-formGap)',\n padding: 'var(--space-controlGap) var(--space-cardPadding)',\n backgroundColor: 'var(--color-bg-sunken)',\n borderRadius: 'var(--radius-button)',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <Layers\n style={{\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n color: 'var(--color-action-primary-bg)',\n }}\n />\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n }}\n >\n {getPageCount(dashboard)}\n </span>\n <span style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-muted)' }}>\n {tr('bigconsole.dashboards.card.pages', 'pages')}\n </span>\n </div>\n <div\n style={{ width: '1px', height: 'var(--size-icon-sm)', backgroundColor: 'var(--color-border)' }}\n />\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <FileText\n style={{\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n color: 'var(--color-action-primary-bg)',\n }}\n />\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n }}\n >\n {getWidgetCount(dashboard)}\n </span>\n <span style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-muted)' }}>\n {tr('bigconsole.dashboards.card.widgets', 'widgets')}\n </span>\n </div>\n </div>\n\n {/* Footer with Date and Actions */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n paddingTop: 'var(--space-controlGap)',\n borderTop: '1px solid var(--color-border)',\n }}\n >\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-iconGap)',\n }}\n >\n <Calendar\n style={{\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n color: 'var(--color-text-muted)',\n }}\n />\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-muted)',\n }}\n >\n {formatRelativeDate(dashboard.updatedAt)}\n </span>\n </div>\n\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-controlGap)' }}>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={(e) => handleEditDashboard(dashboard.id, e)}\n style={{\n height: 'var(--size-controlHeight-sm)',\n width: 'var(--size-controlHeight-sm)',\n padding: 0,\n borderRadius: 'var(--radius-button)',\n }}\n title={tr('bigconsole.dashboards.actions.editTitle', 'Edit Dashboard')}\n >\n <Pencil style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={(e) => handleDeleteDashboard(dashboard.id, e)}\n style={{\n height: 'var(--size-controlHeight-sm)',\n width: 'var(--size-controlHeight-sm)',\n padding: 0,\n borderRadius: 'var(--radius-button)',\n }}\n className=\"hover:text-destructive hover:bg-destructive/10\"\n title={tr('bigconsole.dashboards.actions.deleteTitle', 'Delete Dashboard')}\n >\n <Trash2 style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n </Button>\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n\n {/* Empty state */}\n {!loading && filteredDashboards.length === 0 && (\n <Card className=\"border-dashed\">\n <CardContent\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '64px var(--space-pagePadding)',\n }}\n >\n <div\n style={{\n display: 'flex',\n height: '80px',\n width: '80px',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: '50%',\n backgroundColor: 'var(--color-bg-sunken)',\n marginBottom: 'var(--space-sectionGap)',\n }}\n >\n <FolderOpen\n style={{\n height: 'var(--size-icon-xl)',\n width: 'var(--size-icon-xl)',\n color: 'var(--color-text-muted)',\n }}\n />\n </div>\n <h3\n style={{\n fontSize: 'var(--font-size-heading-h4)',\n fontWeight: 'var(--font-weight-semibold)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n {searchQuery\n ? tr('bigconsole.dashboards.empty.filteredTitle', 'No dashboards found')\n : tr('bigconsole.dashboards.empty.title', 'No dashboards yet')}\n </h3>\n <p\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-muted)',\n marginBottom: 'var(--space-sectionGap)',\n textAlign: 'center',\n maxWidth: '360px',\n }}\n >\n {searchQuery\n ? tr('bigconsole.dashboards.empty.filteredDescription', 'Try adjusting your search terms')\n : tr(\n 'bigconsole.dashboards.empty.description',\n 'Get started by creating your first dashboard to visualize your data'\n )}\n </p>\n {!searchQuery && (\n <div style={{ display: 'flex', gap: 'var(--space-controlGap)' }}>\n <Button variant=\"outline\" onClick={handleOpenImportDialog}>\n <Upload\n style={{\n marginRight: 'var(--space-iconGap)',\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n }}\n />\n {tr('bigconsole.dashboards.actions.importDashboard', 'Import Dashboard')}\n </Button>\n <Button onClick={handleOpenCreateDialog}>\n <Plus\n style={{\n marginRight: 'var(--space-iconGap)',\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n }}\n />\n {tr('bigconsole.dashboards.actions.create', 'Create Dashboard')}\n </Button>\n </div>\n )}\n </CardContent>\n </Card>\n )}\n </div>\n\n {/* Create Dashboard Dialog */}\n <CreateDashboardDialog\n isOpen={isCreateDialogOpen}\n isCreating={isCreating}\n onClose={handleCloseCreateDialog}\n onCreate={handleCreateDashboard}\n />\n\n {/* Import Dashboard Dialog */}\n <ImportDashboardDialog\n isOpen={isImportDialogOpen}\n onClose={handleCloseImportDialog}\n onSuccess={handleImportSuccess}\n />\n </div>\n );\n});\n\nexport default DashboardsPage;\n"],"mappings":"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"}
1
+ {"version":3,"file":"DashboardsPage.js","names":[],"sources":["../../../src/bigconsole/pages/DashboardsPage.tsx"],"sourcesContent":["/**\n * DashboardsPage\n *\n * List and manage dashboards - fetches data from real backend.\n * Uses fe-libs shared UI components and semantic tokens for consistent styling.\n */\n\nimport { type FC, memo, useState, useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useBigConsoleNavigate } from '../context';\nimport { isNative, nativeConfirm, nativeImpact, nativeNotify } from '../../utils/nativeBridge';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { Card, CardContent } from '@burdenoff/fe-libs/ui';\nimport { Badge } from '@burdenoff/fe-libs/ui';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport {\n Plus,\n Upload,\n Search,\n LayoutDashboard,\n Calendar,\n Layers,\n FileText,\n Pencil,\n Trash2,\n FolderOpen,\n} from 'lucide-react';\nimport { useDashboardOperations } from '../hooks';\nimport { CreateDashboardDialog } from '../components/dashboard/CreateDashboardDialog';\nimport { ImportDashboardDialog } from '../components/dashboard/ImportDashboardDialog';\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const DashboardsPage: FC = memo(function DashboardsPage() {\n const navigate = useBigConsoleNavigate();\n const { t } = useI18n();\n const tr = useCallback(\n (key: string, fallback: string) => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n },\n [t]\n );\n const [searchQuery, setSearchQuery] = useState('');\n const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);\n const [isCreating, setIsCreating] = useState(false);\n const [isImportDialogOpen, setIsImportDialogOpen] = useState(false);\n\n const { loading, error, dashboards, createDashboard, deleteDashboard, refetch } = useDashboardOperations();\n\n // Filter dashboards by search query\n const filteredDashboards = dashboards.filter(\n (d) =>\n d.name.toLowerCase().includes(searchQuery.toLowerCase()) ||\n d.description?.toLowerCase().includes(searchQuery.toLowerCase())\n );\n\n const handleOpenCreateDialog = useCallback(() => {\n setIsCreateDialogOpen(true);\n }, []);\n\n const handleCloseCreateDialog = useCallback(() => {\n if (!isCreating) {\n setIsCreateDialogOpen(false);\n }\n }, [isCreating]);\n\n const handleCreateDashboard = useCallback(\n async (data: { name: string; description: string; category: string; tags?: string[] }) => {\n setIsCreating(true);\n try {\n const newDashboard = await createDashboard({\n name: data.name,\n description: data.description,\n category: data.category,\n tags: data.tags,\n });\n\n if (newDashboard) {\n setIsCreateDialogOpen(false);\n navigate(`/dashboards/${newDashboard.id}/builder`);\n }\n } catch (err) {\n // Surface the failure instead of swallowing it: log for debugging,\n // notify on native, and rethrow so CreateDashboardDialog displays the error.\n console.error('Failed to create dashboard:', err);\n if (isNative()) void nativeNotify('error');\n throw err;\n } finally {\n setIsCreating(false);\n }\n },\n [createDashboard, navigate]\n );\n\n const handleOpenDashboard = useCallback(\n (dashboardId: string) => {\n navigate(`/dashboards/${dashboardId}`);\n },\n [navigate]\n );\n\n const handleEditDashboard = useCallback(\n (dashboardId: string, e: React.MouseEvent) => {\n e.stopPropagation();\n navigate(`/dashboards/${dashboardId}/builder`);\n },\n [navigate]\n );\n\n const handleDeleteDashboard = useCallback(\n async (dashboardId: string, e: React.MouseEvent) => {\n e.stopPropagation();\n const msg = tr('bigconsole.dashboards.confirmDelete', 'Are you sure you want to delete this dashboard?');\n const native = await nativeConfirm({\n title: 'Delete dashboard?',\n message: msg,\n okButtonTitle: 'Delete',\n cancelButtonTitle: 'Cancel',\n });\n const ok = native === null ? window.confirm(msg) : native;\n if (ok) {\n nativeImpact('medium');\n try {\n await deleteDashboard(dashboardId);\n if (isNative()) void nativeNotify('success');\n } catch (err) {\n if (isNative()) void nativeNotify('error');\n throw err;\n }\n }\n },\n [deleteDashboard, tr]\n );\n\n const handleOpenImportDialog = useCallback(() => {\n setIsImportDialogOpen(true);\n }, []);\n\n const handleCloseImportDialog = useCallback(() => {\n setIsImportDialogOpen(false);\n }, []);\n\n const handleImportSuccess = useCallback(\n (dashboardId: string, dashboardName: string) => {\n refetch();\n },\n [refetch]\n );\n\n // Format relative date\n const formatRelativeDate = (dateStr: string) => {\n const date = new Date(dateStr);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffMins = Math.floor(diffMs / 60000);\n const diffHours = Math.floor(diffMs / 3600000);\n const diffDays = Math.floor(diffMs / 86400000);\n\n if (diffMins < 1) return tr('bigconsole.dashboards.time.justNow', 'Just now');\n if (diffMins < 60) return `${diffMins}${tr('bigconsole.dashboards.time.minutesAgoSuffix', 'm ago')}`;\n if (diffHours < 24) return `${diffHours}${tr('bigconsole.dashboards.time.hoursAgoSuffix', 'h ago')}`;\n if (diffDays < 7) return `${diffDays}${tr('bigconsole.dashboards.time.daysAgoSuffix', 'd ago')}`;\n\n return new Intl.DateTimeFormat('en-US', {\n month: 'short',\n day: 'numeric',\n year: date.getFullYear() !== now.getFullYear() ? 'numeric' : undefined,\n }).format(date);\n };\n\n // Get widget count - uses widgetCount field from backend\n const getWidgetCount = (dashboard: (typeof dashboards)[0]) => {\n return dashboard.widgetCount ?? 0;\n };\n\n // Get page count\n const getPageCount = (dashboard: (typeof dashboards)[0]) => {\n return dashboard.pages?.length || 0;\n };\n\n // Error state\n if (error) {\n return (\n <div style={{ padding: 'var(--space-pagePadding)' }}>\n <Card\n style={{\n borderColor: 'var(--color-status-error-border)',\n backgroundColor: 'var(--color-status-error-bgSubtle)',\n }}\n >\n <CardContent style={{ padding: 'var(--space-pagePadding)' }}>\n <h3\n style={{\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-status-error-text)',\n }}\n >\n {tr('bigconsole.dashboards.error.title', 'Error loading dashboards')}\n </h3>\n <p\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-secondary)',\n marginTop: 'var(--space-controlGap)',\n }}\n >\n {error.message}\n </p>\n <Button size=\"sm\" onClick={() => refetch()} style={{ marginTop: 'var(--space-formGap)' }}>\n {tr('bigconsole.dashboards.error.retry', 'Retry')}\n </Button>\n </CardContent>\n </Card>\n </div>\n );\n }\n\n return (\n <div style={{ minHeight: '100vh', backgroundColor: 'var(--color-bg-canvas)' }}>\n {/* Header Section */}\n <div style={{ borderBottom: '1px solid var(--color-border)', backgroundColor: 'var(--color-bg-surface)' }}>\n <div style={{ padding: 'var(--space-pagePadding)' }}>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n flexWrap: 'wrap',\n gap: 'var(--space-formGap)',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-formGap)', minWidth: 0 }}>\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 borderRadius: 'var(--radius-card)',\n backgroundColor: 'var(--color-action-primary-bg)',\n }}\n >\n <LayoutDashboard\n style={{\n height: 'var(--size-icon-lg)',\n width: 'var(--size-icon-lg)',\n color: 'var(--color-action-primary-text)',\n }}\n />\n </div>\n <div>\n <h1\n style={{\n fontSize: 'var(--font-size-heading-h4)',\n fontWeight: 'var(--font-weight-bold)',\n margin: 0,\n color: 'var(--color-text-primary)',\n }}\n >\n {tr('bigconsole.dashboards.title', 'Dashboards')}\n </h1>\n <p style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-secondary)', margin: 0 }}>\n {tr('bigconsole.dashboards.subtitle', 'Create and manage your analytics dashboards')}\n </p>\n </div>\n </div>\n\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-controlGap)', flexWrap: 'wrap' }}>\n <Button variant=\"outline\" onClick={handleOpenImportDialog}>\n <Upload\n style={{\n marginRight: 'var(--space-iconGap)',\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n }}\n />\n {tr('bigconsole.dashboards.actions.import', 'Import')}\n </Button>\n <Button onClick={handleOpenCreateDialog}>\n <Plus\n style={{\n marginRight: 'var(--space-iconGap)',\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n }}\n />\n {tr('bigconsole.dashboards.actions.create', 'Create Dashboard')}\n </Button>\n </div>\n </div>\n </div>\n </div>\n\n {/* Main Content */}\n <div style={{ padding: 'var(--space-pagePadding)' }}>\n {/* Search Bar */}\n <div style={{ marginBottom: 'var(--space-sectionGap)' }}>\n <div style={{ position: 'relative', maxWidth: '400px' }}>\n <Search\n style={{\n position: 'absolute',\n left: 'var(--space-controlGap)',\n top: '50%',\n transform: 'translateY(-50%)',\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n color: 'var(--color-text-muted)',\n }}\n />\n <Input\n type=\"text\"\n placeholder={tr('bigconsole.dashboards.search.placeholder', 'Search dashboards...')}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n style={{ paddingLeft: 'var(--size-controlHeight-md)', height: 'var(--size-controlHeight-md)' }}\n />\n </div>\n </div>\n\n {/* Loading state */}\n {loading && dashboards.length === 0 && (\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '80px 0' }}>\n <div style={{ textAlign: 'center' }}>\n <Spinner\n style={{\n height: 'var(--size-icon-xl)',\n width: 'var(--size-icon-xl)',\n margin: '0 auto var(--space-formGap)',\n }}\n />\n <p style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-muted)' }}>\n {tr('bigconsole.dashboards.loading', 'Loading dashboards...')}\n </p>\n </div>\n </div>\n )}\n\n {/* Dashboard Grid */}\n {!loading && filteredDashboards.length > 0 && (\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fill, minmax(min(320px, 100%), 1fr))',\n gap: 'var(--space-formGap)',\n }}\n >\n {filteredDashboards.map((dashboard) => (\n <Card\n key={dashboard.id}\n onClick={() => handleOpenDashboard(dashboard.id)}\n style={{\n cursor: 'pointer',\n transition: 'all 0.2s ease',\n }}\n className=\"hover:shadow-md hover:border-primary/50\"\n >\n <CardContent style={{ padding: 'var(--space-cardPadding)' }}>\n {/* Card Header with Icon and Name */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n marginBottom: 'var(--space-formGap)',\n }}\n >\n <div\n style={{\n display: 'flex',\n height: 'var(--size-controlHeight-lg)',\n width: 'var(--size-controlHeight-lg)',\n flexShrink: 0,\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 'var(--radius-button)',\n backgroundColor: 'var(--color-action-primary-bg)',\n }}\n >\n <LayoutDashboard\n style={{\n height: 'var(--size-icon-md)',\n width: 'var(--size-icon-md)',\n color: 'var(--color-action-primary-text)',\n }}\n />\n </div>\n <div style={{ flex: 1, minWidth: 0 }}>\n <h3\n style={{\n fontWeight: 'var(--font-weight-bold)',\n fontSize: 'var(--font-size-body-md)',\n margin: 0,\n color: 'var(--color-text-primary)',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {dashboard.name}\n </h3>\n {dashboard.category && (\n <Badge\n variant=\"secondary\"\n style={{\n marginTop: 'var(--space-controlGap)',\n fontSize: '10px',\n fontWeight: 'var(--font-weight-semibold)',\n textTransform: 'uppercase',\n }}\n >\n {dashboard.category}\n </Badge>\n )}\n </div>\n </div>\n\n {/* Description */}\n <p\n style={{\n fontSize: 'var(--font-size-body-sm)',\n lineHeight: 'var(--font-lineHeight-normal)',\n color: 'var(--color-text-secondary)',\n margin: '0 0 var(--space-formGap) 0',\n minHeight: '40px',\n display: '-webkit-box',\n WebkitLineClamp: 2,\n WebkitBoxOrient: 'vertical',\n overflow: 'hidden',\n }}\n >\n {dashboard.description || tr('bigconsole.dashboards.card.noDescription', 'No description provided')}\n </p>\n\n {/* Stats Row */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-formGap)',\n marginBottom: 'var(--space-formGap)',\n padding: 'var(--space-controlGap) var(--space-cardPadding)',\n backgroundColor: 'var(--color-bg-sunken)',\n borderRadius: 'var(--radius-button)',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <Layers\n style={{\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n color: 'var(--color-action-primary-bg)',\n }}\n />\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n }}\n >\n {getPageCount(dashboard)}\n </span>\n <span style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-muted)' }}>\n {tr('bigconsole.dashboards.card.pages', 'pages')}\n </span>\n </div>\n <div\n style={{ width: '1px', height: 'var(--size-icon-sm)', backgroundColor: 'var(--color-border)' }}\n />\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <FileText\n style={{\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n color: 'var(--color-action-primary-bg)',\n }}\n />\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n }}\n >\n {getWidgetCount(dashboard)}\n </span>\n <span style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-muted)' }}>\n {tr('bigconsole.dashboards.card.widgets', 'widgets')}\n </span>\n </div>\n </div>\n\n {/* Footer with Date and Actions */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n paddingTop: 'var(--space-controlGap)',\n borderTop: '1px solid var(--color-border)',\n }}\n >\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-iconGap)',\n }}\n >\n <Calendar\n style={{\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n color: 'var(--color-text-muted)',\n }}\n />\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-muted)',\n }}\n >\n {formatRelativeDate(dashboard.updatedAt)}\n </span>\n </div>\n\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-controlGap)' }}>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={(e) => handleEditDashboard(dashboard.id, e)}\n style={{\n height: 'var(--size-controlHeight-sm)',\n width: 'var(--size-controlHeight-sm)',\n padding: 0,\n borderRadius: 'var(--radius-button)',\n }}\n title={tr('bigconsole.dashboards.actions.editTitle', 'Edit Dashboard')}\n >\n <Pencil style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={(e) => handleDeleteDashboard(dashboard.id, e)}\n style={{\n height: 'var(--size-controlHeight-sm)',\n width: 'var(--size-controlHeight-sm)',\n padding: 0,\n borderRadius: 'var(--radius-button)',\n }}\n className=\"hover:text-destructive hover:bg-destructive/10\"\n title={tr('bigconsole.dashboards.actions.deleteTitle', 'Delete Dashboard')}\n >\n <Trash2 style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n </Button>\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n\n {/* Empty state */}\n {!loading && filteredDashboards.length === 0 && (\n <Card className=\"border-dashed\">\n <CardContent\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '64px var(--space-pagePadding)',\n }}\n >\n <div\n style={{\n display: 'flex',\n height: '80px',\n width: '80px',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: '50%',\n backgroundColor: 'var(--color-bg-sunken)',\n marginBottom: 'var(--space-sectionGap)',\n }}\n >\n <FolderOpen\n style={{\n height: 'var(--size-icon-xl)',\n width: 'var(--size-icon-xl)',\n color: 'var(--color-text-muted)',\n }}\n />\n </div>\n <h3\n style={{\n fontSize: 'var(--font-size-heading-h4)',\n fontWeight: 'var(--font-weight-semibold)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n {searchQuery\n ? tr('bigconsole.dashboards.empty.filteredTitle', 'No dashboards found')\n : tr('bigconsole.dashboards.empty.title', 'No dashboards yet')}\n </h3>\n <p\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-muted)',\n marginBottom: 'var(--space-sectionGap)',\n textAlign: 'center',\n maxWidth: '360px',\n }}\n >\n {searchQuery\n ? tr('bigconsole.dashboards.empty.filteredDescription', 'Try adjusting your search terms')\n : tr(\n 'bigconsole.dashboards.empty.description',\n 'Get started by creating your first dashboard to visualize your data'\n )}\n </p>\n {!searchQuery && (\n <div style={{ display: 'flex', gap: 'var(--space-controlGap)' }}>\n <Button variant=\"outline\" onClick={handleOpenImportDialog}>\n <Upload\n style={{\n marginRight: 'var(--space-iconGap)',\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n }}\n />\n {tr('bigconsole.dashboards.actions.importDashboard', 'Import Dashboard')}\n </Button>\n <Button onClick={handleOpenCreateDialog}>\n <Plus\n style={{\n marginRight: 'var(--space-iconGap)',\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n }}\n />\n {tr('bigconsole.dashboards.actions.create', 'Create Dashboard')}\n </Button>\n </div>\n )}\n </CardContent>\n </Card>\n )}\n </div>\n\n {/* Create Dashboard Dialog */}\n <CreateDashboardDialog\n isOpen={isCreateDialogOpen}\n isCreating={isCreating}\n onClose={handleCloseCreateDialog}\n onCreate={handleCreateDashboard}\n />\n\n {/* Import Dashboard Dialog */}\n <ImportDashboardDialog\n isOpen={isImportDialogOpen}\n onClose={handleCloseImportDialog}\n onSuccess={handleImportSuccess}\n />\n </div>\n );\n});\n\nexport default DashboardsPage;\n"],"mappings":"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"}
@@ -121,6 +121,10 @@ var k = i(function() {
121
121
  }, [R, N]);
122
122
  let B = a(async () => {
123
123
  if (!(!u.trim() || h)) {
124
+ if (u.length > 2e3) {
125
+ A("Prompt is too long (max 2000 characters).");
126
+ return;
127
+ }
124
128
  A(null), g(!0);
125
129
  try {
126
130
  await F({ variables: { input: {
@@ -224,6 +228,7 @@ var k = i(function() {
224
228
  onChange: (e) => d(e.target.value),
225
229
  placeholder: "e.g., Create a sales dashboard showing revenue trends, top products, and regional performance",
226
230
  rows: 3,
231
+ maxLength: 2e3,
227
232
  style: {
228
233
  width: "100%",
229
234
  padding: "8px 12px",
@@ -244,7 +249,9 @@ var k = i(function() {
244
249
  display: "flex",
245
250
  justifyContent: "space-between",
246
251
  alignItems: "center",
247
- marginTop: 8
252
+ marginTop: 8,
253
+ flexWrap: "wrap",
254
+ gap: 8
248
255
  },
249
256
  children: [/* @__PURE__ */ y("span", {
250
257
  style: {
@@ -325,7 +332,7 @@ var k = i(function() {
325
332
  }), /* @__PURE__ */ y("div", {
326
333
  style: {
327
334
  display: "grid",
328
- gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))",
335
+ gridTemplateColumns: "repeat(auto-fill, minmax(min(280px, 100%), 1fr))",
329
336
  gap: 12
330
337
  },
331
338
  children: z.map((e) => /* @__PURE__ */ b("button", {
@@ -1 +1 @@
1
- {"version":3,"file":"InsightsPage.js","names":[],"sources":["../../../src/bigconsole/pages/InsightsPage.tsx"],"sourcesContent":["/**\n * InsightsPage\n *\n * AI-powered dashboard generation using the Prompt module backend.\n * Users enter a natural language prompt to generate dashboards with\n * suggested widgets, layouts, and configurations.\n */\n\nimport { type FC, memo, useState, useCallback, useEffect } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { useAppNavigate } from '../contexts';\nimport { isNative, nativeImpact, nativeNotify } from '../../utils/nativeBridge';\nimport { Sparkles, Loader2, Trash2, ArrowRight, Clock, CheckCircle, XCircle, AlertCircle } from 'lucide-react';\n\n// ============================================================================\n// GRAPHQL OPERATIONS (inline until codegen is configured for prompt module)\n// TODO(BOFF-2055): Replace inline gql with codegen-generated hooks\n// ============================================================================\n\nconst LIST_PROMPT_GENERATIONS = gql`\n query ListPromptGenerations($status: PromptGenerationStatus, $first: Int) {\n listPromptGenerations(status: $status, first: $first) {\n edges {\n node {\n id\n prompt\n status\n dashboardId\n errorMessage\n createdAt\n completedAt\n generatedSpec {\n name\n description\n overallConfidence\n pages {\n name\n widgets {\n title\n type\n }\n }\n }\n }\n }\n totalCount\n }\n }\n`;\n\nconst GET_PROMPT_SUGGESTIONS = gql`\n query GetPromptSuggestions($category: String, $limit: Int) {\n getPromptSuggestions(category: $category, limit: $limit) {\n id\n category\n title\n prompt\n exampleDescription\n tags\n }\n }\n`;\n\nconst GENERATE_DASHBOARD = gql`\n mutation GenerateDashboardFromPrompt($input: GenerateDashboardFromPromptInput!) {\n generateDashboardFromPrompt(input: $input) {\n id\n status\n prompt\n }\n }\n`;\n\nconst CREATE_FROM_GENERATION = gql`\n mutation CreateDashboardFromGeneration($input: CreateDashboardFromGenerationInput!) {\n createDashboardFromGeneration(input: $input) {\n id\n }\n }\n`;\n\nconst DELETE_GENERATION = gql`\n mutation DeletePromptGeneration($generationId: ID!) {\n deletePromptGeneration(generationId: $generationId)\n }\n`;\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface ListPromptGenerationsData {\n listPromptGenerations: {\n edges: Array<{ node: PromptGeneration }>;\n totalCount: number;\n };\n}\n\ninterface GetPromptSuggestionsData {\n getPromptSuggestions: PromptSuggestion[];\n}\n\ninterface GenerateDashboardData {\n generateDashboardFromPrompt: {\n id: string;\n status: string;\n prompt: string;\n };\n}\n\ninterface CreateFromGenerationData {\n createDashboardFromGeneration: {\n id: string;\n };\n}\n\nconst NON_TERMINAL_STATUSES = ['PENDING', 'PROCESSING', 'GENERATING'];\n\ninterface PromptSuggestion {\n id: string;\n category: string;\n title: string;\n prompt: string;\n exampleDescription?: string;\n tags: string[];\n}\n\ninterface PromptGeneration {\n id: string;\n prompt: string;\n status: string;\n dashboardId?: string;\n errorMessage?: string;\n createdAt: string;\n completedAt?: string;\n generatedSpec?: {\n name: string;\n description?: string;\n overallConfidence: number;\n pages: Array<{\n name: string;\n widgets: Array<{ title: string; type: string }>;\n }>;\n };\n}\n\n// ============================================================================\n// STATUS HELPERS\n// ============================================================================\n\nfunction getStatusIcon(status: string) {\n switch (status) {\n case 'COMPLETED':\n return <CheckCircle size={16} className=\"text-green-500\" />;\n case 'FAILED':\n return <XCircle size={16} className=\"text-red-500\" />;\n case 'CANCELLED':\n return <XCircle size={16} className=\"text-gray-400\" />;\n case 'PENDING':\n case 'PROCESSING':\n case 'GENERATING':\n return <Loader2 size={16} className=\"text-blue-500 animate-spin\" />;\n default:\n return <Clock size={16} className=\"text-gray-400\" />;\n }\n}\n\nfunction getStatusLabel(status: string) {\n switch (status) {\n case 'COMPLETED':\n return 'Completed';\n case 'FAILED':\n return 'Failed';\n case 'CANCELLED':\n return 'Cancelled';\n case 'PENDING':\n return 'Pending';\n case 'PROCESSING':\n return 'Processing';\n case 'GENERATING':\n return 'Generating';\n default:\n return status;\n }\n}\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const InsightsPage: FC = memo(function InsightsPage() {\n const navigate = useAppNavigate();\n const [promptText, setPromptText] = useState('');\n const [isGenerating, setIsGenerating] = useState(false);\n const [mutationError, setMutationError] = useState<string | null>(null);\n\n // Fetch existing generations\n const {\n data: generationsData,\n loading: generationsLoading,\n refetch: refetchGenerations,\n } = useQuery<ListPromptGenerationsData>(LIST_PROMPT_GENERATIONS, {\n variables: { first: 20 },\n fetchPolicy: 'cache-and-network',\n });\n\n // Fetch suggestions\n const { data: suggestionsData } = useQuery<GetPromptSuggestionsData>(GET_PROMPT_SUGGESTIONS, {\n variables: { limit: 6 },\n });\n\n // Mutations\n const [generateDashboard] = useMutation<GenerateDashboardData>(GENERATE_DASHBOARD);\n const [createFromGeneration] = useMutation<CreateFromGenerationData>(CREATE_FROM_GENERATION);\n const [deleteGeneration] = useMutation(DELETE_GENERATION);\n\n const generations: PromptGeneration[] = generationsData?.listPromptGenerations?.edges?.map((edge) => edge.node) || [];\n const suggestions: PromptSuggestion[] = suggestionsData?.getPromptSuggestions || [];\n\n // Poll for in-progress generations every 3 seconds\n useEffect(() => {\n const hasActiveGenerations = generations.some((gen) => NON_TERMINAL_STATUSES.includes(gen.status));\n if (!hasActiveGenerations) return;\n\n const interval = setInterval(() => {\n refetchGenerations();\n }, 3_000);\n\n return () => clearInterval(interval);\n }, [generations, refetchGenerations]);\n\n // Handlers\n const handleGenerate = useCallback(async () => {\n if (!promptText.trim() || isGenerating) return;\n setMutationError(null);\n setIsGenerating(true);\n try {\n await generateDashboard({\n variables: {\n input: {\n prompt: promptText.trim(),\n styleType: 'MODERN',\n layoutType: 'GRID',\n maxWidgets: 8,\n },\n },\n });\n setPromptText('');\n refetchGenerations();\n } catch (err) {\n setMutationError(err instanceof Error ? err.message : 'Failed to generate dashboard');\n } finally {\n setIsGenerating(false);\n }\n }, [promptText, isGenerating, generateDashboard, refetchGenerations]);\n\n const handleCreateDashboard = useCallback(\n async (generationId: string) => {\n setMutationError(null);\n try {\n const result = await createFromGeneration({\n variables: { input: { generationId } },\n });\n const dashboardId = result.data?.createDashboardFromGeneration?.id;\n if (dashboardId) {\n navigate(`/dashboards/${dashboardId}`);\n }\n } catch (err) {\n setMutationError(err instanceof Error ? err.message : 'Failed to create dashboard');\n }\n },\n [createFromGeneration, navigate]\n );\n\n const handleDelete = useCallback(\n async (generationId: string) => {\n setMutationError(null);\n try {\n await deleteGeneration({ variables: { generationId } });\n if (isNative()) void nativeNotify('success');\n refetchGenerations();\n } catch (err) {\n setMutationError(err instanceof Error ? err.message : 'Failed to delete generation');\n if (isNative()) void nativeNotify('error');\n }\n },\n [deleteGeneration, refetchGenerations]\n );\n\n const handleSuggestionClick = useCallback((prompt: string) => {\n setPromptText(prompt);\n }, []);\n\n return (\n <div style={{ minHeight: '100vh', backgroundColor: 'var(--color-bg-canvas)' }}>\n <div style={{ padding: 'var(--space-pagePadding)', maxWidth: 960, margin: '0 auto' }}>\n {/* Header */}\n <div style={{ marginBottom: 'var(--space-sectionGap)' }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <Sparkles size={24} style={{ color: 'var(--color-action-primary-bg)' }} />\n <h1\n style={{\n fontSize: 'var(--font-size-heading-h4)',\n fontWeight: 'var(--font-weight-bold)',\n color: 'var(--color-text-primary)',\n }}\n >\n AI Insights\n </h1>\n </div>\n <p style={{ fontSize: 'var(--font-size-body-md)', color: 'var(--color-text-secondary)', marginTop: 4 }}>\n Generate dashboards from natural language prompts\n </p>\n </div>\n\n {/* Prompt Input */}\n <div\n style={{\n backgroundColor: 'var(--color-bg-surface)',\n border: '1px solid var(--color-border)',\n borderRadius: 'var(--radius-card)',\n padding: 'var(--space-cardPadding)',\n marginBottom: 'var(--space-sectionGap)',\n }}\n >\n <label\n htmlFor=\"prompt-input\"\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-primary)',\n marginBottom: 8,\n }}\n >\n Describe the dashboard you want to create\n </label>\n <textarea\n id=\"prompt-input\"\n value={promptText}\n onChange={(e) => setPromptText(e.target.value)}\n placeholder=\"e.g., Create a sales dashboard showing revenue trends, top products, and regional performance\"\n rows={3}\n style={{\n width: '100%',\n padding: '8px 12px',\n borderRadius: 'var(--radius-button)',\n border: '1px solid var(--color-border)',\n backgroundColor: 'var(--color-bg-canvas)',\n color: 'var(--color-text-primary)',\n fontSize: 'var(--font-size-body-md)',\n resize: 'vertical',\n outline: 'none',\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) handleGenerate();\n }}\n />\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: 8 }}>\n <span style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-muted)' }}>\n Press Ctrl+Enter to generate\n </span>\n <button\n onClick={handleGenerate}\n disabled={!promptText.trim() || isGenerating}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n padding: '8px 16px',\n borderRadius: 'var(--radius-button)',\n backgroundColor: 'var(--color-action-primary-bg)',\n color: 'var(--color-action-primary-text)',\n fontWeight: 'var(--font-weight-medium)',\n fontSize: 'var(--font-size-body-sm)',\n border: 'none',\n cursor: !promptText.trim() || isGenerating ? 'not-allowed' : 'pointer',\n opacity: !promptText.trim() || isGenerating ? 0.5 : 1,\n }}\n >\n {isGenerating ? <Loader2 size={16} className=\"animate-spin\" /> : <Sparkles size={16} />}\n Generate Dashboard\n </button>\n </div>\n </div>\n\n {/* Mutation Error Banner */}\n {mutationError && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 8,\n padding: '10px 16px',\n marginBottom: 'var(--space-sectionGap)',\n borderRadius: 'var(--radius-card)',\n border: '1px solid var(--color-status-error-text)',\n backgroundColor: 'var(--color-bg-surface)',\n color: 'var(--color-status-error-text)',\n fontSize: 'var(--font-size-body-sm)',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>\n <AlertCircle size={16} />\n {mutationError}\n </div>\n <button\n onClick={() => setMutationError(null)}\n style={{\n background: 'none',\n border: 'none',\n color: 'var(--color-status-error-text)',\n cursor: 'pointer',\n fontSize: 'var(--font-size-body-md)',\n padding: '0 4px',\n }}\n aria-label=\"Dismiss error\"\n >\n &times;\n </button>\n </div>\n )}\n\n {/* Suggestions */}\n {suggestions.length > 0 && (\n <div style={{ marginBottom: 'var(--space-sectionGap)' }}>\n <h2\n style={{\n fontSize: 'var(--font-size-body-md)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n marginBottom: 12,\n }}\n >\n Suggestions\n </h2>\n <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: 12 }}>\n {suggestions.map((s) => (\n <button\n key={s.id}\n onClick={() => handleSuggestionClick(s.prompt)}\n style={{\n textAlign: 'left',\n padding: 12,\n borderRadius: 'var(--radius-card)',\n border: '1px solid var(--color-border)',\n backgroundColor: 'var(--color-bg-surface)',\n cursor: 'pointer',\n }}\n >\n <div\n style={{\n fontWeight: 'var(--font-weight-medium)',\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-primary)',\n marginBottom: 4,\n }}\n >\n {s.title}\n </div>\n <div\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-secondary)',\n lineHeight: 1.4,\n }}\n >\n {s.exampleDescription || s.prompt.slice(0, 80)}\n </div>\n <div style={{ display: 'flex', gap: 4, marginTop: 8, flexWrap: 'wrap' }}>\n {s.tags.slice(0, 3).map((tag) => (\n <span\n key={tag}\n style={{\n fontSize: 11,\n padding: '2px 6px',\n borderRadius: 4,\n backgroundColor: 'var(--color-bg-sunken)',\n color: 'var(--color-text-muted)',\n }}\n >\n {tag}\n </span>\n ))}\n </div>\n </button>\n ))}\n </div>\n </div>\n )}\n\n {/* Generations History */}\n <div>\n <h2\n style={{\n fontSize: 'var(--font-size-body-md)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n marginBottom: 12,\n }}\n >\n Recent Generations\n </h2>\n\n {generationsLoading && generations.length === 0 ? (\n <div style={{ textAlign: 'center', padding: 40, color: 'var(--color-text-muted)' }}>\n <Loader2 size={24} className=\"animate-spin\" style={{ margin: '0 auto 8px' }} />\n <p>Loading generations...</p>\n </div>\n ) : generations.length === 0 ? (\n <div\n style={{\n textAlign: 'center',\n padding: 40,\n backgroundColor: 'var(--color-bg-surface)',\n border: '1px solid var(--color-border)',\n borderRadius: 'var(--radius-card)',\n }}\n >\n <Sparkles size={32} style={{ color: 'var(--color-text-muted)', margin: '0 auto 8px' }} />\n <p style={{ color: 'var(--color-text-secondary)', fontWeight: 'var(--font-weight-medium)' }}>\n No generations yet\n </p>\n <p style={{ color: 'var(--color-text-muted)', fontSize: 'var(--font-size-body-sm)', marginTop: 4 }}>\n Describe a dashboard above to get started\n </p>\n </div>\n ) : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>\n {generations.map((gen) => (\n <div\n key={gen.id}\n style={{\n padding: 16,\n borderRadius: 'var(--radius-card)',\n border: '1px solid var(--color-border)',\n backgroundColor: 'var(--color-bg-surface)',\n }}\n >\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>\n <div style={{ flex: 1 }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 4 }}>\n {getStatusIcon(gen.status)}\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-primary)',\n }}\n >\n {gen.generatedSpec?.name || 'Generating...'}\n </span>\n <span\n style={{\n fontSize: 11,\n color: 'var(--color-text-muted)',\n padding: '2px 6px',\n borderRadius: 4,\n backgroundColor: 'var(--color-bg-sunken)',\n }}\n >\n {getStatusLabel(gen.status)}\n </span>\n </div>\n <p\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-secondary)',\n marginBottom: 4,\n }}\n >\n {gen.prompt.length > 120 ? gen.prompt.slice(0, 120) + '...' : gen.prompt}\n </p>\n {gen.generatedSpec && (\n <div style={{ fontSize: 11, color: 'var(--color-text-muted)' }}>\n {gen.generatedSpec.pages.reduce((acc, p) => acc + p.widgets.length, 0)} widgets across{' '}\n {gen.generatedSpec.pages.length} page(s) &middot;{' '}\n {Math.round(gen.generatedSpec.overallConfidence * 100)}% confidence\n </div>\n )}\n {gen.errorMessage && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n marginTop: 4,\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-status-error-text)',\n }}\n >\n <AlertCircle size={14} />\n {gen.errorMessage}\n </div>\n )}\n </div>\n <div style={{ display: 'flex', gap: 8 }}>\n {gen.status === 'COMPLETED' && !gen.dashboardId && (\n <button\n onClick={() => handleCreateDashboard(gen.id)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n padding: '6px 12px',\n borderRadius: 'var(--radius-button)',\n backgroundColor: 'var(--color-action-primary-bg)',\n color: 'var(--color-action-primary-text)',\n border: 'none',\n fontSize: 'var(--font-size-body-sm)',\n cursor: 'pointer',\n }}\n >\n Create <ArrowRight size={14} />\n </button>\n )}\n {gen.dashboardId && (\n <button\n onClick={() => navigate(`/dashboards/${gen.dashboardId}`)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n padding: '6px 12px',\n borderRadius: 'var(--radius-button)',\n border: '1px solid var(--color-border)',\n backgroundColor: 'transparent',\n color: 'var(--color-text-primary)',\n fontSize: 'var(--font-size-body-sm)',\n cursor: 'pointer',\n }}\n >\n View Dashboard <ArrowRight size={14} />\n </button>\n )}\n <button\n onClick={() => {\n nativeImpact('medium');\n void handleDelete(gen.id);\n }}\n title=\"Delete generation\"\n style={{\n display: 'flex',\n alignItems: 'center',\n padding: 6,\n borderRadius: 'var(--radius-button)',\n border: '1px solid var(--color-border)',\n backgroundColor: 'transparent',\n color: 'var(--color-text-muted)',\n cursor: 'pointer',\n }}\n >\n <Trash2 size={14} />\n </button>\n </div>\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n});\n\nexport default InsightsPage;\n"],"mappings":"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"}
1
+ {"version":3,"file":"InsightsPage.js","names":[],"sources":["../../../src/bigconsole/pages/InsightsPage.tsx"],"sourcesContent":["/**\n * InsightsPage\n *\n * AI-powered dashboard generation using the Prompt module backend.\n * Users enter a natural language prompt to generate dashboards with\n * suggested widgets, layouts, and configurations.\n */\n\nimport { type FC, memo, useState, useCallback, useEffect } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { useAppNavigate } from '../contexts';\nimport { isNative, nativeImpact, nativeNotify } from '../../utils/nativeBridge';\nimport { Sparkles, Loader2, Trash2, ArrowRight, Clock, CheckCircle, XCircle, AlertCircle } from 'lucide-react';\n\n// ============================================================================\n// GRAPHQL OPERATIONS (inline until codegen is configured for prompt module)\n// TODO(BOFF-2055): Replace inline gql with codegen-generated hooks\n// ============================================================================\n\nconst LIST_PROMPT_GENERATIONS = gql`\n query ListPromptGenerations($status: PromptGenerationStatus, $first: Int) {\n listPromptGenerations(status: $status, first: $first) {\n edges {\n node {\n id\n prompt\n status\n dashboardId\n errorMessage\n createdAt\n completedAt\n generatedSpec {\n name\n description\n overallConfidence\n pages {\n name\n widgets {\n title\n type\n }\n }\n }\n }\n }\n totalCount\n }\n }\n`;\n\nconst GET_PROMPT_SUGGESTIONS = gql`\n query GetPromptSuggestions($category: String, $limit: Int) {\n getPromptSuggestions(category: $category, limit: $limit) {\n id\n category\n title\n prompt\n exampleDescription\n tags\n }\n }\n`;\n\nconst GENERATE_DASHBOARD = gql`\n mutation GenerateDashboardFromPrompt($input: GenerateDashboardFromPromptInput!) {\n generateDashboardFromPrompt(input: $input) {\n id\n status\n prompt\n }\n }\n`;\n\nconst CREATE_FROM_GENERATION = gql`\n mutation CreateDashboardFromGeneration($input: CreateDashboardFromGenerationInput!) {\n createDashboardFromGeneration(input: $input) {\n id\n }\n }\n`;\n\nconst DELETE_GENERATION = gql`\n mutation DeletePromptGeneration($generationId: ID!) {\n deletePromptGeneration(generationId: $generationId)\n }\n`;\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface ListPromptGenerationsData {\n listPromptGenerations: {\n edges: Array<{ node: PromptGeneration }>;\n totalCount: number;\n };\n}\n\ninterface GetPromptSuggestionsData {\n getPromptSuggestions: PromptSuggestion[];\n}\n\ninterface GenerateDashboardData {\n generateDashboardFromPrompt: {\n id: string;\n status: string;\n prompt: string;\n };\n}\n\ninterface CreateFromGenerationData {\n createDashboardFromGeneration: {\n id: string;\n };\n}\n\nconst NON_TERMINAL_STATUSES = ['PENDING', 'PROCESSING', 'GENERATING'];\n\ninterface PromptSuggestion {\n id: string;\n category: string;\n title: string;\n prompt: string;\n exampleDescription?: string;\n tags: string[];\n}\n\ninterface PromptGeneration {\n id: string;\n prompt: string;\n status: string;\n dashboardId?: string;\n errorMessage?: string;\n createdAt: string;\n completedAt?: string;\n generatedSpec?: {\n name: string;\n description?: string;\n overallConfidence: number;\n pages: Array<{\n name: string;\n widgets: Array<{ title: string; type: string }>;\n }>;\n };\n}\n\n// ============================================================================\n// STATUS HELPERS\n// ============================================================================\n\nfunction getStatusIcon(status: string) {\n switch (status) {\n case 'COMPLETED':\n return <CheckCircle size={16} className=\"text-green-500\" />;\n case 'FAILED':\n return <XCircle size={16} className=\"text-red-500\" />;\n case 'CANCELLED':\n return <XCircle size={16} className=\"text-gray-400\" />;\n case 'PENDING':\n case 'PROCESSING':\n case 'GENERATING':\n return <Loader2 size={16} className=\"text-blue-500 animate-spin\" />;\n default:\n return <Clock size={16} className=\"text-gray-400\" />;\n }\n}\n\nfunction getStatusLabel(status: string) {\n switch (status) {\n case 'COMPLETED':\n return 'Completed';\n case 'FAILED':\n return 'Failed';\n case 'CANCELLED':\n return 'Cancelled';\n case 'PENDING':\n return 'Pending';\n case 'PROCESSING':\n return 'Processing';\n case 'GENERATING':\n return 'Generating';\n default:\n return status;\n }\n}\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const InsightsPage: FC = memo(function InsightsPage() {\n const navigate = useAppNavigate();\n const [promptText, setPromptText] = useState('');\n const [isGenerating, setIsGenerating] = useState(false);\n const [mutationError, setMutationError] = useState<string | null>(null);\n\n // Fetch existing generations\n const {\n data: generationsData,\n loading: generationsLoading,\n refetch: refetchGenerations,\n } = useQuery<ListPromptGenerationsData>(LIST_PROMPT_GENERATIONS, {\n variables: { first: 20 },\n fetchPolicy: 'cache-and-network',\n });\n\n // Fetch suggestions\n const { data: suggestionsData } = useQuery<GetPromptSuggestionsData>(GET_PROMPT_SUGGESTIONS, {\n variables: { limit: 6 },\n });\n\n // Mutations\n const [generateDashboard] = useMutation<GenerateDashboardData>(GENERATE_DASHBOARD);\n const [createFromGeneration] = useMutation<CreateFromGenerationData>(CREATE_FROM_GENERATION);\n const [deleteGeneration] = useMutation(DELETE_GENERATION);\n\n const generations: PromptGeneration[] = generationsData?.listPromptGenerations?.edges?.map((edge) => edge.node) || [];\n const suggestions: PromptSuggestion[] = suggestionsData?.getPromptSuggestions || [];\n\n // Poll for in-progress generations every 3 seconds\n useEffect(() => {\n const hasActiveGenerations = generations.some((gen) => NON_TERMINAL_STATUSES.includes(gen.status));\n if (!hasActiveGenerations) return;\n\n const interval = setInterval(() => {\n refetchGenerations();\n }, 3_000);\n\n return () => clearInterval(interval);\n }, [generations, refetchGenerations]);\n\n // Handlers\n const handleGenerate = useCallback(async () => {\n if (!promptText.trim() || isGenerating) return;\n if (promptText.length > 2000) {\n setMutationError('Prompt is too long (max 2000 characters).');\n return;\n }\n setMutationError(null);\n setIsGenerating(true);\n try {\n await generateDashboard({\n variables: {\n input: {\n prompt: promptText.trim(),\n styleType: 'MODERN',\n layoutType: 'GRID',\n maxWidgets: 8,\n },\n },\n });\n setPromptText('');\n refetchGenerations();\n } catch (err) {\n setMutationError(err instanceof Error ? err.message : 'Failed to generate dashboard');\n } finally {\n setIsGenerating(false);\n }\n }, [promptText, isGenerating, generateDashboard, refetchGenerations]);\n\n const handleCreateDashboard = useCallback(\n async (generationId: string) => {\n setMutationError(null);\n try {\n const result = await createFromGeneration({\n variables: { input: { generationId } },\n });\n const dashboardId = result.data?.createDashboardFromGeneration?.id;\n if (dashboardId) {\n navigate(`/dashboards/${dashboardId}`);\n }\n } catch (err) {\n setMutationError(err instanceof Error ? err.message : 'Failed to create dashboard');\n }\n },\n [createFromGeneration, navigate]\n );\n\n const handleDelete = useCallback(\n async (generationId: string) => {\n setMutationError(null);\n try {\n await deleteGeneration({ variables: { generationId } });\n if (isNative()) void nativeNotify('success');\n refetchGenerations();\n } catch (err) {\n setMutationError(err instanceof Error ? err.message : 'Failed to delete generation');\n if (isNative()) void nativeNotify('error');\n }\n },\n [deleteGeneration, refetchGenerations]\n );\n\n const handleSuggestionClick = useCallback((prompt: string) => {\n setPromptText(prompt);\n }, []);\n\n return (\n <div style={{ minHeight: '100vh', backgroundColor: 'var(--color-bg-canvas)' }}>\n <div style={{ padding: 'var(--space-pagePadding)', maxWidth: 960, margin: '0 auto' }}>\n {/* Header */}\n <div style={{ marginBottom: 'var(--space-sectionGap)' }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <Sparkles size={24} style={{ color: 'var(--color-action-primary-bg)' }} />\n <h1\n style={{\n fontSize: 'var(--font-size-heading-h4)',\n fontWeight: 'var(--font-weight-bold)',\n color: 'var(--color-text-primary)',\n }}\n >\n AI Insights\n </h1>\n </div>\n <p style={{ fontSize: 'var(--font-size-body-md)', color: 'var(--color-text-secondary)', marginTop: 4 }}>\n Generate dashboards from natural language prompts\n </p>\n </div>\n\n {/* Prompt Input */}\n <div\n style={{\n backgroundColor: 'var(--color-bg-surface)',\n border: '1px solid var(--color-border)',\n borderRadius: 'var(--radius-card)',\n padding: 'var(--space-cardPadding)',\n marginBottom: 'var(--space-sectionGap)',\n }}\n >\n <label\n htmlFor=\"prompt-input\"\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-primary)',\n marginBottom: 8,\n }}\n >\n Describe the dashboard you want to create\n </label>\n <textarea\n id=\"prompt-input\"\n value={promptText}\n onChange={(e) => setPromptText(e.target.value)}\n placeholder=\"e.g., Create a sales dashboard showing revenue trends, top products, and regional performance\"\n rows={3}\n maxLength={2000}\n style={{\n width: '100%',\n padding: '8px 12px',\n borderRadius: 'var(--radius-button)',\n border: '1px solid var(--color-border)',\n backgroundColor: 'var(--color-bg-canvas)',\n color: 'var(--color-text-primary)',\n fontSize: 'var(--font-size-body-md)',\n resize: 'vertical',\n outline: 'none',\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) handleGenerate();\n }}\n />\n <div\n style={{\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n marginTop: 8,\n flexWrap: 'wrap',\n gap: 8,\n }}\n >\n <span style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-muted)' }}>\n Press Ctrl+Enter to generate\n </span>\n <button\n onClick={handleGenerate}\n disabled={!promptText.trim() || isGenerating}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n padding: '8px 16px',\n borderRadius: 'var(--radius-button)',\n backgroundColor: 'var(--color-action-primary-bg)',\n color: 'var(--color-action-primary-text)',\n fontWeight: 'var(--font-weight-medium)',\n fontSize: 'var(--font-size-body-sm)',\n border: 'none',\n cursor: !promptText.trim() || isGenerating ? 'not-allowed' : 'pointer',\n opacity: !promptText.trim() || isGenerating ? 0.5 : 1,\n }}\n >\n {isGenerating ? <Loader2 size={16} className=\"animate-spin\" /> : <Sparkles size={16} />}\n Generate Dashboard\n </button>\n </div>\n </div>\n\n {/* Mutation Error Banner */}\n {mutationError && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 8,\n padding: '10px 16px',\n marginBottom: 'var(--space-sectionGap)',\n borderRadius: 'var(--radius-card)',\n border: '1px solid var(--color-status-error-text)',\n backgroundColor: 'var(--color-bg-surface)',\n color: 'var(--color-status-error-text)',\n fontSize: 'var(--font-size-body-sm)',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>\n <AlertCircle size={16} />\n {mutationError}\n </div>\n <button\n onClick={() => setMutationError(null)}\n style={{\n background: 'none',\n border: 'none',\n color: 'var(--color-status-error-text)',\n cursor: 'pointer',\n fontSize: 'var(--font-size-body-md)',\n padding: '0 4px',\n }}\n aria-label=\"Dismiss error\"\n >\n &times;\n </button>\n </div>\n )}\n\n {/* Suggestions */}\n {suggestions.length > 0 && (\n <div style={{ marginBottom: 'var(--space-sectionGap)' }}>\n <h2\n style={{\n fontSize: 'var(--font-size-body-md)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n marginBottom: 12,\n }}\n >\n Suggestions\n </h2>\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fill, minmax(min(280px, 100%), 1fr))',\n gap: 12,\n }}\n >\n {suggestions.map((s) => (\n <button\n key={s.id}\n onClick={() => handleSuggestionClick(s.prompt)}\n style={{\n textAlign: 'left',\n padding: 12,\n borderRadius: 'var(--radius-card)',\n border: '1px solid var(--color-border)',\n backgroundColor: 'var(--color-bg-surface)',\n cursor: 'pointer',\n }}\n >\n <div\n style={{\n fontWeight: 'var(--font-weight-medium)',\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-primary)',\n marginBottom: 4,\n }}\n >\n {s.title}\n </div>\n <div\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-secondary)',\n lineHeight: 1.4,\n }}\n >\n {s.exampleDescription || s.prompt.slice(0, 80)}\n </div>\n <div style={{ display: 'flex', gap: 4, marginTop: 8, flexWrap: 'wrap' }}>\n {s.tags.slice(0, 3).map((tag) => (\n <span\n key={tag}\n style={{\n fontSize: 11,\n padding: '2px 6px',\n borderRadius: 4,\n backgroundColor: 'var(--color-bg-sunken)',\n color: 'var(--color-text-muted)',\n }}\n >\n {tag}\n </span>\n ))}\n </div>\n </button>\n ))}\n </div>\n </div>\n )}\n\n {/* Generations History */}\n <div>\n <h2\n style={{\n fontSize: 'var(--font-size-body-md)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n marginBottom: 12,\n }}\n >\n Recent Generations\n </h2>\n\n {generationsLoading && generations.length === 0 ? (\n <div style={{ textAlign: 'center', padding: 40, color: 'var(--color-text-muted)' }}>\n <Loader2 size={24} className=\"animate-spin\" style={{ margin: '0 auto 8px' }} />\n <p>Loading generations...</p>\n </div>\n ) : generations.length === 0 ? (\n <div\n style={{\n textAlign: 'center',\n padding: 40,\n backgroundColor: 'var(--color-bg-surface)',\n border: '1px solid var(--color-border)',\n borderRadius: 'var(--radius-card)',\n }}\n >\n <Sparkles size={32} style={{ color: 'var(--color-text-muted)', margin: '0 auto 8px' }} />\n <p style={{ color: 'var(--color-text-secondary)', fontWeight: 'var(--font-weight-medium)' }}>\n No generations yet\n </p>\n <p style={{ color: 'var(--color-text-muted)', fontSize: 'var(--font-size-body-sm)', marginTop: 4 }}>\n Describe a dashboard above to get started\n </p>\n </div>\n ) : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>\n {generations.map((gen) => (\n <div\n key={gen.id}\n style={{\n padding: 16,\n borderRadius: 'var(--radius-card)',\n border: '1px solid var(--color-border)',\n backgroundColor: 'var(--color-bg-surface)',\n }}\n >\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>\n <div style={{ flex: 1 }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 4 }}>\n {getStatusIcon(gen.status)}\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-primary)',\n }}\n >\n {gen.generatedSpec?.name || 'Generating...'}\n </span>\n <span\n style={{\n fontSize: 11,\n color: 'var(--color-text-muted)',\n padding: '2px 6px',\n borderRadius: 4,\n backgroundColor: 'var(--color-bg-sunken)',\n }}\n >\n {getStatusLabel(gen.status)}\n </span>\n </div>\n <p\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-secondary)',\n marginBottom: 4,\n }}\n >\n {gen.prompt.length > 120 ? gen.prompt.slice(0, 120) + '...' : gen.prompt}\n </p>\n {gen.generatedSpec && (\n <div style={{ fontSize: 11, color: 'var(--color-text-muted)' }}>\n {gen.generatedSpec.pages.reduce((acc, p) => acc + p.widgets.length, 0)} widgets across{' '}\n {gen.generatedSpec.pages.length} page(s) &middot;{' '}\n {Math.round(gen.generatedSpec.overallConfidence * 100)}% confidence\n </div>\n )}\n {gen.errorMessage && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n marginTop: 4,\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-status-error-text)',\n }}\n >\n <AlertCircle size={14} />\n {gen.errorMessage}\n </div>\n )}\n </div>\n <div style={{ display: 'flex', gap: 8 }}>\n {gen.status === 'COMPLETED' && !gen.dashboardId && (\n <button\n onClick={() => handleCreateDashboard(gen.id)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n padding: '6px 12px',\n borderRadius: 'var(--radius-button)',\n backgroundColor: 'var(--color-action-primary-bg)',\n color: 'var(--color-action-primary-text)',\n border: 'none',\n fontSize: 'var(--font-size-body-sm)',\n cursor: 'pointer',\n }}\n >\n Create <ArrowRight size={14} />\n </button>\n )}\n {gen.dashboardId && (\n <button\n onClick={() => navigate(`/dashboards/${gen.dashboardId}`)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n padding: '6px 12px',\n borderRadius: 'var(--radius-button)',\n border: '1px solid var(--color-border)',\n backgroundColor: 'transparent',\n color: 'var(--color-text-primary)',\n fontSize: 'var(--font-size-body-sm)',\n cursor: 'pointer',\n }}\n >\n View Dashboard <ArrowRight size={14} />\n </button>\n )}\n <button\n onClick={() => {\n nativeImpact('medium');\n void handleDelete(gen.id);\n }}\n title=\"Delete generation\"\n style={{\n display: 'flex',\n alignItems: 'center',\n padding: 6,\n borderRadius: 'var(--radius-button)',\n border: '1px solid var(--color-border)',\n backgroundColor: 'transparent',\n color: 'var(--color-text-muted)',\n cursor: 'pointer',\n }}\n >\n <Trash2 size={14} />\n </button>\n </div>\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n});\n\nexport default InsightsPage;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-bigconsole",
3
- "version": "2026.608.1",
3
+ "version": "2026.610.1",
4
4
  "description": "BigConsole - AI-powered analytics and dashboard platform",
5
5
  "type": "module",
6
6
  "files": [