@burdenoff/microfe-bigconsole 2026.707.3 → 2026.708.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.
@@ -1 +1 @@
1
- {"version":3,"file":"DataSinksPage.js","names":[],"sources":["../../../src/bigconsole/pages/DataSinksPage.tsx"],"sourcesContent":["/**\n * DataSinksPage\n *\n * List and manage DataSinks - fetches data from backend.\n * Uses fe-libs shared UI components and semantic tokens for consistent styling.\n */\n\nimport { type FC, memo, useCallback, useMemo, useState } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { getProfileScopedKey } from '@burdenoff/fe-libs/shared/utils';\nimport { useAppNavigate } from '../contexts';\nimport { isNative, nativeNotify } from '../../utils/nativeBridge';\nimport { useDataSinkOperations } from '../hooks/useDataSinkOperations';\nimport { useExportDataSink } from '../hooks/useExportDataSink';\nimport { useDataSinkStore } from '../store/dataSinkStore';\nimport type { DataSink, DataSinkSetupState } from '../types';\nimport { DataSinkCard } from '../components/datasink/DataSinkCard';\nimport { DataSinkDeleteDialog } from '../components/datasink/DataSinkDeleteDialog';\nimport { DataSinkRefreshDialog } from '../components/datasink/DataSinkRefreshDialog';\nimport { ImportDataSinkDialog } from '../components/datasink/ImportDataSinkDialog';\n\n// fe-libs components\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } 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 AuroraBackground,\n GradientText,\n GlassCard,\n IllustratedEmptyState,\n CTAOverflowMenu,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\n\n// Lucide icons\nimport {\n Plus,\n Search,\n AlertCircle,\n Container,\n X,\n Upload,\n LayoutGrid,\n Table2,\n Eye,\n Pencil,\n RefreshCw,\n Download,\n Trash2,\n} from 'lucide-react';\nimport { DataSinkStatusBadge } from '../components/datasink/DataSinkStatusBadge';\nimport { SetupStateBadge } from '../components/datasink/SetupStateBadge';\n\n// ============================================================================\n// Types\n// ============================================================================\n\ntype SetupStateFilter = 'all' | 'in_progress' | 'completed';\ntype ListViewMode = 'grid' | 'table';\n\nconst VIEW_MODE_KEY = 'bigconsole-datasinks-view-mode';\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Determine setup state for a DataSink based on its properties.\n */\nconst getSetupState = (dataSink: DataSink): DataSinkSetupState => {\n if (dataSink.setupState === 'completed') {\n return 'completed';\n }\n if (dataSink.ttl !== null && dataSink.ttl !== undefined && dataSink.ttl > 0) {\n return 'completed';\n }\n if (dataSink.fluidGridsWorkflowId && dataSink.data && Object.keys(dataSink.data).length > 0) {\n return 'completed';\n }\n if (dataSink.fluidGridsWorkflowId) {\n return 'workflow_running';\n }\n return 'workflow_pending';\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const DataSinksPage: FC = memo(function DataSinksPage() {\n const navigate = useAppNavigate();\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\n // Local state\n const [setupStateFilter, setSetupStateFilter] = useState<SetupStateFilter>('all');\n const [isImportDialogOpen, setIsImportDialogOpen] = useState(false);\n const [viewMode, setViewMode] = useState<ListViewMode>(\n () => (localStorage.getItem(getProfileScopedKey(VIEW_MODE_KEY)) as ListViewMode) || 'grid'\n );\n\n const toggleViewMode = useCallback((mode: ListViewMode) => {\n setViewMode(mode);\n localStorage.setItem(getProfileScopedKey(VIEW_MODE_KEY), mode);\n }, []);\n\n // Store state\n const statusFilter = useDataSinkStore((state) => state.statusFilter);\n const activeFilter = useDataSinkStore((state) => state.activeFilter);\n const searchQuery = useDataSinkStore((state) => state.searchQuery);\n const setStatusFilter = useDataSinkStore((state) => state.setStatusFilter);\n const setActiveFilter = useDataSinkStore((state) => state.setActiveFilter);\n const setSearchQuery = useDataSinkStore((state) => state.setSearchQuery);\n const deleteDialogOpen = useDataSinkStore((state) => state.deleteDialogOpen);\n const refreshDialogOpen = useDataSinkStore((state) => state.refreshDialogOpen);\n const currentDataSink = useDataSinkStore((state) => state.currentDataSink);\n const openDeleteDialog = useDataSinkStore((state) => state.openDeleteDialog);\n const closeDeleteDialog = useDataSinkStore((state) => state.closeDeleteDialog);\n const openRefreshDialog = useDataSinkStore((state) => state.openRefreshDialog);\n const closeRefreshDialog = useDataSinkStore((state) => state.closeRefreshDialog);\n\n // Data operations\n const { loading, error, dataSinks, deleteDataSink, refreshDataSink, refetch } = useDataSinkOperations();\n\n // Export hook\n const { downloadDataSink } = useExportDataSink();\n\n // Compute filtered DataSinks with setup states\n const dataSinksWithSetupState = useMemo(() => {\n return dataSinks.map((ds) => ({\n dataSink: ds,\n setupState: getSetupState(ds),\n }));\n }, [dataSinks]);\n\n // Compute filtered DataSinks\n const filteredDataSinks = useMemo(() => {\n let filtered = [...dataSinksWithSetupState];\n\n if (setupStateFilter === 'in_progress') {\n filtered = filtered.filter((item) => item.setupState !== 'completed');\n } else if (setupStateFilter === 'completed') {\n filtered = filtered.filter((item) => item.setupState === 'completed');\n }\n\n if (statusFilter !== null) {\n filtered = filtered.filter((item) => item.dataSink.status === statusFilter);\n }\n\n if (activeFilter !== null) {\n filtered = filtered.filter((item) => item.dataSink.isActive === activeFilter);\n }\n\n if (searchQuery.trim()) {\n const query = searchQuery.toLowerCase();\n filtered = filtered.filter(\n (item) =>\n item.dataSink.name?.toLowerCase().includes(query) ||\n item.dataSink.key.toLowerCase().includes(query) ||\n item.dataSink.description?.toLowerCase().includes(query)\n );\n }\n\n return filtered.sort((a, b) => new Date(b.dataSink.updatedAt).getTime() - new Date(a.dataSink.updatedAt).getTime());\n }, [dataSinksWithSetupState, setupStateFilter, statusFilter, activeFilter, searchQuery]);\n\n // Handlers\n const handleCreateDataSink = useCallback(() => {\n navigate('/datasinks/new');\n }, [navigate]);\n\n const handleViewDataSink = useCallback(\n (id: string) => {\n navigate(`/datasinks/${id}`);\n },\n [navigate]\n );\n\n const handleEditDataSink = useCallback(\n (id: string) => {\n navigate(`/datasinks/${id}/edit`);\n },\n [navigate]\n );\n\n const handleRefreshClick = useCallback(\n (id: string) => {\n const dataSink = dataSinks.find((ds) => ds.id === id);\n if (dataSink) {\n openRefreshDialog(dataSink);\n }\n },\n [dataSinks, openRefreshDialog]\n );\n\n const handleRefreshConfirm = useCallback(\n async (forceRefresh: boolean) => {\n if (currentDataSink) {\n await refreshDataSink({\n id: currentDataSink.id,\n forceRefresh,\n });\n closeRefreshDialog();\n }\n },\n [currentDataSink, refreshDataSink, closeRefreshDialog]\n );\n\n const handleDeleteClick = useCallback(\n (id: string) => {\n const dataSink = dataSinks.find((ds) => ds.id === id);\n if (dataSink) {\n openDeleteDialog(dataSink);\n }\n },\n [dataSinks, openDeleteDialog]\n );\n\n const handleDeleteConfirm = useCallback(async () => {\n if (currentDataSink) {\n try {\n await deleteDataSink(currentDataSink.id);\n if (isNative()) void nativeNotify('success');\n } catch (err) {\n if (isNative()) void nativeNotify('error');\n throw err;\n }\n closeDeleteDialog();\n }\n }, [currentDataSink, deleteDataSink, closeDeleteDialog]);\n\n const handleExportDataSink = useCallback(\n async (id: string) => {\n const dataSink = dataSinks.find((ds) => ds.id === id);\n if (dataSink) {\n await downloadDataSink(id, dataSink.name || dataSink.key);\n }\n },\n [dataSinks, downloadDataSink]\n );\n\n const handleImportDataSink = useCallback(() => {\n setIsImportDialogOpen(true);\n }, []);\n\n const handleImportSuccess = useCallback(\n (_dataSinkId: string, _dataSinkName: string | null, _wasUpdate: boolean) => {\n // Refetch DataSinks to show the newly imported one\n refetch();\n },\n [refetch]\n );\n\n const hasActiveFilters = useMemo(() => {\n return setupStateFilter !== 'all' || statusFilter !== null || activeFilter !== null || searchQuery.trim() !== '';\n }, [setupStateFilter, statusFilter, activeFilter, searchQuery]);\n\n const handleClearFilters = useCallback(() => {\n setSetupStateFilter('all');\n setStatusFilter(null);\n setActiveFilter(null);\n setSearchQuery('');\n }, [setStatusFilter, setActiveFilter, setSearchQuery]);\n\n // Setup state filter options\n const setupStateOptions: { value: SetupStateFilter; label: string }[] = [\n { value: 'all', label: tr('bigconsole.dataSinks.filters.setupState.all', 'All') },\n { value: 'in_progress', label: tr('bigconsole.dataSinks.filters.setupState.inProgress', 'In Progress') },\n { value: 'completed', label: tr('bigconsole.dataSinks.filters.setupState.completed', 'Completed') },\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 <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center' }}>\n <div\n style={{\n padding: 'var(--space-controlGap)',\n borderRadius: '50%',\n backgroundColor: 'var(--color-status-error-bgSubtle)',\n marginBottom: 'var(--space-formGap)',\n }}\n >\n <AlertCircle\n style={{\n height: 'var(--size-icon-xl)',\n width: 'var(--size-icon-xl)',\n color: 'var(--color-status-error-text)',\n }}\n />\n </div>\n <h3\n style={{\n fontSize: 'var(--font-size-body-lg)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-status-error-text)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n {tr('bigconsole.dataSinks.error.title', 'Failed to load Data Sinks')}\n </h3>\n <p\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-secondary)',\n marginBottom: 'var(--space-formGap)',\n }}\n >\n {error.message}\n </p>\n <Button size=\"sm\" onClick={() => refetch()}>\n {tr('bigconsole.dataSinks.error.retry', 'Try Again')}\n </Button>\n </div>\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 className=\"relative overflow-hidden border-b border-border-seam bg-gloss-card\">\n <AuroraBackground intensity=\"subtle\" />\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 <Container\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 <GradientText>{tr('bigconsole.dataSinks.title', 'Data Sinks')}</GradientText>\n </h1>\n <p style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-secondary)', margin: 0 }}>\n {tr('bigconsole.dataSinks.subtitle', 'Manage pre-processed data from FluidGrids workflows')}\n </p>\n </div>\n </div>\n\n <CTAOverflowMenu\n primary={{\n label: tr('bigconsole.dataSinks.actions.create', 'Create Data Sink'),\n onSelect: handleCreateDataSink,\n icon: (\n <Plus\n style={{\n marginRight: 'var(--space-iconGap)',\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n }}\n />\n ),\n }}\n actions={[\n {\n label: tr('bigconsole.dataSinks.actions.import', 'Import'),\n onSelect: handleImportDataSink,\n icon: <Upload style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />,\n },\n ]}\n />\n </div>\n </div>\n </div>\n\n {/* Main Content */}\n <div style={{ padding: 'var(--space-pagePadding)' }}>\n <PagePurpose className=\"mb-[var(--space-sectionGap)]\">\n Data sinks are the structured destinations that hold your processed data — define a schema once and every\n pipeline, parser, and workflow can write into it. Dashboards then query sinks directly, so a sink is where\n your data lives and where your charts read from.\n </PagePurpose>\n\n {/* Setup State Filter Tabs */}\n <div style={{ marginBottom: 'var(--space-formGap)' }}>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '2px',\n padding: '4px',\n backgroundColor: 'var(--color-bg-sunken)',\n borderRadius: 'var(--radius-card)',\n width: 'fit-content',\n }}\n >\n {setupStateOptions.map((option) => (\n <button\n key={option.value}\n type=\"button\"\n onClick={() => setSetupStateFilter(option.value)}\n style={{\n padding: 'var(--space-controlGap) var(--space-formGap)',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n borderRadius: 'var(--radius-button)',\n border: 'none',\n cursor: 'pointer',\n transition: 'all 0.2s ease',\n backgroundColor: setupStateFilter === option.value ? 'var(--color-bg-surface)' : 'transparent',\n color:\n setupStateFilter === option.value ? 'var(--color-text-primary)' : 'var(--color-text-secondary)',\n boxShadow: setupStateFilter === option.value ? '0 1px 2px rgba(0,0,0,0.05)' : 'none',\n }}\n >\n {option.label}\n </button>\n ))}\n </div>\n </div>\n\n {/* Search and Filters Row */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n marginBottom: 'var(--space-sectionGap)',\n flexWrap: 'wrap',\n }}\n >\n {/* Search Bar */}\n <div style={{ position: 'relative', maxWidth: '400px', flex: 1 }}>\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.dataSinks.search.placeholder', 'Search data sinks...')}\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\n {/* Status Filter */}\n <Select\n value={statusFilter || 'all'}\n onValueChange={(value) =>\n setStatusFilter(value === 'all' ? null : (value as 'ready' | 'error' | 'stale' | 'refreshing'))\n }\n >\n <SelectTrigger style={{ width: '150px' }}>\n <SelectValue placeholder={tr('bigconsole.dataSinks.filters.status.placeholder', 'All Statuses')} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">{tr('bigconsole.dataSinks.filters.status.all', 'All Statuses')}</SelectItem>\n <SelectItem value=\"ready\">{tr('bigconsole.dataSinks.filters.status.ready', 'Ready')}</SelectItem>\n <SelectItem value=\"error\">{tr('bigconsole.dataSinks.filters.status.error', 'Error')}</SelectItem>\n <SelectItem value=\"stale\">{tr('bigconsole.dataSinks.filters.status.stale', 'Stale')}</SelectItem>\n <SelectItem value=\"refreshing\">\n {tr('bigconsole.dataSinks.filters.status.refreshing', 'Refreshing')}\n </SelectItem>\n </SelectContent>\n </Select>\n\n {/* Active Filter */}\n <Select\n value={activeFilter === null ? 'all' : activeFilter ? 'true' : 'false'}\n onValueChange={(value) => setActiveFilter(value === 'all' ? null : value === 'true')}\n >\n <SelectTrigger style={{ width: '130px' }}>\n <SelectValue placeholder={tr('bigconsole.dataSinks.filters.active.placeholder', 'All')} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">{tr('bigconsole.dataSinks.filters.active.all', 'All')}</SelectItem>\n <SelectItem value=\"true\">{tr('bigconsole.dataSinks.filters.active.active', 'Active')}</SelectItem>\n <SelectItem value=\"false\">{tr('bigconsole.dataSinks.filters.active.inactive', 'Inactive')}</SelectItem>\n </SelectContent>\n </Select>\n\n {/* Clear Filters */}\n {hasActiveFilters && (\n <Button variant=\"ghost\" size=\"sm\" onClick={handleClearFilters}>\n <X\n style={{\n marginRight: 'var(--space-iconGap)',\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n }}\n />\n {tr('bigconsole.dataSinks.filters.clear', 'Clear Filters')}\n </Button>\n )}\n\n {/* Results Count + View Toggle */}\n <div style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: 'var(--space-controlGap)' }}>\n <Badge variant=\"secondary\">\n {filteredDataSinks.length}{' '}\n {filteredDataSinks.length === 1\n ? tr('bigconsole.dataSinks.count.single', 'Data Sink')\n : tr('bigconsole.dataSinks.count.plural', 'Data Sinks')}\n </Badge>\n <div\n style={{\n display: 'flex',\n borderRadius: 'var(--radius-button)',\n border: '1px solid var(--color-border)',\n overflow: 'hidden',\n }}\n >\n <button\n type=\"button\"\n onClick={() => toggleViewMode('grid')}\n title={tr('bigconsole.dataSinks.view.grid', 'Grid view')}\n style={{\n padding: '6px 8px',\n border: 'none',\n cursor: 'pointer',\n backgroundColor: viewMode === 'grid' ? 'var(--color-bg-sunken)' : 'transparent',\n color: viewMode === 'grid' ? 'var(--color-text-primary)' : 'var(--color-text-muted)',\n }}\n >\n <LayoutGrid size={16} />\n </button>\n <button\n type=\"button\"\n onClick={() => toggleViewMode('table')}\n title={tr('bigconsole.dataSinks.view.table', 'Table view')}\n style={{\n padding: '6px 8px',\n border: 'none',\n borderLeft: '1px solid var(--color-border)',\n cursor: 'pointer',\n backgroundColor: viewMode === 'table' ? 'var(--color-bg-sunken)' : 'transparent',\n color: viewMode === 'table' ? 'var(--color-text-primary)' : 'var(--color-text-muted)',\n }}\n >\n <Table2 size={16} />\n </button>\n </div>\n </div>\n </div>\n\n {/* Loading state */}\n {loading && dataSinks.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.dataSinks.loading', 'Loading data sinks...')}\n </p>\n </div>\n </div>\n )}\n\n {/* Empty state */}\n {!loading && dataSinks.length === 0 && (\n <GlassCard treatment=\"insight\" className=\"border-border-seam\">\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={tr('bigconsole.dataSinks.empty.title', 'No Data Sinks yet')}\n description={tr(\n 'bigconsole.dataSinks.empty.description',\n 'Data Sinks store pre-processed data from FluidGrids workflows for fast access in widgets.'\n )}\n action={\n <Button onClick={handleCreateDataSink}>\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.dataSinks.actions.create', 'Create Data Sink')}\n </Button>\n }\n />\n </GlassCard>\n )}\n\n {/* No results state */}\n {!loading && filteredDataSinks.length === 0 && dataSinks.length > 0 && (\n <GlassCard treatment=\"insight\" className=\"border-border-seam\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title={tr('bigconsole.dataSinks.empty.filteredTitle', 'No matching data sinks')}\n description={tr('bigconsole.dataSinks.empty.filtered', 'No data sinks match your filters')}\n action={\n <Button variant=\"ghost\" size=\"sm\" onClick={handleClearFilters}>\n {tr('bigconsole.dataSinks.filters.clear', 'Clear Filters')}\n </Button>\n }\n />\n </GlassCard>\n )}\n\n {/* DataSink Grid / Table */}\n {filteredDataSinks.length > 0 && viewMode === 'grid' && (\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fill, minmax(320px, 1fr))',\n gap: 'var(--space-formGap)',\n }}\n >\n {filteredDataSinks.map((item) => (\n <DataSinkCard\n key={item.dataSink.id}\n dataSink={item.dataSink}\n setupState={item.setupState}\n onView={handleViewDataSink}\n onEdit={handleEditDataSink}\n onRefresh={handleRefreshClick}\n onExport={handleExportDataSink}\n onDelete={handleDeleteClick}\n />\n ))}\n </div>\n )}\n\n {/* Table View */}\n {filteredDataSinks.length > 0 && viewMode === 'table' && (\n <div\n style={{\n border: '1px solid var(--color-border)',\n borderRadius: 'var(--radius-card)',\n overflow: 'hidden',\n }}\n >\n <div style={{ overflowX: 'auto' }}>\n <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 'var(--font-size-body-sm)' }}>\n <thead>\n <tr\n style={{\n backgroundColor: 'var(--color-bg-sunken)',\n borderBottom: '1px solid var(--color-border)',\n }}\n >\n <th\n style={{\n padding: '10px 12px',\n textAlign: 'left',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n whiteSpace: 'nowrap',\n }}\n >\n {tr('bigconsole.dataSinks.table.name', 'Name')}\n </th>\n <th\n style={{\n padding: '10px 12px',\n textAlign: 'left',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n whiteSpace: 'nowrap',\n }}\n >\n {tr('bigconsole.dataSinks.table.key', 'Key')}\n </th>\n <th\n style={{\n padding: '10px 12px',\n textAlign: 'left',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n whiteSpace: 'nowrap',\n }}\n >\n {tr('bigconsole.dataSinks.table.status', 'Status')}\n </th>\n <th\n style={{\n padding: '10px 12px',\n textAlign: 'left',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n whiteSpace: 'nowrap',\n }}\n >\n {tr('bigconsole.dataSinks.table.setup', 'Setup')}\n </th>\n <th\n style={{\n padding: '10px 12px',\n textAlign: 'center',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n whiteSpace: 'nowrap',\n }}\n >\n {tr('bigconsole.dataSinks.table.active', 'Active')}\n </th>\n <th\n style={{\n padding: '10px 12px',\n textAlign: 'left',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n whiteSpace: 'nowrap',\n }}\n >\n {tr('bigconsole.dataSinks.table.version', 'Version')}\n </th>\n <th\n style={{\n padding: '10px 12px',\n textAlign: 'left',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n whiteSpace: 'nowrap',\n }}\n >\n {tr('bigconsole.dataSinks.table.updated', 'Updated')}\n </th>\n <th\n style={{\n padding: '10px 12px',\n textAlign: 'right',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n whiteSpace: 'nowrap',\n }}\n >\n {tr('bigconsole.dataSinks.table.actions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody>\n {filteredDataSinks.map((item) => {\n const ds = item.dataSink;\n return (\n <tr\n key={ds.id}\n onClick={() => handleViewDataSink(ds.id)}\n style={{\n borderBottom: '1px solid var(--color-border)',\n cursor: 'pointer',\n transition: 'background-color 0.15s',\n }}\n onMouseEnter={(e) => {\n (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--color-bg-sunken)';\n }}\n onMouseLeave={(e) => {\n (e.currentTarget as HTMLElement).style.backgroundColor = 'transparent';\n }}\n >\n <td\n style={{\n padding: '10px 12px',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-primary)',\n maxWidth: 200,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {ds.name || ds.key}\n </td>\n <td\n style={{\n padding: '10px 12px',\n color: 'var(--color-text-muted)',\n fontFamily: 'monospace',\n fontSize: '12px',\n maxWidth: 160,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {ds.key}\n </td>\n <td style={{ padding: '10px 12px' }}>\n <DataSinkStatusBadge status={ds.status} />\n </td>\n <td style={{ padding: '10px 12px' }}>\n <SetupStateBadge state={item.setupState} />\n </td>\n <td style={{ padding: '10px 12px', textAlign: 'center' }}>\n <span\n style={{\n display: 'inline-block',\n width: 8,\n height: 8,\n borderRadius: '50%',\n backgroundColor: ds.isActive ? '#22c55e' : 'var(--color-text-muted)',\n }}\n title={\n ds.isActive\n ? tr('bigconsole.dataSinks.badges.active', 'Active')\n : tr('bigconsole.dataSinks.badges.inactive', 'Inactive')\n }\n />\n </td>\n <td style={{ padding: '10px 12px', color: 'var(--color-text-muted)' }}>v{ds.version ?? 0}</td>\n <td style={{ padding: '10px 12px', color: 'var(--color-text-muted)', whiteSpace: 'nowrap' }}>\n {new Date(ds.updatedAt).toLocaleDateString()}\n </td>\n <td style={{ padding: '10px 12px', textAlign: 'right' }}>\n <div\n style={{ display: 'flex', gap: 4, justifyContent: 'flex-end' }}\n onClick={(e) => e.stopPropagation()}\n >\n <button\n type=\"button\"\n title={tr('bigconsole.dataSinks.actions.view', 'View')}\n onClick={() => handleViewDataSink(ds.id)}\n style={{\n padding: 4,\n border: 'none',\n background: 'none',\n cursor: 'pointer',\n color: 'var(--color-text-muted)',\n borderRadius: 4,\n }}\n >\n <Eye size={14} />\n </button>\n <button\n type=\"button\"\n title={tr('bigconsole.dataSinks.actions.edit', 'Edit')}\n onClick={() => handleEditDataSink(ds.id)}\n style={{\n padding: 4,\n border: 'none',\n background: 'none',\n cursor: 'pointer',\n color: 'var(--color-text-muted)',\n borderRadius: 4,\n }}\n >\n <Pencil size={14} />\n </button>\n <button\n type=\"button\"\n title={tr('bigconsole.dataSinks.actions.refresh', 'Refresh')}\n onClick={() => handleRefreshClick(ds.id)}\n style={{\n padding: 4,\n border: 'none',\n background: 'none',\n cursor: 'pointer',\n color: 'var(--color-text-muted)',\n borderRadius: 4,\n }}\n >\n <RefreshCw size={14} />\n </button>\n <button\n type=\"button\"\n title={tr('bigconsole.dataSinks.actions.export', 'Export')}\n onClick={() => handleExportDataSink(ds.id)}\n style={{\n padding: 4,\n border: 'none',\n background: 'none',\n cursor: 'pointer',\n color: 'var(--color-text-muted)',\n borderRadius: 4,\n }}\n >\n <Download size={14} />\n </button>\n <button\n type=\"button\"\n title={tr('bigconsole.dataSinks.actions.delete', 'Delete')}\n onClick={() => handleDeleteClick(ds.id)}\n style={{\n padding: 4,\n border: 'none',\n background: 'none',\n cursor: 'pointer',\n color: 'var(--color-text-muted)',\n borderRadius: 4,\n }}\n >\n <Trash2 size={14} />\n </button>\n </div>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n </div>\n )}\n </div>\n\n {/* Dialogs */}\n {currentDataSink && (\n <>\n <DataSinkDeleteDialog\n dataSink={currentDataSink}\n isOpen={deleteDialogOpen}\n onClose={closeDeleteDialog}\n onConfirm={handleDeleteConfirm}\n />\n\n <DataSinkRefreshDialog\n dataSink={currentDataSink}\n isOpen={refreshDialogOpen}\n onClose={closeRefreshDialog}\n onConfirm={handleRefreshConfirm}\n />\n </>\n )}\n\n {/* Import DataSink Dialog */}\n <ImportDataSinkDialog\n isOpen={isImportDialogOpen}\n onClose={() => setIsImportDialogOpen(false)}\n onSuccess={handleImportSuccess}\n />\n </div>\n );\n});\n\nexport default DataSinksPage;\n"],"mappings":"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"}
1
+ {"version":3,"file":"DataSinksPage.js","names":[],"sources":["../../../src/bigconsole/pages/DataSinksPage.tsx"],"sourcesContent":["/**\n * DataSinksPage\n *\n * List and manage DataSinks - fetches data from backend.\n * Uses fe-libs shared UI components and semantic tokens for consistent styling.\n */\n\nimport { type FC, memo, useCallback, useMemo, useState } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { getProfileScopedKey } from '@burdenoff/fe-libs/shared/utils';\nimport { useAppNavigate } from '../contexts';\nimport { isNative, nativeNotify } from '../../utils/nativeBridge';\nimport { useDataSinkOperations } from '../hooks/useDataSinkOperations';\nimport { useExportDataSink } from '../hooks/useExportDataSink';\nimport { useDataSinkStore } from '../store/dataSinkStore';\nimport type { DataSink, DataSinkSetupState } from '../types';\nimport { DataSinkCard } from '../components/datasink/DataSinkCard';\nimport { DataSinkDeleteDialog } from '../components/datasink/DataSinkDeleteDialog';\nimport { DataSinkRefreshDialog } from '../components/datasink/DataSinkRefreshDialog';\nimport { ImportDataSinkDialog } from '../components/datasink/ImportDataSinkDialog';\n\n// fe-libs components\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } 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 AuroraBackground,\n GradientText,\n GlassCard,\n IllustratedEmptyState,\n CTAOverflowMenu,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\n\n// Lucide icons\nimport {\n Plus,\n Search,\n AlertCircle,\n Container,\n X,\n Upload,\n LayoutGrid,\n Table2,\n Eye,\n Pencil,\n RefreshCw,\n Download,\n Trash2,\n} from 'lucide-react';\nimport { DataSinkStatusBadge } from '../components/datasink/DataSinkStatusBadge';\nimport { SetupStateBadge } from '../components/datasink/SetupStateBadge';\n\n// ============================================================================\n// Types\n// ============================================================================\n\ntype SetupStateFilter = 'all' | 'in_progress' | 'completed';\ntype ListViewMode = 'grid' | 'table';\n\nconst VIEW_MODE_KEY = 'bigconsole-datasinks-view-mode';\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Determine setup state for a DataSink based on its properties.\n */\nconst getSetupState = (dataSink: DataSink): DataSinkSetupState => {\n if (dataSink.setupState === 'completed') {\n return 'completed';\n }\n if (dataSink.ttl !== null && dataSink.ttl !== undefined && dataSink.ttl > 0) {\n return 'completed';\n }\n if (dataSink.fluidGridsWorkflowId && dataSink.data && Object.keys(dataSink.data).length > 0) {\n return 'completed';\n }\n if (dataSink.fluidGridsWorkflowId) {\n return 'workflow_running';\n }\n return 'workflow_pending';\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const DataSinksPage: FC = memo(function DataSinksPage() {\n const navigate = useAppNavigate();\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\n // Local state\n const [setupStateFilter, setSetupStateFilter] = useState<SetupStateFilter>('all');\n const [isImportDialogOpen, setIsImportDialogOpen] = useState(false);\n const [viewMode, setViewMode] = useState<ListViewMode>(\n () => (localStorage.getItem(getProfileScopedKey(VIEW_MODE_KEY)) as ListViewMode) || 'grid'\n );\n\n const toggleViewMode = useCallback((mode: ListViewMode) => {\n setViewMode(mode);\n localStorage.setItem(getProfileScopedKey(VIEW_MODE_KEY), mode);\n }, []);\n\n // Store state\n const statusFilter = useDataSinkStore((state) => state.statusFilter);\n const activeFilter = useDataSinkStore((state) => state.activeFilter);\n const searchQuery = useDataSinkStore((state) => state.searchQuery);\n const setStatusFilter = useDataSinkStore((state) => state.setStatusFilter);\n const setActiveFilter = useDataSinkStore((state) => state.setActiveFilter);\n const setSearchQuery = useDataSinkStore((state) => state.setSearchQuery);\n const deleteDialogOpen = useDataSinkStore((state) => state.deleteDialogOpen);\n const refreshDialogOpen = useDataSinkStore((state) => state.refreshDialogOpen);\n const currentDataSink = useDataSinkStore((state) => state.currentDataSink);\n const openDeleteDialog = useDataSinkStore((state) => state.openDeleteDialog);\n const closeDeleteDialog = useDataSinkStore((state) => state.closeDeleteDialog);\n const openRefreshDialog = useDataSinkStore((state) => state.openRefreshDialog);\n const closeRefreshDialog = useDataSinkStore((state) => state.closeRefreshDialog);\n\n // Data operations\n const { loading, error, dataSinks, deleteDataSink, refreshDataSink, refetch } = useDataSinkOperations();\n\n // Export hook\n const { downloadDataSink } = useExportDataSink();\n\n // Compute filtered DataSinks with setup states\n const dataSinksWithSetupState = useMemo(() => {\n return dataSinks.map((ds) => ({\n dataSink: ds,\n setupState: getSetupState(ds),\n }));\n }, [dataSinks]);\n\n // Compute filtered DataSinks\n const filteredDataSinks = useMemo(() => {\n let filtered = [...dataSinksWithSetupState];\n\n if (setupStateFilter === 'in_progress') {\n filtered = filtered.filter((item) => item.setupState !== 'completed');\n } else if (setupStateFilter === 'completed') {\n filtered = filtered.filter((item) => item.setupState === 'completed');\n }\n\n if (statusFilter !== null) {\n filtered = filtered.filter((item) => item.dataSink.status === statusFilter);\n }\n\n if (activeFilter !== null) {\n filtered = filtered.filter((item) => item.dataSink.isActive === activeFilter);\n }\n\n if (searchQuery.trim()) {\n const query = searchQuery.toLowerCase();\n filtered = filtered.filter(\n (item) =>\n item.dataSink.name?.toLowerCase().includes(query) ||\n item.dataSink.key.toLowerCase().includes(query) ||\n item.dataSink.description?.toLowerCase().includes(query)\n );\n }\n\n return filtered.sort((a, b) => new Date(b.dataSink.updatedAt).getTime() - new Date(a.dataSink.updatedAt).getTime());\n }, [dataSinksWithSetupState, setupStateFilter, statusFilter, activeFilter, searchQuery]);\n\n // Handlers\n const handleCreateDataSink = useCallback(() => {\n navigate('/datasinks/new');\n }, [navigate]);\n\n const handleViewDataSink = useCallback(\n (id: string) => {\n navigate(`/datasinks/${id}`);\n },\n [navigate]\n );\n\n const handleEditDataSink = useCallback(\n (id: string) => {\n navigate(`/datasinks/${id}/edit`);\n },\n [navigate]\n );\n\n const handleRefreshClick = useCallback(\n (id: string) => {\n const dataSink = dataSinks.find((ds) => ds.id === id);\n if (dataSink) {\n openRefreshDialog(dataSink);\n }\n },\n [dataSinks, openRefreshDialog]\n );\n\n const handleRefreshConfirm = useCallback(\n async (forceRefresh: boolean) => {\n if (currentDataSink) {\n await refreshDataSink({\n id: currentDataSink.id,\n forceRefresh,\n });\n closeRefreshDialog();\n }\n },\n [currentDataSink, refreshDataSink, closeRefreshDialog]\n );\n\n const handleDeleteClick = useCallback(\n (id: string) => {\n const dataSink = dataSinks.find((ds) => ds.id === id);\n if (dataSink) {\n openDeleteDialog(dataSink);\n }\n },\n [dataSinks, openDeleteDialog]\n );\n\n const handleDeleteConfirm = useCallback(async () => {\n if (currentDataSink) {\n try {\n await deleteDataSink(currentDataSink.id);\n if (isNative()) void nativeNotify('success');\n } catch (err) {\n if (isNative()) void nativeNotify('error');\n throw err;\n }\n closeDeleteDialog();\n }\n }, [currentDataSink, deleteDataSink, closeDeleteDialog]);\n\n const handleExportDataSink = useCallback(\n async (id: string) => {\n const dataSink = dataSinks.find((ds) => ds.id === id);\n if (dataSink) {\n await downloadDataSink(id, dataSink.name || dataSink.key);\n }\n },\n [dataSinks, downloadDataSink]\n );\n\n const handleImportDataSink = useCallback(() => {\n setIsImportDialogOpen(true);\n }, []);\n\n const handleImportSuccess = useCallback(\n (_dataSinkId: string, _dataSinkName: string | null, _wasUpdate: boolean) => {\n // Refetch DataSinks to show the newly imported one\n refetch();\n },\n [refetch]\n );\n\n const hasActiveFilters = useMemo(() => {\n return setupStateFilter !== 'all' || statusFilter !== null || activeFilter !== null || searchQuery.trim() !== '';\n }, [setupStateFilter, statusFilter, activeFilter, searchQuery]);\n\n const handleClearFilters = useCallback(() => {\n setSetupStateFilter('all');\n setStatusFilter(null);\n setActiveFilter(null);\n setSearchQuery('');\n }, [setStatusFilter, setActiveFilter, setSearchQuery]);\n\n // Setup state filter options\n const setupStateOptions: { value: SetupStateFilter; label: string }[] = [\n { value: 'all', label: tr('bigconsole.dataSinks.filters.setupState.all', 'All') },\n { value: 'in_progress', label: tr('bigconsole.dataSinks.filters.setupState.inProgress', 'In Progress') },\n { value: 'completed', label: tr('bigconsole.dataSinks.filters.setupState.completed', 'Completed') },\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 <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center' }}>\n <div\n style={{\n padding: 'var(--space-controlGap)',\n borderRadius: '50%',\n backgroundColor: 'var(--color-status-error-bgSubtle)',\n marginBottom: 'var(--space-formGap)',\n }}\n >\n <AlertCircle\n style={{\n height: 'var(--size-icon-xl)',\n width: 'var(--size-icon-xl)',\n color: 'var(--color-status-error-text)',\n }}\n />\n </div>\n <h3\n style={{\n fontSize: 'var(--font-size-body-lg)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-status-error-text)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n {tr('bigconsole.dataSinks.error.title', 'Failed to load Data Sinks')}\n </h3>\n <p\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-secondary)',\n marginBottom: 'var(--space-formGap)',\n }}\n >\n {error.message}\n </p>\n <Button size=\"sm\" onClick={() => refetch()}>\n {tr('bigconsole.dataSinks.error.retry', 'Try Again')}\n </Button>\n </div>\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 className=\"relative overflow-hidden border-b border-border-seam bg-gloss-card\">\n <AuroraBackground intensity=\"subtle\" />\n <div style={{ padding: 'var(--space-pagePadding)' }}>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 'var(--space-formGap)',\n flexWrap: 'wrap',\n }}\n >\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-formGap)',\n flex: '1 1 280px',\n minWidth: 0,\n }}\n >\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 <Container\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 style={{ minWidth: 0 }}>\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 <GradientText>{tr('bigconsole.dataSinks.title', 'Data Sinks')}</GradientText>\n </h1>\n <p style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-secondary)', margin: 0 }}>\n {tr('bigconsole.dataSinks.subtitle', 'Manage pre-processed data from FluidGrids workflows')}\n </p>\n </div>\n </div>\n\n <CTAOverflowMenu\n primary={{\n label: tr('bigconsole.dataSinks.actions.create', 'Create Data Sink'),\n onSelect: handleCreateDataSink,\n icon: (\n <Plus\n style={{\n marginRight: 'var(--space-iconGap)',\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n }}\n />\n ),\n }}\n actions={[\n {\n label: tr('bigconsole.dataSinks.actions.import', 'Import'),\n onSelect: handleImportDataSink,\n icon: <Upload style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />,\n },\n ]}\n />\n </div>\n </div>\n </div>\n\n {/* Main Content */}\n <div style={{ padding: 'var(--space-pagePadding)' }}>\n <PagePurpose className=\"mb-[var(--space-sectionGap)]\">\n Data sinks are the structured destinations that hold your processed data — define a schema once and every\n pipeline, parser, and workflow can write into it. Dashboards then query sinks directly, so a sink is where\n your data lives and where your charts read from.\n </PagePurpose>\n\n {/* Setup State Filter Tabs */}\n <div style={{ marginBottom: 'var(--space-formGap)' }}>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '2px',\n padding: '4px',\n backgroundColor: 'var(--color-bg-sunken)',\n borderRadius: 'var(--radius-card)',\n width: 'fit-content',\n }}\n >\n {setupStateOptions.map((option) => (\n <button\n key={option.value}\n type=\"button\"\n onClick={() => setSetupStateFilter(option.value)}\n style={{\n padding: 'var(--space-controlGap) var(--space-formGap)',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n borderRadius: 'var(--radius-button)',\n border: 'none',\n cursor: 'pointer',\n transition: 'all 0.2s ease',\n backgroundColor: setupStateFilter === option.value ? 'var(--color-bg-surface)' : 'transparent',\n color:\n setupStateFilter === option.value ? 'var(--color-text-primary)' : 'var(--color-text-secondary)',\n boxShadow: setupStateFilter === option.value ? '0 1px 2px rgba(0,0,0,0.05)' : 'none',\n }}\n >\n {option.label}\n </button>\n ))}\n </div>\n </div>\n\n {/* Search and Filters Row */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n marginBottom: 'var(--space-sectionGap)',\n flexWrap: 'wrap',\n }}\n >\n {/* Search Bar */}\n <div style={{ position: 'relative', maxWidth: '400px', minWidth: 'min(100%, 240px)', flex: '1 1 240px' }}>\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.dataSinks.search.placeholder', 'Search data sinks...')}\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\n {/* Status Filter */}\n <Select\n value={statusFilter || 'all'}\n onValueChange={(value) =>\n setStatusFilter(value === 'all' ? null : (value as 'ready' | 'error' | 'stale' | 'refreshing'))\n }\n >\n <SelectTrigger style={{ width: 'min(100%, 150px)' }}>\n <SelectValue placeholder={tr('bigconsole.dataSinks.filters.status.placeholder', 'All Statuses')} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">{tr('bigconsole.dataSinks.filters.status.all', 'All Statuses')}</SelectItem>\n <SelectItem value=\"ready\">{tr('bigconsole.dataSinks.filters.status.ready', 'Ready')}</SelectItem>\n <SelectItem value=\"error\">{tr('bigconsole.dataSinks.filters.status.error', 'Error')}</SelectItem>\n <SelectItem value=\"stale\">{tr('bigconsole.dataSinks.filters.status.stale', 'Stale')}</SelectItem>\n <SelectItem value=\"refreshing\">\n {tr('bigconsole.dataSinks.filters.status.refreshing', 'Refreshing')}\n </SelectItem>\n </SelectContent>\n </Select>\n\n {/* Active Filter */}\n <Select\n value={activeFilter === null ? 'all' : activeFilter ? 'true' : 'false'}\n onValueChange={(value) => setActiveFilter(value === 'all' ? null : value === 'true')}\n >\n <SelectTrigger style={{ width: 'min(100%, 130px)' }}>\n <SelectValue placeholder={tr('bigconsole.dataSinks.filters.active.placeholder', 'All')} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">{tr('bigconsole.dataSinks.filters.active.all', 'All')}</SelectItem>\n <SelectItem value=\"true\">{tr('bigconsole.dataSinks.filters.active.active', 'Active')}</SelectItem>\n <SelectItem value=\"false\">{tr('bigconsole.dataSinks.filters.active.inactive', 'Inactive')}</SelectItem>\n </SelectContent>\n </Select>\n\n {/* Clear Filters */}\n {hasActiveFilters && (\n <Button variant=\"ghost\" size=\"sm\" onClick={handleClearFilters}>\n <X\n style={{\n marginRight: 'var(--space-iconGap)',\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n }}\n />\n {tr('bigconsole.dataSinks.filters.clear', 'Clear Filters')}\n </Button>\n )}\n\n {/* Results Count + View Toggle */}\n <div style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: 'var(--space-controlGap)' }}>\n <Badge variant=\"secondary\">\n {filteredDataSinks.length}{' '}\n {filteredDataSinks.length === 1\n ? tr('bigconsole.dataSinks.count.single', 'Data Sink')\n : tr('bigconsole.dataSinks.count.plural', 'Data Sinks')}\n </Badge>\n <div\n style={{\n display: 'flex',\n borderRadius: 'var(--radius-button)',\n border: '1px solid var(--color-border)',\n overflow: 'hidden',\n }}\n >\n <button\n type=\"button\"\n onClick={() => toggleViewMode('grid')}\n title={tr('bigconsole.dataSinks.view.grid', 'Grid view')}\n style={{\n padding: '6px 8px',\n border: 'none',\n cursor: 'pointer',\n backgroundColor: viewMode === 'grid' ? 'var(--color-bg-sunken)' : 'transparent',\n color: viewMode === 'grid' ? 'var(--color-text-primary)' : 'var(--color-text-muted)',\n }}\n >\n <LayoutGrid size={16} />\n </button>\n <button\n type=\"button\"\n onClick={() => toggleViewMode('table')}\n title={tr('bigconsole.dataSinks.view.table', 'Table view')}\n style={{\n padding: '6px 8px',\n border: 'none',\n borderLeft: '1px solid var(--color-border)',\n cursor: 'pointer',\n backgroundColor: viewMode === 'table' ? 'var(--color-bg-sunken)' : 'transparent',\n color: viewMode === 'table' ? 'var(--color-text-primary)' : 'var(--color-text-muted)',\n }}\n >\n <Table2 size={16} />\n </button>\n </div>\n </div>\n </div>\n\n {/* Loading state */}\n {loading && dataSinks.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.dataSinks.loading', 'Loading data sinks...')}\n </p>\n </div>\n </div>\n )}\n\n {/* Empty state */}\n {!loading && dataSinks.length === 0 && (\n <GlassCard treatment=\"insight\" className=\"border-border-seam\">\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={tr('bigconsole.dataSinks.empty.title', 'No Data Sinks yet')}\n description={tr(\n 'bigconsole.dataSinks.empty.description',\n 'Data Sinks store pre-processed data from FluidGrids workflows for fast access in widgets.'\n )}\n action={\n <Button onClick={handleCreateDataSink}>\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.dataSinks.actions.create', 'Create Data Sink')}\n </Button>\n }\n />\n </GlassCard>\n )}\n\n {/* No results state */}\n {!loading && filteredDataSinks.length === 0 && dataSinks.length > 0 && (\n <GlassCard treatment=\"insight\" className=\"border-border-seam\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title={tr('bigconsole.dataSinks.empty.filteredTitle', 'No matching data sinks')}\n description={tr('bigconsole.dataSinks.empty.filtered', 'No data sinks match your filters')}\n action={\n <Button variant=\"ghost\" size=\"sm\" onClick={handleClearFilters}>\n {tr('bigconsole.dataSinks.filters.clear', 'Clear Filters')}\n </Button>\n }\n />\n </GlassCard>\n )}\n\n {/* DataSink Grid / Table */}\n {filteredDataSinks.length > 0 && viewMode === 'grid' && (\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fill, minmax(min(100%, 320px), 1fr))',\n gap: 'var(--space-formGap)',\n }}\n >\n {filteredDataSinks.map((item) => (\n <DataSinkCard\n key={item.dataSink.id}\n dataSink={item.dataSink}\n setupState={item.setupState}\n onView={handleViewDataSink}\n onEdit={handleEditDataSink}\n onRefresh={handleRefreshClick}\n onExport={handleExportDataSink}\n onDelete={handleDeleteClick}\n />\n ))}\n </div>\n )}\n\n {/* Table View */}\n {filteredDataSinks.length > 0 && viewMode === 'table' && (\n <div\n style={{\n border: '1px solid var(--color-border)',\n borderRadius: 'var(--radius-card)',\n overflow: 'hidden',\n }}\n >\n <div style={{ overflowX: 'auto' }}>\n <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 'var(--font-size-body-sm)' }}>\n <thead>\n <tr\n style={{\n backgroundColor: 'var(--color-bg-sunken)',\n borderBottom: '1px solid var(--color-border)',\n }}\n >\n <th\n style={{\n padding: '10px 12px',\n textAlign: 'left',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n whiteSpace: 'nowrap',\n }}\n >\n {tr('bigconsole.dataSinks.table.name', 'Name')}\n </th>\n <th\n style={{\n padding: '10px 12px',\n textAlign: 'left',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n whiteSpace: 'nowrap',\n }}\n >\n {tr('bigconsole.dataSinks.table.key', 'Key')}\n </th>\n <th\n style={{\n padding: '10px 12px',\n textAlign: 'left',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n whiteSpace: 'nowrap',\n }}\n >\n {tr('bigconsole.dataSinks.table.status', 'Status')}\n </th>\n <th\n style={{\n padding: '10px 12px',\n textAlign: 'left',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n whiteSpace: 'nowrap',\n }}\n >\n {tr('bigconsole.dataSinks.table.setup', 'Setup')}\n </th>\n <th\n style={{\n padding: '10px 12px',\n textAlign: 'center',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n whiteSpace: 'nowrap',\n }}\n >\n {tr('bigconsole.dataSinks.table.active', 'Active')}\n </th>\n <th\n style={{\n padding: '10px 12px',\n textAlign: 'left',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n whiteSpace: 'nowrap',\n }}\n >\n {tr('bigconsole.dataSinks.table.version', 'Version')}\n </th>\n <th\n style={{\n padding: '10px 12px',\n textAlign: 'left',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n whiteSpace: 'nowrap',\n }}\n >\n {tr('bigconsole.dataSinks.table.updated', 'Updated')}\n </th>\n <th\n style={{\n padding: '10px 12px',\n textAlign: 'right',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n whiteSpace: 'nowrap',\n }}\n >\n {tr('bigconsole.dataSinks.table.actions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody>\n {filteredDataSinks.map((item) => {\n const ds = item.dataSink;\n return (\n <tr\n key={ds.id}\n onClick={() => handleViewDataSink(ds.id)}\n style={{\n borderBottom: '1px solid var(--color-border)',\n cursor: 'pointer',\n transition: 'background-color 0.15s',\n }}\n onMouseEnter={(e) => {\n (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--color-bg-sunken)';\n }}\n onMouseLeave={(e) => {\n (e.currentTarget as HTMLElement).style.backgroundColor = 'transparent';\n }}\n >\n <td\n style={{\n padding: '10px 12px',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-primary)',\n maxWidth: 200,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {ds.name || ds.key}\n </td>\n <td\n style={{\n padding: '10px 12px',\n color: 'var(--color-text-muted)',\n fontFamily: 'monospace',\n fontSize: '12px',\n maxWidth: 160,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {ds.key}\n </td>\n <td style={{ padding: '10px 12px' }}>\n <DataSinkStatusBadge status={ds.status} />\n </td>\n <td style={{ padding: '10px 12px' }}>\n <SetupStateBadge state={item.setupState} />\n </td>\n <td style={{ padding: '10px 12px', textAlign: 'center' }}>\n <span\n style={{\n display: 'inline-block',\n width: 8,\n height: 8,\n borderRadius: '50%',\n backgroundColor: ds.isActive ? '#22c55e' : 'var(--color-text-muted)',\n }}\n title={\n ds.isActive\n ? tr('bigconsole.dataSinks.badges.active', 'Active')\n : tr('bigconsole.dataSinks.badges.inactive', 'Inactive')\n }\n />\n </td>\n <td style={{ padding: '10px 12px', color: 'var(--color-text-muted)' }}>v{ds.version ?? 0}</td>\n <td style={{ padding: '10px 12px', color: 'var(--color-text-muted)', whiteSpace: 'nowrap' }}>\n {new Date(ds.updatedAt).toLocaleDateString()}\n </td>\n <td style={{ padding: '10px 12px', textAlign: 'right' }}>\n <div\n style={{ display: 'flex', gap: 4, justifyContent: 'flex-end' }}\n onClick={(e) => e.stopPropagation()}\n >\n <button\n type=\"button\"\n title={tr('bigconsole.dataSinks.actions.view', 'View')}\n onClick={() => handleViewDataSink(ds.id)}\n style={{\n padding: 4,\n border: 'none',\n background: 'none',\n cursor: 'pointer',\n color: 'var(--color-text-muted)',\n borderRadius: 4,\n }}\n >\n <Eye size={14} />\n </button>\n <button\n type=\"button\"\n title={tr('bigconsole.dataSinks.actions.edit', 'Edit')}\n onClick={() => handleEditDataSink(ds.id)}\n style={{\n padding: 4,\n border: 'none',\n background: 'none',\n cursor: 'pointer',\n color: 'var(--color-text-muted)',\n borderRadius: 4,\n }}\n >\n <Pencil size={14} />\n </button>\n <button\n type=\"button\"\n title={tr('bigconsole.dataSinks.actions.refresh', 'Refresh')}\n onClick={() => handleRefreshClick(ds.id)}\n style={{\n padding: 4,\n border: 'none',\n background: 'none',\n cursor: 'pointer',\n color: 'var(--color-text-muted)',\n borderRadius: 4,\n }}\n >\n <RefreshCw size={14} />\n </button>\n <button\n type=\"button\"\n title={tr('bigconsole.dataSinks.actions.export', 'Export')}\n onClick={() => handleExportDataSink(ds.id)}\n style={{\n padding: 4,\n border: 'none',\n background: 'none',\n cursor: 'pointer',\n color: 'var(--color-text-muted)',\n borderRadius: 4,\n }}\n >\n <Download size={14} />\n </button>\n <button\n type=\"button\"\n title={tr('bigconsole.dataSinks.actions.delete', 'Delete')}\n onClick={() => handleDeleteClick(ds.id)}\n style={{\n padding: 4,\n border: 'none',\n background: 'none',\n cursor: 'pointer',\n color: 'var(--color-text-muted)',\n borderRadius: 4,\n }}\n >\n <Trash2 size={14} />\n </button>\n </div>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n </div>\n )}\n </div>\n\n {/* Dialogs */}\n {currentDataSink && (\n <>\n <DataSinkDeleteDialog\n dataSink={currentDataSink}\n isOpen={deleteDialogOpen}\n onClose={closeDeleteDialog}\n onConfirm={handleDeleteConfirm}\n />\n\n <DataSinkRefreshDialog\n dataSink={currentDataSink}\n isOpen={refreshDialogOpen}\n onClose={closeRefreshDialog}\n onConfirm={handleRefreshConfirm}\n />\n </>\n )}\n\n {/* Import DataSink Dialog */}\n <ImportDataSinkDialog\n isOpen={isImportDialogOpen}\n onClose={() => setIsImportDialogOpen(false)}\n onSuccess={handleImportSuccess}\n />\n </div>\n );\n});\n\nexport default DataSinksPage;\n"],"mappings":"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"}
@@ -158,7 +158,7 @@ var _ = e(function() {
158
158
  children: [
159
159
  /* @__PURE__ */ d(a, { size: 14 }),
160
160
  " ",
161
- _ ? "Saved" : "Save"
161
+ _ ? "Saved locally" : "Save locally"
162
162
  ]
163
163
  })]
164
164
  })
@@ -166,7 +166,7 @@ var _ = e(function() {
166
166
  }),
167
167
  /* @__PURE__ */ d(u, {
168
168
  className: "mb-[var(--space-sectionGap)]",
169
- children: "Settings control the defaults BigConsole applies everywhere — how new dashboards are laid out, how aggressively widget data is cached, and how the UI is displayed. Tune these once to match how your team works; they apply across every dashboard you build."
169
+ children: "Settings control the defaults BigConsole applies everywhere — how new dashboards are laid out, how aggressively widget data is cached, and how the UI is displayed. Tune these once to match how your team works; they apply across every dashboard you build. These preferences are saved locally in this browser until the backend settings API is available."
170
170
  }),
171
171
  /* @__PURE__ */ f(c, {
172
172
  className: "mb-[var(--space-sectionGap)] p-[var(--space-cardPadding)]",
@@ -1 +1 @@
1
- {"version":3,"file":"SettingsPage.js","names":[],"sources":["../../../src/bigconsole/pages/SettingsPage.tsx"],"sourcesContent":["/**\n * SettingsPage\n *\n * BigConsole workspace settings and preferences.\n * Settings are persisted to localStorage until a backend settings API is available.\n */\n\nimport { type FC, memo, useState, useCallback, useEffect } from 'react';\nimport { AuroraBackground, GradientText, PagePurpose, EmphasisPanel } from '@burdenoff/fe-libs/ui';\nimport { Settings, Save, RotateCcw } from 'lucide-react';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface BigConsoleSettings {\n defaultRefreshInterval: number;\n defaultGridColumns: number;\n defaultWidgetHeight: number;\n cacheEnabled: boolean;\n cacheTTLSeconds: number;\n showWidgetBorders: boolean;\n compactMode: boolean;\n animationsEnabled: boolean;\n}\n\nconst STORAGE_KEY = 'bigconsole-settings';\n\nconst DEFAULT_SETTINGS: BigConsoleSettings = {\n defaultRefreshInterval: 0,\n defaultGridColumns: 12,\n defaultWidgetHeight: 4,\n cacheEnabled: true,\n cacheTTLSeconds: 300,\n showWidgetBorders: true,\n compactMode: false,\n animationsEnabled: true,\n};\n\n// ============================================================================\n// HELPERS\n// ============================================================================\n\nfunction loadSettings(): BigConsoleSettings {\n try {\n const stored = localStorage.getItem(STORAGE_KEY);\n if (stored) {\n return { ...DEFAULT_SETTINGS, ...JSON.parse(stored) };\n }\n } catch {\n // Fall through to defaults\n }\n return { ...DEFAULT_SETTINGS };\n}\n\nfunction saveSettings(settings: BigConsoleSettings): void {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(settings));\n}\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const SettingsPage: FC = memo(function SettingsPage() {\n const [settings, setSettings] = useState<BigConsoleSettings>(loadSettings);\n const [saved, setSaved] = useState(false);\n\n useEffect(() => {\n if (saved) {\n const timer = setTimeout(() => setSaved(false), 2000);\n return () => clearTimeout(timer);\n }\n }, [saved]);\n\n const handleChange = useCallback(<K extends keyof BigConsoleSettings>(key: K, value: BigConsoleSettings[K]) => {\n setSettings((prev) => ({ ...prev, [key]: value }));\n }, []);\n\n const handleSave = useCallback(() => {\n saveSettings(settings);\n setSaved(true);\n }, [settings]);\n\n const handleReset = useCallback(() => {\n setSettings({ ...DEFAULT_SETTINGS });\n saveSettings(DEFAULT_SETTINGS);\n setSaved(true);\n }, []);\n\n const inputStyle: React.CSSProperties = {\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-sm)',\n outline: 'none',\n };\n\n const labelStyle: React.CSSProperties = {\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-primary)',\n marginBottom: 4,\n };\n\n const descStyle: React.CSSProperties = {\n fontSize: 11,\n color: 'var(--color-text-muted)',\n marginTop: 4,\n };\n\n const sectionStyle: React.CSSProperties = {\n backgroundColor: 'var(--color-bg-surface)',\n border: '1px solid var(--color-border-seam)',\n borderRadius: 'var(--radius-card)',\n padding: 'var(--space-cardPadding)',\n marginBottom: 'var(--space-sectionGap)',\n boxShadow: 'var(--shadow-pop)',\n };\n\n return (\n <div style={{ minHeight: '100vh', backgroundColor: 'var(--color-bg-canvas)' }}>\n <div style={{ padding: 'var(--space-pagePadding)', maxWidth: 720, margin: '0 auto' }}>\n {/* Header */}\n <div\n className=\"relative overflow-hidden rounded-card border border-border-seam bg-gloss-card p-6\"\n style={{\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n marginBottom: 'var(--space-sectionGap)',\n flexWrap: 'wrap',\n gap: 'var(--space-formGap)',\n }}\n >\n <AuroraBackground intensity=\"subtle\" />\n <div>\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <Settings size={24} style={{ color: 'var(--color-text-primary)' }} />\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 <GradientText>Settings</GradientText>\n </h1>\n </div>\n <p style={{ fontSize: 'var(--font-size-body-md)', color: 'var(--color-text-secondary)', marginTop: 4 }}>\n Configure BigConsole preferences\n </p>\n </div>\n <div style={{ display: 'flex', gap: 8 }}>\n <button\n onClick={handleReset}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n padding: '8px 12px',\n borderRadius: 'var(--radius-button)',\n border: '1px solid var(--color-border)',\n backgroundColor: 'transparent',\n color: 'var(--color-text-secondary)',\n fontSize: 'var(--font-size-body-sm)',\n cursor: 'pointer',\n }}\n >\n <RotateCcw size={14} /> Reset\n </button>\n <button\n onClick={handleSave}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n padding: '8px 16px',\n borderRadius: 'var(--radius-button)',\n backgroundColor: saved ? 'var(--color-status-success-bg)' : '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: 'pointer',\n transition: 'background-color 200ms',\n }}\n >\n <Save size={14} /> {saved ? 'Saved' : 'Save'}\n </button>\n </div>\n </div>\n\n <PagePurpose className=\"mb-[var(--space-sectionGap)]\">\n Settings control the defaults BigConsole applies everywhere — how new dashboards are laid out, how\n aggressively widget data is cached, and how the UI is displayed. Tune these once to match how your team works;\n they apply across every dashboard you build.\n </PagePurpose>\n\n {/* Dashboard Defaults — primary emphasis zone */}\n <EmphasisPanel className=\"mb-[var(--space-sectionGap)] p-[var(--space-cardPadding)]\">\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: 16,\n }}\n >\n Dashboard Defaults\n </h2>\n <div style={{ display: 'grid', gap: 16 }}>\n <div>\n <label htmlFor=\"grid-cols\" style={labelStyle}>\n Grid Columns\n </label>\n <input\n id=\"grid-cols\"\n type=\"number\"\n min={4}\n max={24}\n value={settings.defaultGridColumns}\n onChange={(e) => handleChange('defaultGridColumns', parseInt(e.target.value) || 12)}\n style={inputStyle}\n />\n <p style={descStyle}>Number of columns in the dashboard grid (4-24)</p>\n </div>\n <div>\n <label htmlFor=\"widget-height\" style={labelStyle}>\n Default Widget Height\n </label>\n <input\n id=\"widget-height\"\n type=\"number\"\n min={2}\n max={12}\n value={settings.defaultWidgetHeight}\n onChange={(e) => handleChange('defaultWidgetHeight', parseInt(e.target.value) || 4)}\n style={inputStyle}\n />\n <p style={descStyle}>Default height units for new widgets (2-12)</p>\n </div>\n <div>\n <label htmlFor=\"refresh-interval\" style={labelStyle}>\n Auto-Refresh Interval (seconds)\n </label>\n <select\n id=\"refresh-interval\"\n value={settings.defaultRefreshInterval}\n onChange={(e) => handleChange('defaultRefreshInterval', parseInt(e.target.value))}\n style={inputStyle}\n >\n <option value={0}>Disabled</option>\n <option value={10}>10 seconds</option>\n <option value={30}>30 seconds</option>\n <option value={60}>1 minute</option>\n <option value={300}>5 minutes</option>\n <option value={600}>10 minutes</option>\n </select>\n <p style={descStyle}>How often widgets refresh their data automatically</p>\n </div>\n </div>\n </EmphasisPanel>\n\n {/* Cache Settings */}\n <div style={sectionStyle}>\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: 16,\n }}\n >\n Cache\n </h2>\n <div style={{ display: 'grid', gap: 16 }}>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>\n <div>\n <label style={labelStyle}>Enable Cache</label>\n <p style={descStyle}>Cache widget data to reduce API calls</p>\n </div>\n <button\n onClick={() => handleChange('cacheEnabled', !settings.cacheEnabled)}\n role=\"switch\"\n aria-checked={settings.cacheEnabled}\n aria-label=\"Enable cache\"\n style={{\n width: 44,\n height: 24,\n borderRadius: 12,\n backgroundColor: settings.cacheEnabled ? 'var(--color-action-primary-bg)' : 'var(--color-bg-sunken)',\n border: 'none',\n cursor: 'pointer',\n position: 'relative',\n transition: 'background-color 200ms',\n }}\n >\n <div\n style={{\n width: 18,\n height: 18,\n borderRadius: '50%',\n backgroundColor: 'white',\n position: 'absolute',\n top: 3,\n left: settings.cacheEnabled ? 23 : 3,\n transition: 'left 200ms',\n }}\n />\n </button>\n </div>\n {settings.cacheEnabled && (\n <div>\n <label htmlFor=\"cache-ttl\" style={labelStyle}>\n Cache TTL (seconds)\n </label>\n <input\n id=\"cache-ttl\"\n type=\"number\"\n min={30}\n max={3600}\n value={settings.cacheTTLSeconds}\n onChange={(e) => handleChange('cacheTTLSeconds', parseInt(e.target.value) || 300)}\n style={inputStyle}\n />\n <p style={descStyle}>How long cached data is considered fresh (30-3600)</p>\n </div>\n )}\n </div>\n </div>\n\n {/* Display Settings */}\n <div style={sectionStyle}>\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: 16,\n }}\n >\n Display\n </h2>\n <div style={{ display: 'grid', gap: 16 }}>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>\n <div>\n <label style={labelStyle}>Show Widget Borders</label>\n <p style={descStyle}>Display borders around widgets in dashboards</p>\n </div>\n <button\n onClick={() => handleChange('showWidgetBorders', !settings.showWidgetBorders)}\n role=\"switch\"\n aria-checked={settings.showWidgetBorders}\n aria-label=\"Show widget borders\"\n style={{\n width: 44,\n height: 24,\n borderRadius: 12,\n backgroundColor: settings.showWidgetBorders\n ? 'var(--color-action-primary-bg)'\n : 'var(--color-bg-sunken)',\n border: 'none',\n cursor: 'pointer',\n position: 'relative',\n transition: 'background-color 200ms',\n }}\n >\n <div\n style={{\n width: 18,\n height: 18,\n borderRadius: '50%',\n backgroundColor: 'white',\n position: 'absolute',\n top: 3,\n left: settings.showWidgetBorders ? 23 : 3,\n transition: 'left 200ms',\n }}\n />\n </button>\n </div>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>\n <div>\n <label style={labelStyle}>Compact Mode</label>\n <p style={descStyle}>Reduce padding and spacing for more content</p>\n </div>\n <button\n onClick={() => handleChange('compactMode', !settings.compactMode)}\n role=\"switch\"\n aria-checked={settings.compactMode}\n aria-label=\"Compact mode\"\n style={{\n width: 44,\n height: 24,\n borderRadius: 12,\n backgroundColor: settings.compactMode ? 'var(--color-action-primary-bg)' : 'var(--color-bg-sunken)',\n border: 'none',\n cursor: 'pointer',\n position: 'relative',\n transition: 'background-color 200ms',\n }}\n >\n <div\n style={{\n width: 18,\n height: 18,\n borderRadius: '50%',\n backgroundColor: 'white',\n position: 'absolute',\n top: 3,\n left: settings.compactMode ? 23 : 3,\n transition: 'left 200ms',\n }}\n />\n </button>\n </div>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>\n <div>\n <label style={labelStyle}>Animations</label>\n <p style={descStyle}>Enable transition animations and effects</p>\n </div>\n <button\n onClick={() => handleChange('animationsEnabled', !settings.animationsEnabled)}\n role=\"switch\"\n aria-checked={settings.animationsEnabled}\n aria-label=\"Animations\"\n style={{\n width: 44,\n height: 24,\n borderRadius: 12,\n backgroundColor: settings.animationsEnabled\n ? 'var(--color-action-primary-bg)'\n : 'var(--color-bg-sunken)',\n border: 'none',\n cursor: 'pointer',\n position: 'relative',\n transition: 'background-color 200ms',\n }}\n >\n <div\n style={{\n width: 18,\n height: 18,\n borderRadius: '50%',\n backgroundColor: 'white',\n position: 'absolute',\n top: 3,\n left: settings.animationsEnabled ? 23 : 3,\n transition: 'left 200ms',\n }}\n />\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n});\n\nexport default SettingsPage;\n"],"mappings":"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"}
1
+ {"version":3,"file":"SettingsPage.js","names":[],"sources":["../../../src/bigconsole/pages/SettingsPage.tsx"],"sourcesContent":["/**\n * SettingsPage\n *\n * BigConsole workspace settings and preferences.\n * Settings are persisted to localStorage until a backend settings API is available.\n */\n\nimport { type FC, memo, useState, useCallback, useEffect } from 'react';\nimport { AuroraBackground, GradientText, PagePurpose, EmphasisPanel } from '@burdenoff/fe-libs/ui';\nimport { Settings, Save, RotateCcw } from 'lucide-react';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface BigConsoleSettings {\n defaultRefreshInterval: number;\n defaultGridColumns: number;\n defaultWidgetHeight: number;\n cacheEnabled: boolean;\n cacheTTLSeconds: number;\n showWidgetBorders: boolean;\n compactMode: boolean;\n animationsEnabled: boolean;\n}\n\nconst STORAGE_KEY = 'bigconsole-settings';\n\nconst DEFAULT_SETTINGS: BigConsoleSettings = {\n defaultRefreshInterval: 0,\n defaultGridColumns: 12,\n defaultWidgetHeight: 4,\n cacheEnabled: true,\n cacheTTLSeconds: 300,\n showWidgetBorders: true,\n compactMode: false,\n animationsEnabled: true,\n};\n\n// ============================================================================\n// HELPERS\n// ============================================================================\n\nfunction loadSettings(): BigConsoleSettings {\n try {\n const stored = localStorage.getItem(STORAGE_KEY);\n if (stored) {\n return { ...DEFAULT_SETTINGS, ...JSON.parse(stored) };\n }\n } catch {\n // Fall through to defaults\n }\n return { ...DEFAULT_SETTINGS };\n}\n\nfunction saveSettings(settings: BigConsoleSettings): void {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(settings));\n}\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const SettingsPage: FC = memo(function SettingsPage() {\n const [settings, setSettings] = useState<BigConsoleSettings>(loadSettings);\n const [saved, setSaved] = useState(false);\n\n useEffect(() => {\n if (saved) {\n const timer = setTimeout(() => setSaved(false), 2000);\n return () => clearTimeout(timer);\n }\n }, [saved]);\n\n const handleChange = useCallback(<K extends keyof BigConsoleSettings>(key: K, value: BigConsoleSettings[K]) => {\n setSettings((prev) => ({ ...prev, [key]: value }));\n }, []);\n\n const handleSave = useCallback(() => {\n saveSettings(settings);\n setSaved(true);\n }, [settings]);\n\n const handleReset = useCallback(() => {\n setSettings({ ...DEFAULT_SETTINGS });\n saveSettings(DEFAULT_SETTINGS);\n setSaved(true);\n }, []);\n\n const inputStyle: React.CSSProperties = {\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-sm)',\n outline: 'none',\n };\n\n const labelStyle: React.CSSProperties = {\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-primary)',\n marginBottom: 4,\n };\n\n const descStyle: React.CSSProperties = {\n fontSize: 11,\n color: 'var(--color-text-muted)',\n marginTop: 4,\n };\n\n const sectionStyle: React.CSSProperties = {\n backgroundColor: 'var(--color-bg-surface)',\n border: '1px solid var(--color-border-seam)',\n borderRadius: 'var(--radius-card)',\n padding: 'var(--space-cardPadding)',\n marginBottom: 'var(--space-sectionGap)',\n boxShadow: 'var(--shadow-pop)',\n };\n\n return (\n <div style={{ minHeight: '100vh', backgroundColor: 'var(--color-bg-canvas)' }}>\n <div style={{ padding: 'var(--space-pagePadding)', maxWidth: 720, margin: '0 auto' }}>\n {/* Header */}\n <div\n className=\"relative overflow-hidden rounded-card border border-border-seam bg-gloss-card p-6\"\n style={{\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n marginBottom: 'var(--space-sectionGap)',\n flexWrap: 'wrap',\n gap: 'var(--space-formGap)',\n }}\n >\n <AuroraBackground intensity=\"subtle\" />\n <div>\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <Settings size={24} style={{ color: 'var(--color-text-primary)' }} />\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 <GradientText>Settings</GradientText>\n </h1>\n </div>\n <p style={{ fontSize: 'var(--font-size-body-md)', color: 'var(--color-text-secondary)', marginTop: 4 }}>\n Configure BigConsole preferences\n </p>\n </div>\n <div style={{ display: 'flex', gap: 8 }}>\n <button\n onClick={handleReset}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n padding: '8px 12px',\n borderRadius: 'var(--radius-button)',\n border: '1px solid var(--color-border)',\n backgroundColor: 'transparent',\n color: 'var(--color-text-secondary)',\n fontSize: 'var(--font-size-body-sm)',\n cursor: 'pointer',\n }}\n >\n <RotateCcw size={14} /> Reset\n </button>\n <button\n onClick={handleSave}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n padding: '8px 16px',\n borderRadius: 'var(--radius-button)',\n backgroundColor: saved ? 'var(--color-status-success-bg)' : '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: 'pointer',\n transition: 'background-color 200ms',\n }}\n >\n <Save size={14} /> {saved ? 'Saved locally' : 'Save locally'}\n </button>\n </div>\n </div>\n\n <PagePurpose className=\"mb-[var(--space-sectionGap)]\">\n Settings control the defaults BigConsole applies everywhere — how new dashboards are laid out, how\n aggressively widget data is cached, and how the UI is displayed. Tune these once to match how your team works;\n they apply across every dashboard you build. These preferences are saved locally in this browser until the\n backend settings API is available.\n </PagePurpose>\n\n {/* Dashboard Defaults — primary emphasis zone */}\n <EmphasisPanel className=\"mb-[var(--space-sectionGap)] p-[var(--space-cardPadding)]\">\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: 16,\n }}\n >\n Dashboard Defaults\n </h2>\n <div style={{ display: 'grid', gap: 16 }}>\n <div>\n <label htmlFor=\"grid-cols\" style={labelStyle}>\n Grid Columns\n </label>\n <input\n id=\"grid-cols\"\n type=\"number\"\n min={4}\n max={24}\n value={settings.defaultGridColumns}\n onChange={(e) => handleChange('defaultGridColumns', parseInt(e.target.value) || 12)}\n style={inputStyle}\n />\n <p style={descStyle}>Number of columns in the dashboard grid (4-24)</p>\n </div>\n <div>\n <label htmlFor=\"widget-height\" style={labelStyle}>\n Default Widget Height\n </label>\n <input\n id=\"widget-height\"\n type=\"number\"\n min={2}\n max={12}\n value={settings.defaultWidgetHeight}\n onChange={(e) => handleChange('defaultWidgetHeight', parseInt(e.target.value) || 4)}\n style={inputStyle}\n />\n <p style={descStyle}>Default height units for new widgets (2-12)</p>\n </div>\n <div>\n <label htmlFor=\"refresh-interval\" style={labelStyle}>\n Auto-Refresh Interval (seconds)\n </label>\n <select\n id=\"refresh-interval\"\n value={settings.defaultRefreshInterval}\n onChange={(e) => handleChange('defaultRefreshInterval', parseInt(e.target.value))}\n style={inputStyle}\n >\n <option value={0}>Disabled</option>\n <option value={10}>10 seconds</option>\n <option value={30}>30 seconds</option>\n <option value={60}>1 minute</option>\n <option value={300}>5 minutes</option>\n <option value={600}>10 minutes</option>\n </select>\n <p style={descStyle}>How often widgets refresh their data automatically</p>\n </div>\n </div>\n </EmphasisPanel>\n\n {/* Cache Settings */}\n <div style={sectionStyle}>\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: 16,\n }}\n >\n Cache\n </h2>\n <div style={{ display: 'grid', gap: 16 }}>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>\n <div>\n <label style={labelStyle}>Enable Cache</label>\n <p style={descStyle}>Cache widget data to reduce API calls</p>\n </div>\n <button\n onClick={() => handleChange('cacheEnabled', !settings.cacheEnabled)}\n role=\"switch\"\n aria-checked={settings.cacheEnabled}\n aria-label=\"Enable cache\"\n style={{\n width: 44,\n height: 24,\n borderRadius: 12,\n backgroundColor: settings.cacheEnabled ? 'var(--color-action-primary-bg)' : 'var(--color-bg-sunken)',\n border: 'none',\n cursor: 'pointer',\n position: 'relative',\n transition: 'background-color 200ms',\n }}\n >\n <div\n style={{\n width: 18,\n height: 18,\n borderRadius: '50%',\n backgroundColor: 'white',\n position: 'absolute',\n top: 3,\n left: settings.cacheEnabled ? 23 : 3,\n transition: 'left 200ms',\n }}\n />\n </button>\n </div>\n {settings.cacheEnabled && (\n <div>\n <label htmlFor=\"cache-ttl\" style={labelStyle}>\n Cache TTL (seconds)\n </label>\n <input\n id=\"cache-ttl\"\n type=\"number\"\n min={30}\n max={3600}\n value={settings.cacheTTLSeconds}\n onChange={(e) => handleChange('cacheTTLSeconds', parseInt(e.target.value) || 300)}\n style={inputStyle}\n />\n <p style={descStyle}>How long cached data is considered fresh (30-3600)</p>\n </div>\n )}\n </div>\n </div>\n\n {/* Display Settings */}\n <div style={sectionStyle}>\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: 16,\n }}\n >\n Display\n </h2>\n <div style={{ display: 'grid', gap: 16 }}>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>\n <div>\n <label style={labelStyle}>Show Widget Borders</label>\n <p style={descStyle}>Display borders around widgets in dashboards</p>\n </div>\n <button\n onClick={() => handleChange('showWidgetBorders', !settings.showWidgetBorders)}\n role=\"switch\"\n aria-checked={settings.showWidgetBorders}\n aria-label=\"Show widget borders\"\n style={{\n width: 44,\n height: 24,\n borderRadius: 12,\n backgroundColor: settings.showWidgetBorders\n ? 'var(--color-action-primary-bg)'\n : 'var(--color-bg-sunken)',\n border: 'none',\n cursor: 'pointer',\n position: 'relative',\n transition: 'background-color 200ms',\n }}\n >\n <div\n style={{\n width: 18,\n height: 18,\n borderRadius: '50%',\n backgroundColor: 'white',\n position: 'absolute',\n top: 3,\n left: settings.showWidgetBorders ? 23 : 3,\n transition: 'left 200ms',\n }}\n />\n </button>\n </div>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>\n <div>\n <label style={labelStyle}>Compact Mode</label>\n <p style={descStyle}>Reduce padding and spacing for more content</p>\n </div>\n <button\n onClick={() => handleChange('compactMode', !settings.compactMode)}\n role=\"switch\"\n aria-checked={settings.compactMode}\n aria-label=\"Compact mode\"\n style={{\n width: 44,\n height: 24,\n borderRadius: 12,\n backgroundColor: settings.compactMode ? 'var(--color-action-primary-bg)' : 'var(--color-bg-sunken)',\n border: 'none',\n cursor: 'pointer',\n position: 'relative',\n transition: 'background-color 200ms',\n }}\n >\n <div\n style={{\n width: 18,\n height: 18,\n borderRadius: '50%',\n backgroundColor: 'white',\n position: 'absolute',\n top: 3,\n left: settings.compactMode ? 23 : 3,\n transition: 'left 200ms',\n }}\n />\n </button>\n </div>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>\n <div>\n <label style={labelStyle}>Animations</label>\n <p style={descStyle}>Enable transition animations and effects</p>\n </div>\n <button\n onClick={() => handleChange('animationsEnabled', !settings.animationsEnabled)}\n role=\"switch\"\n aria-checked={settings.animationsEnabled}\n aria-label=\"Animations\"\n style={{\n width: 44,\n height: 24,\n borderRadius: 12,\n backgroundColor: settings.animationsEnabled\n ? 'var(--color-action-primary-bg)'\n : 'var(--color-bg-sunken)',\n border: 'none',\n cursor: 'pointer',\n position: 'relative',\n transition: 'background-color 200ms',\n }}\n >\n <div\n style={{\n width: 18,\n height: 18,\n borderRadius: '50%',\n backgroundColor: 'white',\n position: 'absolute',\n top: 3,\n left: settings.animationsEnabled ? 23 : 3,\n transition: 'left 200ms',\n }}\n />\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n});\n\nexport default SettingsPage;\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.707.3",
3
+ "version": "2026.708.1",
4
4
  "description": "BigConsole - AI-powered analytics and dashboard platform",
5
5
  "type": "module",
6
6
  "files": [