@burdenoff/microfe-bigconsole 2026.713.5 → 2026.713.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bigconsole/assistant/createSandboxAssistantTransport.js +79 -67
- package/dist/bigconsole/assistant/createSandboxAssistantTransport.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetWrapper.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js.map +1 -1
- package/dist/bigconsole/hooks/useDataSinkOperations.js +4 -1
- package/dist/bigconsole/hooks/useDataSinkOperations.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkViewPage.js +226 -178
- package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
- package/dist/bigconsole/pages/WidgetDemoPage.js.map +1 -1
- package/dist/bigconsole/utils/widgetTypeMapping.js.map +1 -1
- package/dist/generated/wspace-operations.js +8 -1
- package/dist/generated/wspace-operations.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataSinkViewPage.js","names":[],"sources":["../../../src/bigconsole/pages/DataSinkViewPage.tsx"],"sourcesContent":["/**\n * DataSink View Page\n *\n * Page for viewing DataSink details, data preview, and actions.\n */\n\nimport { memo, useState, useEffect, useCallback } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { useAppNavigate } from '../contexts';\nimport { isNative, nativeConfirm, nativeImpact, nativeNotify } from '../../utils/nativeBridge';\nimport { formatDistanceToNow } from 'date-fns';\nimport { useDataSinkOperations } from '../hooks/useDataSinkOperations';\nimport { useDataSinkSubscription } from '../hooks/useDataSinkSubscription';\nimport { useDataSinkStore } from '../store/dataSinkStore';\nimport { DataSinkStatusBadge } from '../components/datasink/DataSinkStatusBadge';\nimport { DataSinkDataViewer } from '../components/datasink/DataSinkDataViewer';\nimport { DataSinkTableViewer } from '../components/datasink/DataSinkTableViewer';\nimport { LinkedWorkflowsPanel } from '../components/datasink/LinkedWorkflowsPanel';\nimport { LinkedParsersPanel } from '../components/datasink/LinkedParsersPanel';\nimport { WorkflowStatusPanel } from '../components/datasink/WorkflowStatusPanel';\nimport { ExportDataSinkDialog } from '../components/datasink/ExportDataSinkDialog';\n\n// fe-libs UI components\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport { GlassCard, IllustratedEmptyState, PagePurpose, NextSteps } from '@burdenoff/fe-libs/ui';\n\n// Lucide icons\nimport {\n ArrowLeft,\n Edit,\n RefreshCw,\n Trash2,\n Database,\n Loader2,\n AlertCircle,\n Eye,\n EyeOff,\n Download,\n Grid3X3,\n Code,\n} from 'lucide-react';\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const DataSinkViewPage = memo(function DataSinkViewPage() {\n const { dataSinkId } = useParams<{ dataSinkId: string; consoleId: string }>();\n const navigate = useAppNavigate();\n\n // Local state\n const [showData, setShowData] = useState(false);\n const [isRefreshing, setIsRefreshing] = useState(false);\n const [isDeleting, setIsDeleting] = useState(false);\n const [isExportDialogOpen, setIsExportDialogOpen] = useState(false);\n const [dataPreview, setDataPreview] = useState<Record<string, unknown> | null>(null);\n const [dataLoading, setDataLoading] = useState(false);\n const [dataViewMode, setDataViewMode] = useState<'table' | 'json'>('table');\n\n // Store\n const dataSink = useDataSinkStore((state) => (dataSinkId ? state.dataSinks.get(dataSinkId) : undefined));\n\n // Operations\n const { loading, error, fetchDataSink, getDataSinkData, refreshDataSink, deleteDataSink } = useDataSinkOperations({\n skipFetch: true,\n });\n\n // Subscribe to updates\n useDataSinkSubscription({\n dataSinkId,\n enabled: !!dataSinkId,\n });\n\n // Load DataSink on mount - always fetch full data to get workflowLinks\n useEffect(() => {\n if (dataSinkId) {\n fetchDataSink(dataSinkId);\n }\n }, [dataSinkId, fetchDataSink]);\n\n // Handle back navigation\n const handleBack = useCallback(() => {\n navigate(`/datasinks`);\n }, [navigate]);\n\n // Handle edit\n const handleEdit = useCallback(() => {\n navigate(`/datasinks/${dataSinkId}/edit`);\n }, [navigate, dataSinkId]);\n\n // Handle refresh\n const handleRefresh = useCallback(async () => {\n if (!dataSinkId) return;\n setIsRefreshing(true);\n try {\n await refreshDataSink({ id: dataSinkId });\n } catch (err) {\n } finally {\n setIsRefreshing(false);\n }\n }, [dataSinkId, refreshDataSink]);\n\n // Handle delete\n const handleDelete = useCallback(async () => {\n if (!dataSinkId) return;\n const native = await nativeConfirm({\n title: 'Delete DataSink?',\n message: 'Are you sure you want to delete this DataSink?',\n okButtonTitle: 'Delete',\n cancelButtonTitle: 'Cancel',\n });\n const ok = native === null ? window.confirm('Are you sure you want to delete this DataSink?') : native;\n if (!ok) return;\n nativeImpact('medium');\n setIsDeleting(true);\n try {\n await deleteDataSink(dataSinkId);\n if (isNative()) void nativeNotify('success');\n navigate(`/datasinks`);\n } catch (err) {\n if (isNative()) void nativeNotify('error');\n } finally {\n setIsDeleting(false);\n }\n }, [dataSinkId, deleteDataSink, navigate]);\n\n // Handle show data\n const handleShowData = useCallback(async () => {\n if (!dataSinkId) return;\n if (showData) {\n setShowData(false);\n return;\n }\n setDataLoading(true);\n try {\n const result = await getDataSinkData({ id: dataSinkId });\n if (result) {\n // Use raw data for preview\n setDataPreview((result.raw as Record<string, unknown>) || {});\n }\n setShowData(true);\n } catch (err) {\n } finally {\n setDataLoading(false);\n }\n }, [dataSinkId, showData, getDataSinkData]);\n\n // Handle export\n const handleExport = useCallback(() => {\n setIsExportDialogOpen(true);\n }, []);\n\n const handleExportClose = useCallback(() => {\n setIsExportDialogOpen(false);\n }, []);\n\n // Loading state\n if (loading && !dataSink) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <Loader2 className=\"w-8 h-8 text-text-secondary animate-spin\" />\n </div>\n );\n }\n\n // Error state\n if (error) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px] p-card-padding\">\n <div className=\"text-center\">\n <AlertCircle className=\"w-12 h-12 text-state-error mx-auto mb-spacing-md\" />\n <p className=\"text-state-error text-body-sm font-medium mb-spacing-sm\">Failed to load DataSink</p>\n <p className=\"text-text-tertiary text-body-xs mb-spacing-lg\">{error.message}</p>\n <Button onClick={handleBack} variant=\"ghost\" size=\"sm\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n Go back\n </Button>\n </div>\n </div>\n );\n }\n\n // Not found state\n if (!dataSink) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px] p-card-padding\">\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"DataSink not found\"\n description=\"The DataSink you're looking for doesn't exist or has been deleted.\"\n action={\n <Button onClick={handleBack} variant=\"default\" size=\"default\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n Go back to DataSinks\n </Button>\n }\n />\n </div>\n );\n }\n\n return (\n <div className=\"p-card-padding space-y-spacing-lg\">\n {/* Header */}\n <div className=\"flex flex-col sm:flex-row sm:items-start sm:justify-between gap-spacing-md\">\n <div className=\"flex-1\">\n <Button onClick={handleBack} variant=\"ghost\" size=\"sm\" className=\"mb-spacing-md\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n Back to DataSinks\n </Button>\n <div className=\"flex items-center gap-spacing-sm flex-wrap\">\n <h1 className=\"text-heading-h1 font-bold text-text-primary\">{dataSink.name || 'Untitled'}</h1>\n <DataSinkStatusBadge status={dataSink.status} />\n </div>\n <p className=\"text-body-sm text-text-tertiary font-mono mt-spacing-xs\">{dataSink.key}</p>\n {dataSink.description && (\n <p className=\"text-body-sm text-text-secondary mt-spacing-sm\">{dataSink.description}</p>\n )}\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center gap-spacing-sm flex-wrap\">\n <Button onClick={handleRefresh} disabled={isRefreshing} variant=\"secondary\" size=\"default\">\n <RefreshCw className={`w-4 h-4 mr-2 ${isRefreshing ? 'animate-spin' : ''}`} />\n {isRefreshing ? 'Refreshing...' : 'Refresh'}\n </Button>\n <Button onClick={handleExport} variant=\"secondary\" size=\"default\">\n <Download className=\"w-4 h-4 mr-2\" />\n Export\n </Button>\n <Button onClick={handleEdit} variant=\"secondary\" size=\"default\">\n <Edit className=\"w-4 h-4 mr-2\" />\n Edit\n </Button>\n <Button onClick={handleDelete} disabled={isDeleting} variant=\"destructive\" size=\"default\">\n <Trash2 className=\"w-4 h-4 mr-2\" />\n {isDeleting ? 'Deleting...' : 'Delete'}\n </Button>\n </div>\n </div>\n\n <PagePurpose>\n A data sink is a structured store that holds your processed data and serves it to dashboards. From here you can\n inspect its schema and stats, preview the cached rows, refresh it from its linked workflow, or export it.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"bigconsole-datasink-view\"\n steps={[\n {\n id: 'preview',\n label: 'Preview the data',\n description: 'Open the cached rows to confirm the sink holds what you expect.',\n onClick: handleShowData,\n },\n {\n id: 'refresh',\n label: 'Refresh from source',\n description: 'Re-run the linked workflow to pull the latest data.',\n onClick: handleRefresh,\n },\n {\n id: 'build-dashboard',\n label: 'Visualize it on a dashboard',\n description: 'Add widgets that query this sink to see your data live.',\n onClick: () => navigate('/dashboards'),\n },\n {\n id: 'export',\n label: 'Export the data',\n description: 'Download the contents for use elsewhere.',\n onClick: handleExport,\n },\n ]}\n />\n\n {/* Details Grid */}\n <div className=\"grid gap-spacing-lg md:grid-cols-2\">\n {/* Info Panel — primary emphasis zone */}\n <GlassCard treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle>Details</CardTitle>\n </CardHeader>\n <CardContent>\n <dl className=\"space-y-spacing-md text-body-sm\">\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Status</dt>\n <dd>\n <DataSinkStatusBadge status={dataSink.status} />\n </dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Cache TTL</dt>\n <dd className=\"text-text-primary font-medium\">{dataSink.ttl ? `${dataSink.ttl}s` : 'None'}</dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Refresh Type</dt>\n <dd className=\"text-text-primary font-medium capitalize\">{dataSink.refresh?.type || 'Manual'}</dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Size</dt>\n <dd className=\"text-text-primary font-medium\">\n {dataSink.sizeBytes ? `${(dataSink.sizeBytes / 1024).toFixed(2)} KB` : '0 KB'}\n </dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Version</dt>\n <dd className=\"text-text-primary font-medium\">{dataSink.version || 1}</dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Last Refreshed</dt>\n <dd className=\"text-text-primary font-medium\">\n {dataSink.lastRefreshedAt\n ? formatDistanceToNow(new Date(dataSink.lastRefreshedAt), { addSuffix: true })\n : 'Never'}\n </dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Created</dt>\n <dd className=\"text-text-primary font-medium\">\n {formatDistanceToNow(new Date(dataSink.createdAt), { addSuffix: true })}\n </dd>\n </div>\n </dl>\n </CardContent>\n </GlassCard>\n\n {/* Workflow Status Panel */}\n {dataSink.fluidGridsWorkflowId && (\n <WorkflowStatusPanel\n workflowId={dataSink.fluidGridsWorkflowId}\n executionId={dataSink.fluidGridsWorkflowExecutionId || undefined}\n lastRefreshedAt={dataSink.lastRefreshedAt || undefined}\n setupState={dataSink.setupState}\n status={dataSink.status}\n onRerunWorkflow={handleRefresh}\n disabled={isRefreshing}\n isRerunning={isRefreshing}\n />\n )}\n\n {/* Linked Workflows */}\n <LinkedWorkflowsPanel workflowLinks={dataSink.workflowLinks} />\n\n {/* Linked Parsers */}\n <LinkedParsersPanel dataSinkKey={dataSink.key} />\n </div>\n\n {/* Data Preview Section */}\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0\">\n <CardTitle className=\"flex items-center gap-spacing-sm\">\n <Database className=\"w-4 h-4 text-text-secondary\" />\n Data Preview\n </CardTitle>\n <div className=\"flex items-center gap-2\">\n {showData && (\n <div className=\"flex items-center border border-border-default rounded-md overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setDataViewMode('table')}\n className={`p-1.5 ${dataViewMode === 'table' ? 'bg-bg-sunken text-text-primary' : 'text-text-secondary hover:text-text-primary'}`}\n title=\"Table view\"\n >\n <Grid3X3 className=\"w-4 h-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setDataViewMode('json')}\n className={`p-1.5 ${dataViewMode === 'json' ? 'bg-bg-sunken text-text-primary' : 'text-text-secondary hover:text-text-primary'}`}\n title=\"JSON view\"\n >\n <Code className=\"w-4 h-4\" />\n </button>\n </div>\n )}\n <Button\n onClick={handleShowData}\n disabled={dataLoading}\n variant={showData ? 'secondary' : 'default'}\n size=\"sm\"\n >\n {dataLoading ? (\n <>\n <Loader2 className=\"w-4 h-4 mr-2 animate-spin\" />\n Loading...\n </>\n ) : showData ? (\n <>\n <EyeOff className=\"w-4 h-4 mr-2\" />\n Hide Data\n </>\n ) : (\n <>\n <Eye className=\"w-4 h-4 mr-2\" />\n Show Data\n </>\n )}\n </Button>\n </div>\n </CardHeader>\n\n {showData && dataPreview && (\n <CardContent>\n {dataViewMode === 'table' ? (\n <DataSinkTableViewer data={dataPreview} maxHeight=\"400px\" />\n ) : (\n <DataSinkDataViewer data={dataPreview} maxHeight=\"400px\" />\n )}\n </CardContent>\n )}\n\n {!showData && (\n <CardContent className=\"text-center p-spacing-xl\">\n <Database className=\"w-10 h-10 text-text-tertiary mx-auto mb-spacing-md\" />\n <p className=\"text-body-sm text-text-secondary\">Click "Show Data" to preview the cached data.</p>\n </CardContent>\n )}\n </Card>\n\n {/* Export DataSink Dialog */}\n <ExportDataSinkDialog\n isOpen={isExportDialogOpen}\n dataSinkId={dataSinkId || null}\n dataSinkName={dataSink.name || dataSink.key}\n onClose={handleExportClose}\n />\n </div>\n );\n});\n\nexport default DataSinkViewPage;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DataSinkViewPage.js","names":[],"sources":["../../../src/bigconsole/pages/DataSinkViewPage.tsx"],"sourcesContent":["/**\n * DataSink View Page\n *\n * Page for viewing DataSink details, data preview, and actions.\n */\n\nimport { memo, useState, useEffect, useCallback } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { useAppNavigate } from '../contexts';\nimport { isNative, nativeConfirm, nativeImpact, nativeNotify } from '../../utils/nativeBridge';\nimport { formatDistanceToNow } from 'date-fns';\nimport { useDataSinkOperations } from '../hooks/useDataSinkOperations';\nimport { useDataSinkSubscription } from '../hooks/useDataSinkSubscription';\nimport { useDataSinkStore } from '../store/dataSinkStore';\nimport { DataSinkStatusBadge } from '../components/datasink/DataSinkStatusBadge';\nimport { DataSinkDataViewer } from '../components/datasink/DataSinkDataViewer';\nimport { DataSinkTableViewer } from '../components/datasink/DataSinkTableViewer';\nimport { LinkedWorkflowsPanel } from '../components/datasink/LinkedWorkflowsPanel';\nimport { LinkedParsersPanel } from '../components/datasink/LinkedParsersPanel';\nimport { WorkflowStatusPanel } from '../components/datasink/WorkflowStatusPanel';\nimport { ExportDataSinkDialog } from '../components/datasink/ExportDataSinkDialog';\n\n// fe-libs UI components\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport { GlassCard, IllustratedEmptyState, PagePurpose, NextSteps } from '@burdenoff/fe-libs/ui';\n\n// Lucide icons\nimport {\n ArrowLeft,\n Edit,\n RefreshCw,\n Trash2,\n Database,\n Loader2,\n AlertCircle,\n Eye,\n EyeOff,\n Download,\n Grid3X3,\n Code,\n} from 'lucide-react';\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const DataSinkViewPage = memo(function DataSinkViewPage() {\n const { dataSinkId } = useParams<{ dataSinkId: string; consoleId: string }>();\n const navigate = useAppNavigate();\n\n // Local state\n const [showData, setShowData] = useState(false);\n const [isRefreshing, setIsRefreshing] = useState(false);\n const [isDeleting, setIsDeleting] = useState(false);\n const [isExportDialogOpen, setIsExportDialogOpen] = useState(false);\n const [dataPreview, setDataPreview] = useState<Record<string, unknown> | null>(null);\n const [dataLoading, setDataLoading] = useState(false);\n const [dataViewMode, setDataViewMode] = useState<'table' | 'json'>('table');\n // v3.0: server-side pagination for array payloads (avoids loading millions of rows).\n const [pageSize, setPageSize] = useState(100);\n const [pageOffset, setPageOffset] = useState(0);\n const [dataTotalCount, setDataTotalCount] = useState<number | null>(null);\n const [dataHasMore, setDataHasMore] = useState(false);\n\n // Store\n const dataSink = useDataSinkStore((state) => (dataSinkId ? state.dataSinks.get(dataSinkId) : undefined));\n\n // Operations\n const { loading, error, fetchDataSink, getDataSinkData, refreshDataSink, deleteDataSink } = useDataSinkOperations({\n skipFetch: true,\n });\n\n // Subscribe to updates\n useDataSinkSubscription({\n dataSinkId,\n enabled: !!dataSinkId,\n });\n\n // Load DataSink on mount - always fetch full data to get workflowLinks\n useEffect(() => {\n if (dataSinkId) {\n fetchDataSink(dataSinkId);\n }\n }, [dataSinkId, fetchDataSink]);\n\n // Handle back navigation\n const handleBack = useCallback(() => {\n navigate(`/datasinks`);\n }, [navigate]);\n\n // Handle edit\n const handleEdit = useCallback(() => {\n navigate(`/datasinks/${dataSinkId}/edit`);\n }, [navigate, dataSinkId]);\n\n // Handle refresh\n const handleRefresh = useCallback(async () => {\n if (!dataSinkId) return;\n setIsRefreshing(true);\n try {\n await refreshDataSink({ id: dataSinkId });\n } catch (err) {\n } finally {\n setIsRefreshing(false);\n }\n }, [dataSinkId, refreshDataSink]);\n\n // Handle delete\n const handleDelete = useCallback(async () => {\n if (!dataSinkId) return;\n const native = await nativeConfirm({\n title: 'Delete DataSink?',\n message: 'Are you sure you want to delete this DataSink?',\n okButtonTitle: 'Delete',\n cancelButtonTitle: 'Cancel',\n });\n const ok = native === null ? window.confirm('Are you sure you want to delete this DataSink?') : native;\n if (!ok) return;\n nativeImpact('medium');\n setIsDeleting(true);\n try {\n await deleteDataSink(dataSinkId);\n if (isNative()) void nativeNotify('success');\n navigate(`/datasinks`);\n } catch (err) {\n if (isNative()) void nativeNotify('error');\n } finally {\n setIsDeleting(false);\n }\n }, [dataSinkId, deleteDataSink, navigate]);\n\n // Load one page of the sink's data (v3.0: server-side pagination).\n const loadDataPage = useCallback(\n async (offset: number, size: number) => {\n if (!dataSinkId) return;\n setDataLoading(true);\n try {\n const result = await getDataSinkData({ id: dataSinkId }, { limit: size, offset });\n if (result) {\n setDataPreview((result.raw as Record<string, unknown>) || {});\n // totalCount is non-null only for array payloads being paginated.\n setDataTotalCount(typeof result.totalCount === 'number' ? result.totalCount : null);\n setDataHasMore(Boolean(result.hasMore));\n setPageOffset(offset);\n }\n } catch {\n // handled by the hook's error state\n } finally {\n setDataLoading(false);\n }\n },\n [dataSinkId, getDataSinkData]\n );\n\n // Handle show data (toggles the preview; loads the first page).\n const handleShowData = useCallback(async () => {\n if (!dataSinkId) return;\n if (showData) {\n setShowData(false);\n return;\n }\n await loadDataPage(0, pageSize);\n setShowData(true);\n }, [dataSinkId, showData, loadDataPage, pageSize]);\n\n const handlePageSizeChange = useCallback(\n (size: number) => {\n setPageSize(size);\n void loadDataPage(0, size);\n },\n [loadDataPage]\n );\n\n // Handle export\n const handleExport = useCallback(() => {\n setIsExportDialogOpen(true);\n }, []);\n\n const handleExportClose = useCallback(() => {\n setIsExportDialogOpen(false);\n }, []);\n\n // Loading state\n if (loading && !dataSink) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <Loader2 className=\"w-8 h-8 text-text-secondary animate-spin\" />\n </div>\n );\n }\n\n // Error state\n if (error) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px] p-card-padding\">\n <div className=\"text-center\">\n <AlertCircle className=\"w-12 h-12 text-state-error mx-auto mb-spacing-md\" />\n <p className=\"text-state-error text-body-sm font-medium mb-spacing-sm\">Failed to load DataSink</p>\n <p className=\"text-text-tertiary text-body-xs mb-spacing-lg\">{error.message}</p>\n <Button onClick={handleBack} variant=\"ghost\" size=\"sm\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n Go back\n </Button>\n </div>\n </div>\n );\n }\n\n // Not found state\n if (!dataSink) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px] p-card-padding\">\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"DataSink not found\"\n description=\"The DataSink you're looking for doesn't exist or has been deleted.\"\n action={\n <Button onClick={handleBack} variant=\"default\" size=\"default\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n Go back to DataSinks\n </Button>\n }\n />\n </div>\n );\n }\n\n return (\n <div className=\"p-card-padding space-y-spacing-lg\">\n {/* Header */}\n <div className=\"flex flex-col sm:flex-row sm:items-start sm:justify-between gap-spacing-md\">\n <div className=\"flex-1\">\n <Button onClick={handleBack} variant=\"ghost\" size=\"sm\" className=\"mb-spacing-md\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n Back to DataSinks\n </Button>\n <div className=\"flex items-center gap-spacing-sm flex-wrap\">\n <h1 className=\"text-heading-h1 font-bold text-text-primary\">{dataSink.name || 'Untitled'}</h1>\n <DataSinkStatusBadge status={dataSink.status} />\n </div>\n <p className=\"text-body-sm text-text-tertiary font-mono mt-spacing-xs\">{dataSink.key}</p>\n {dataSink.description && (\n <p className=\"text-body-sm text-text-secondary mt-spacing-sm\">{dataSink.description}</p>\n )}\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center gap-spacing-sm flex-wrap\">\n <Button onClick={handleRefresh} disabled={isRefreshing} variant=\"secondary\" size=\"default\">\n <RefreshCw className={`w-4 h-4 mr-2 ${isRefreshing ? 'animate-spin' : ''}`} />\n {isRefreshing ? 'Refreshing...' : 'Refresh'}\n </Button>\n <Button onClick={handleExport} variant=\"secondary\" size=\"default\">\n <Download className=\"w-4 h-4 mr-2\" />\n Export\n </Button>\n <Button onClick={handleEdit} variant=\"secondary\" size=\"default\">\n <Edit className=\"w-4 h-4 mr-2\" />\n Edit\n </Button>\n <Button onClick={handleDelete} disabled={isDeleting} variant=\"destructive\" size=\"default\">\n <Trash2 className=\"w-4 h-4 mr-2\" />\n {isDeleting ? 'Deleting...' : 'Delete'}\n </Button>\n </div>\n </div>\n\n <PagePurpose>\n A data sink is a structured store that holds your processed data and serves it to dashboards. From here you can\n inspect its schema and stats, preview the cached rows, refresh it from its linked workflow, or export it.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"bigconsole-datasink-view\"\n steps={[\n {\n id: 'preview',\n label: 'Preview the data',\n description: 'Open the cached rows to confirm the sink holds what you expect.',\n onClick: handleShowData,\n },\n {\n id: 'refresh',\n label: 'Refresh from source',\n description: 'Re-run the linked workflow to pull the latest data.',\n onClick: handleRefresh,\n },\n {\n id: 'build-dashboard',\n label: 'Visualize it on a dashboard',\n description: 'Add widgets that query this sink to see your data live.',\n onClick: () => navigate('/dashboards'),\n },\n {\n id: 'export',\n label: 'Export the data',\n description: 'Download the contents for use elsewhere.',\n onClick: handleExport,\n },\n ]}\n />\n\n {/* Details Grid */}\n <div className=\"grid gap-spacing-lg md:grid-cols-2\">\n {/* Info Panel — primary emphasis zone */}\n <GlassCard treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle>Details</CardTitle>\n </CardHeader>\n <CardContent>\n <dl className=\"space-y-spacing-md text-body-sm\">\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Status</dt>\n <dd>\n <DataSinkStatusBadge status={dataSink.status} />\n </dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Cache TTL</dt>\n <dd className=\"text-text-primary font-medium\">{dataSink.ttl ? `${dataSink.ttl}s` : 'None'}</dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Refresh Type</dt>\n <dd className=\"text-text-primary font-medium capitalize\">{dataSink.refresh?.type || 'Manual'}</dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Size</dt>\n <dd className=\"text-text-primary font-medium\">\n {dataSink.sizeBytes ? `${(dataSink.sizeBytes / 1024).toFixed(2)} KB` : '0 KB'}\n </dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Version</dt>\n <dd className=\"text-text-primary font-medium\">{dataSink.version || 1}</dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Last Refreshed</dt>\n <dd className=\"text-text-primary font-medium\">\n {dataSink.lastRefreshedAt\n ? formatDistanceToNow(new Date(dataSink.lastRefreshedAt), { addSuffix: true })\n : 'Never'}\n </dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Created</dt>\n <dd className=\"text-text-primary font-medium\">\n {formatDistanceToNow(new Date(dataSink.createdAt), { addSuffix: true })}\n </dd>\n </div>\n </dl>\n </CardContent>\n </GlassCard>\n\n {/* Workflow Status Panel */}\n {dataSink.fluidGridsWorkflowId && (\n <WorkflowStatusPanel\n workflowId={dataSink.fluidGridsWorkflowId}\n executionId={dataSink.fluidGridsWorkflowExecutionId || undefined}\n lastRefreshedAt={dataSink.lastRefreshedAt || undefined}\n setupState={dataSink.setupState}\n status={dataSink.status}\n onRerunWorkflow={handleRefresh}\n disabled={isRefreshing}\n isRerunning={isRefreshing}\n />\n )}\n\n {/* Linked Workflows */}\n <LinkedWorkflowsPanel workflowLinks={dataSink.workflowLinks} />\n\n {/* Linked Parsers */}\n <LinkedParsersPanel dataSinkKey={dataSink.key} />\n </div>\n\n {/* Data Preview Section */}\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0\">\n <CardTitle className=\"flex items-center gap-spacing-sm\">\n <Database className=\"w-4 h-4 text-text-secondary\" />\n Data Preview\n </CardTitle>\n <div className=\"flex items-center gap-2\">\n {showData && (\n <div className=\"flex items-center border border-border-default rounded-md overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setDataViewMode('table')}\n className={`p-1.5 ${dataViewMode === 'table' ? 'bg-bg-sunken text-text-primary' : 'text-text-secondary hover:text-text-primary'}`}\n title=\"Table view\"\n >\n <Grid3X3 className=\"w-4 h-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setDataViewMode('json')}\n className={`p-1.5 ${dataViewMode === 'json' ? 'bg-bg-sunken text-text-primary' : 'text-text-secondary hover:text-text-primary'}`}\n title=\"JSON view\"\n >\n <Code className=\"w-4 h-4\" />\n </button>\n </div>\n )}\n <Button\n onClick={handleShowData}\n disabled={dataLoading}\n variant={showData ? 'secondary' : 'default'}\n size=\"sm\"\n >\n {dataLoading ? (\n <>\n <Loader2 className=\"w-4 h-4 mr-2 animate-spin\" />\n Loading...\n </>\n ) : showData ? (\n <>\n <EyeOff className=\"w-4 h-4 mr-2\" />\n Hide Data\n </>\n ) : (\n <>\n <Eye className=\"w-4 h-4 mr-2\" />\n Show Data\n </>\n )}\n </Button>\n </div>\n </CardHeader>\n\n {showData && dataPreview && (\n <CardContent>\n {dataViewMode === 'table' ? (\n <DataSinkTableViewer data={dataPreview} maxHeight=\"400px\" />\n ) : (\n <DataSinkDataViewer data={dataPreview} maxHeight=\"400px\" />\n )}\n {/* v3.0: pagination controls — shown only for array payloads. */}\n {dataTotalCount !== null && (\n <div className=\"flex items-center justify-between gap-spacing-md mt-spacing-md pt-spacing-md border-t border-border-subtle\">\n <div className=\"flex items-center gap-spacing-sm text-body-sm text-text-secondary\">\n <span>Rows per page</span>\n <select\n aria-label=\"Rows per page\"\n className=\"bg-bg-canvas border border-border-default rounded px-spacing-sm py-spacing-2xs text-text-primary\"\n value={pageSize}\n onChange={(e) => handlePageSizeChange(Number(e.target.value))}\n >\n {[100, 500, 1000].map((n) => (\n <option key={n} value={n}>\n {n}\n </option>\n ))}\n </select>\n </div>\n <div className=\"flex items-center gap-spacing-md text-body-sm text-text-secondary\">\n <span>\n {dataTotalCount === 0\n ? '0 rows'\n : `${pageOffset + 1}–${Math.min(pageOffset + pageSize, dataTotalCount)} of ${dataTotalCount}`}\n </span>\n <Button\n variant=\"secondary\"\n size=\"sm\"\n disabled={pageOffset === 0 || dataLoading}\n onClick={() => void loadDataPage(Math.max(0, pageOffset - pageSize), pageSize)}\n >\n Previous\n </Button>\n <Button\n variant=\"secondary\"\n size=\"sm\"\n disabled={!dataHasMore || dataLoading}\n onClick={() => void loadDataPage(pageOffset + pageSize, pageSize)}\n >\n Next\n </Button>\n </div>\n </div>\n )}\n </CardContent>\n )}\n\n {!showData && (\n <CardContent className=\"text-center p-spacing-xl\">\n <Database className=\"w-10 h-10 text-text-tertiary mx-auto mb-spacing-md\" />\n <p className=\"text-body-sm text-text-secondary\">Click "Show Data" to preview the cached data.</p>\n </CardContent>\n )}\n </Card>\n\n {/* Export DataSink Dialog */}\n <ExportDataSinkDialog\n isOpen={isExportDialogOpen}\n dataSinkId={dataSinkId || null}\n dataSinkName={dataSink.name || dataSink.key}\n onClose={handleExportClose}\n />\n </div>\n );\n});\n\nexport default DataSinkViewPage;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WidgetDemoPage.js","names":[],"sources":["../../../src/bigconsole/pages/WidgetDemoPage.tsx"],"sourcesContent":["/**\n * WidgetDemoPage\n *\n * Demonstrates all 18 widget types.\n * Widgets show empty states when no real data is available.\n * Connect a DataSink + Parser pipeline for real data processing.\n */\n\nimport { type FC, useState, useMemo } from 'react';\nimport { IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport type { Widget } from '../types';\nimport { WidgetWrapper } from '../components/widgets';\n\n// Widget type string literals\ntype WidgetType =\n | 'metric_card'\n | 'kpi_card_comparison'\n | 'chart'\n | 'funnel_chart'\n | 'table'\n | 'pivot_table'\n | 'gauge'\n | 'progress'\n | 'list'\n | 'form'\n | 'text'\n | 'iframe'\n | 'map'\n | 'heatmap'\n | 'calendar'\n | 'kanban'\n | 'timeline'\n | 'custom';\n\n// ============================================================================\n// Widget Types for Demo\n// ============================================================================\n\nconst WIDGET_TYPES: { type: WidgetType; title: string; description: string }[] = [\n { type: 'metric_card', title: 'Metric Card', description: 'Single metric with trend and sparkline' },\n { type: 'kpi_card_comparison', title: 'KPI Card Comparison', description: 'Multiple KPIs with comparisons' },\n { type: 'chart', title: 'Chart (Line/Bar/Area)', description: 'Time-series data visualization' },\n { type: 'funnel_chart', title: 'Funnel Chart', description: 'Conversion funnel with stages' },\n { type: 'table', title: 'Table', description: 'Data table with sort/filter/pagination' },\n { type: 'pivot_table', title: 'Pivot Table', description: 'Multi-dimensional data analysis' },\n { type: 'gauge', title: 'Gauge', description: 'Circular/linear gauge with thresholds' },\n { type: 'progress', title: 'Progress', description: 'Progress bar with milestones' },\n { type: 'list', title: 'List', description: 'Scrollable list with items' },\n { type: 'form', title: 'Form (Adaptive Card)', description: 'Interactive form with inputs' },\n { type: 'text', title: 'Text (Markdown)', description: 'Rich text with markdown support' },\n { type: 'iframe', title: 'iFrame', description: 'Embedded external content' },\n { type: 'map', title: 'Map', description: 'Geographic data with markers' },\n { type: 'heatmap', title: 'Heatmap', description: 'Grid visualization with color intensity' },\n { type: 'calendar', title: 'Calendar', description: 'Event calendar view' },\n { type: 'kanban', title: 'Kanban', description: 'Task board with columns' },\n { type: 'timeline', title: 'Timeline (Gantt)', description: 'Project timeline with tasks' },\n { type: 'custom', title: 'Custom', description: 'User-defined widget rendering' },\n];\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const WidgetDemoPage: FC = () => {\n const [filter, setFilter] = useState('');\n const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid');\n\n // Generate demo widgets from all types\n const demoWidgets = useMemo(() => {\n const filtered = filter\n ? WIDGET_TYPES.filter(\n (w) => w.type.includes(filter.toLowerCase()) || w.title.toLowerCase().includes(filter.toLowerCase())\n )\n : WIDGET_TYPES;\n\n return filtered.map((widgetDef, index): Widget => ({\n id: `demo-${widgetDef.type}`,\n pageId: 'demo-page',\n dashboardId: 'demo-dashboard',\n type: widgetDef.type,\n title: widgetDef.title,\n // No data source - widgets show empty state until connected to DataSink\n config: {},\n position: {\n x: (index % 3) * 4,\n y: Math.floor(index / 3) * 4,\n width: 4,\n height: 4,\n },\n positionX: (index % 3) * 4,\n positionY: Math.floor(index / 3) * 4,\n positionWidth: 4,\n positionHeight: 4,\n refreshInterval: undefined,\n lastRefreshedAt: undefined,\n metadata: { description: widgetDef.description },\n context: {},\n translations: [],\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n }));\n }, [filter]);\n\n return (\n <div className=\"h-full flex flex-col bg-bg-canvas\">\n {/* Header */}\n <div className=\"flex-shrink-0 border-b border-border-default bg-bg-surface px-6 py-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-xl font-semibold text-text-primary\">Widget Demo</h1>\n <p className=\"text-sm text-text-secondary mt-1\">All 18 widget types - connect a DataSink for real data</p>\n </div>\n <div className=\"flex items-center gap-4\">\n {/* Search Filter */}\n <div className=\"relative\">\n <input\n type=\"text\"\n placeholder=\"Filter widgets...\"\n value={filter}\n onChange={(e) => setFilter(e.target.value)}\n className=\"\n w-64 px-3 py-2 pl-[3.25rem]\n text-sm\n bg-bg-sunken\n border border-border-default\n rounded-lg\n text-text-primary\n placeholder:text-text-tertiary\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n <svg\n className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-text-secondary\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\"\n />\n </svg>\n </div>\n\n {/* View Toggle */}\n <div className=\"flex items-center bg-bg-sunken rounded-lg p-1\">\n <button\n type=\"button\"\n onClick={() => setViewMode('grid')}\n className={`\n px-3 py-1.5 text-sm font-medium rounded\n transition-colors\n ${\n viewMode === 'grid'\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-secondary hover:text-text-primary'\n }\n `}\n >\n Grid\n </button>\n <button\n type=\"button\"\n onClick={() => setViewMode('list')}\n className={`\n px-3 py-1.5 text-sm font-medium rounded\n transition-colors\n ${\n viewMode === 'list'\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-secondary hover:text-text-primary'\n }\n `}\n >\n List\n </button>\n </div>\n </div>\n </div>\n </div>\n\n {/* Widget Grid */}\n <div className=\"flex-1 overflow-auto p-6\">\n <PagePurpose className=\"mb-[var(--space-sectionGap)]\">\n This gallery previews every widget type BigConsole can render on a dashboard — metrics, charts, tables, maps,\n kanban boards and more. Use it to see what each widget looks like and pick the right one before wiring it to a\n real DataSink in the dashboard builder.\n </PagePurpose>\n\n <div\n className={\n viewMode === 'grid' ? 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6' : 'flex flex-col gap-4'\n }\n >\n {demoWidgets.map((widget) => {\n const widgetDef = WIDGET_TYPES.find((w) => w.type === widget.type);\n return (\n <div key={widget.id} className={viewMode === 'grid' ? 'h-80' : 'h-64'}>\n <div className=\"h-full flex flex-col\">\n {/* Widget Description */}\n <div className=\"flex-shrink-0 mb-2\">\n <span className=\"text-xs text-text-tertiary\">\n Type: <code className=\"font-mono text-action-primary-text\">{widget.type}</code>\n </span>\n {widgetDef && <span className=\"text-xs text-text-tertiary ml-2\">- {widgetDef.description}</span>}\n </div>\n {/* Widget */}\n <div className=\"flex-1 min-h-0\">\n <WidgetWrapper widget={widget} />\n </div>\n </div>\n </div>\n );\n })}\n </div>\n\n {/* Empty State */}\n {demoWidgets.length === 0 && (\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No widgets match your filter\"\n description=\"Try a different search term to preview a widget type.\"\n />\n )}\n </div>\n\n {/* Footer Stats */}\n <div className=\"flex-shrink-0 border-t border-border-default bg-bg-surface px-6 py-3\">\n <div className=\"flex items-center justify-between text-sm text-text-secondary\">\n <span>\n Showing {demoWidgets.length} of {WIDGET_TYPES.length} widget types\n </span>\n <span>Widgets show empty state until connected to DataSink + Parser</span>\n </div>\n </div>\n </div>\n );\n};\n\nexport default WidgetDemoPage;\n"],"mappings":";;;;;;AAsCA,IAAM,IAA2E;CAC/E;EAAE,MAAM;EAAe,OAAO;EAAe,aAAa;EAA0C;CACpG;EAAE,MAAM;EAAuB,OAAO;EAAuB,aAAa;EAAkC;CAC5G;EAAE,MAAM;EAAS,OAAO;EAAyB,aAAa;EAAkC;CAChG;EAAE,MAAM;EAAgB,OAAO;EAAgB,aAAa;EAAiC;CAC7F;EAAE,MAAM;EAAS,OAAO;EAAS,aAAa;EAA0C;CACxF;EAAE,MAAM;EAAe,OAAO;EAAe,aAAa;EAAmC;CAC7F;EAAE,MAAM;EAAS,OAAO;EAAS,aAAa;EAAyC;CACvF;EAAE,MAAM;EAAY,OAAO;EAAY,aAAa;EAAgC;CACpF;EAAE,MAAM;EAAQ,OAAO;EAAQ,aAAa;EAA8B;CAC1E;EAAE,MAAM;EAAQ,OAAO;EAAwB,aAAa;EAAgC;CAC5F;EAAE,MAAM;EAAQ,OAAO;EAAmB,aAAa;EAAmC;CAC1F;EAAE,MAAM;EAAU,OAAO;EAAU,aAAa;EAA6B;CAC7E;EAAE,MAAM;EAAO,OAAO;EAAO,aAAa;EAAgC;CAC1E;EAAE,MAAM;EAAW,OAAO;EAAW,aAAa;EAA2C;CAC7F;EAAE,MAAM;EAAY,OAAO;EAAY,aAAa;EAAuB;CAC3E;EAAE,MAAM;EAAU,OAAO;EAAU,aAAa;EAA2B;CAC3E;EAAE,MAAM;EAAY,OAAO;EAAoB,aAAa;EAA+B;CAC3F;EAAE,MAAM;EAAU,OAAO;EAAU,aAAa;EAAiC;CAClF,EAMY,UAA2B;CACtC,IAAM,CAAC,GAAQ,KAAa,EAAS,GAAG,EAClC,CAAC,GAAU,KAAe,EAA0B,OAAO,EAG3D,IAAc,SACD,IACb,EAAa,QACV,MAAM,EAAE,KAAK,SAAS,EAAO,aAAa,CAAC,IAAI,EAAE,MAAM,aAAa,CAAC,SAAS,EAAO,aAAa,CAAC,CACrG,GACD,GAEY,KAAK,GAAW,OAAmB;EACjD,IAAI,QAAQ,EAAU;EACtB,QAAQ;EACR,aAAa;EACb,MAAM,EAAU;EAChB,OAAO,EAAU;EAEjB,QAAQ,EAAE;EACV,UAAU;GACR,GAAI,IAAQ,IAAK;GACjB,GAAG,KAAK,MAAM,IAAQ,EAAE,GAAG;GAC3B,OAAO;GACP,QAAQ;GACT;EACD,WAAY,IAAQ,IAAK;EACzB,WAAW,KAAK,MAAM,IAAQ,EAAE,GAAG;EACnC,eAAe;EACf,gBAAgB;EAChB,iBAAiB,KAAA;EACjB,iBAAiB,KAAA;EACjB,UAAU,EAAE,aAAa,EAAU,aAAa;EAChD,SAAS,EAAE;EACX,cAAc,EAAE;EAChB,4BAAW,IAAI,MAAM,EAAC,aAAa;EACnC,4BAAW,IAAI,MAAM,EAAC,aAAa;EACpC,EAAE,EACF,CAAC,EAAO,CAAC;AAEZ,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;MAAI,WAAU;gBAA0C;MAAgB,CAAA,EACxE,kBAAC,KAAD;MAAG,WAAU;gBAAmC;MAA0D,CAAA,CACtG,EAAA,CAAA,EACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CAEE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,SAAD;QACE,MAAK;QACL,aAAY;QACZ,OAAO;QACP,WAAW,MAAM,EAAU,EAAE,OAAO,MAAM;QAC1C,WAAU;QAUV,CAAA,EACF,kBAAC,OAAD;QACE,WAAU;QACV,MAAK;QACL,QAAO;QACP,SAAQ;kBAER,kBAAC,QAAD;SACE,eAAc;SACd,gBAAe;SACf,aAAa;SACb,GAAE;SACF,CAAA;QACE,CAAA,CACF;UAGN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,UAAD;QACE,MAAK;QACL,eAAe,EAAY,OAAO;QAClC,WAAW;;;oBAIP,MAAa,SACT,8CACA,8CACL;;kBAEJ;QAEQ,CAAA,EACT,kBAAC,UAAD;QACE,MAAK;QACL,eAAe,EAAY,OAAO;QAClC,WAAW;;;oBAIP,MAAa,SACT,8CACA,8CACL;;kBAEJ;QAEQ,CAAA,CACL;SACF;QACF;;IACF,CAAA;GAGN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAa,WAAU;gBAA+B;MAIxC,CAAA;KAEd,kBAAC,OAAD;MACE,WACE,MAAa,SAAS,yDAAyD;gBAGhF,EAAY,KAAK,MAAW;OAC3B,IAAM,IAAY,EAAa,MAAM,MAAM,EAAE,SAAS,EAAO,KAAK;AAClE,cACE,kBAAC,OAAD;QAAqB,WAAW,MAAa,SAAS,SAAS;kBAC7D,kBAAC,OAAD;SAAK,WAAU;mBAAf,CAEE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD;WAAM,WAAU;qBAAhB,CAA6C,UACrC,kBAAC,QAAD;YAAM,WAAU;sBAAsC,EAAO;YAAY,CAAA,CAC1E;cACN,KAAa,kBAAC,QAAD;WAAM,WAAU;qBAAhB,CAAkD,MAAG,EAAU,YAAmB;aAC5F;aAEN,kBAAC,OAAD;UAAK,WAAU;oBACb,kBAAC,GAAD,EAAuB,WAAU,CAAA;UAC7B,CAAA,CACF;;QACF,EAdI,EAAO,GAcX;QAER;MACE,CAAA;KAGL,EAAY,WAAW,KACtB,kBAAC,GAAD;MACE,cAAa;MACb,OAAM;MACN,aAAY;MACZ,CAAA;KAEA;;GAGN,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,QAAD,EAAA,UAAA;MAAM;MACK,EAAY;MAAO;MAAK,EAAa;MAAO;MAChD,EAAA,CAAA,EACP,kBAAC,QAAD,EAAA,UAAM,iEAAoE,CAAA,CACtE;;IACF,CAAA;GACF"}
|
|
1
|
+
{"version":3,"file":"WidgetDemoPage.js","names":[],"sources":["../../../src/bigconsole/pages/WidgetDemoPage.tsx"],"sourcesContent":["/**\n * WidgetDemoPage\n *\n * Demonstrates all 18 widget types.\n * Widgets show empty states when no real data is available.\n * Connect a DataSink + Parser pipeline for real data processing.\n */\n\nimport { type FC, useState, useMemo } from 'react';\nimport { IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport type { Widget } from '../types';\nimport { WidgetWrapper } from '../components/widgets';\n\n// Widget type string literals\ntype WidgetType =\n | 'metric_card'\n | 'kpi_card_comparison'\n | 'chart'\n | 'funnel_chart'\n | 'table'\n | 'pivot_table'\n | 'gauge'\n | 'progress'\n | 'list'\n | 'form'\n | 'text'\n | 'iframe'\n | 'map'\n | 'heatmap'\n | 'calendar'\n | 'kanban'\n | 'timeline'\n | 'custom';\n\n// ============================================================================\n// Widget Types for Demo\n// ============================================================================\n\nconst WIDGET_TYPES: { type: WidgetType; title: string; description: string }[] = [\n { type: 'metric_card', title: 'Metric Card', description: 'Single metric with trend and sparkline' },\n { type: 'kpi_card_comparison', title: 'KPI Card Comparison', description: 'Multiple KPIs with comparisons' },\n { type: 'chart', title: 'Chart (Line/Bar/Area)', description: 'Time-series data visualization' },\n { type: 'funnel_chart', title: 'Funnel Chart', description: 'Conversion funnel with stages' },\n { type: 'table', title: 'Table', description: 'Data table with sort/filter/pagination' },\n { type: 'pivot_table', title: 'Pivot Table', description: 'Multi-dimensional data analysis' },\n { type: 'gauge', title: 'Gauge', description: 'Circular/linear gauge with thresholds' },\n { type: 'progress', title: 'Progress', description: 'Progress bar with milestones' },\n { type: 'list', title: 'List', description: 'Scrollable list with items' },\n { type: 'form', title: 'Form (Adaptive Card)', description: 'Interactive form with inputs' },\n { type: 'text', title: 'Text (Markdown)', description: 'Rich text with markdown support' },\n { type: 'iframe', title: 'iFrame', description: 'Embedded external content' },\n { type: 'map', title: 'Map', description: 'Geographic data with markers' },\n { type: 'heatmap', title: 'Heatmap', description: 'Grid visualization with color intensity' },\n { type: 'calendar', title: 'Calendar', description: 'Event calendar view' },\n { type: 'kanban', title: 'Kanban', description: 'Task board with columns' },\n { type: 'timeline', title: 'Timeline (Gantt)', description: 'Project timeline with tasks' },\n { type: 'custom', title: 'Custom', description: 'User-defined widget rendering' },\n];\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const WidgetDemoPage: FC = () => {\n const [filter, setFilter] = useState('');\n const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid');\n\n // Generate demo widgets from all types\n const demoWidgets = useMemo(() => {\n const filtered = filter\n ? WIDGET_TYPES.filter(\n (w) => w.type.includes(filter.toLowerCase()) || w.title.toLowerCase().includes(filter.toLowerCase())\n )\n : WIDGET_TYPES;\n\n return filtered.map(\n (widgetDef, index): Widget => ({\n id: `demo-${widgetDef.type}`,\n pageId: 'demo-page',\n dashboardId: 'demo-dashboard',\n type: widgetDef.type,\n title: widgetDef.title,\n // No data source - widgets show empty state until connected to DataSink\n config: {},\n position: {\n x: (index % 3) * 4,\n y: Math.floor(index / 3) * 4,\n width: 4,\n height: 4,\n },\n positionX: (index % 3) * 4,\n positionY: Math.floor(index / 3) * 4,\n positionWidth: 4,\n positionHeight: 4,\n refreshInterval: undefined,\n lastRefreshedAt: undefined,\n metadata: { description: widgetDef.description },\n context: {},\n translations: [],\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n })\n );\n }, [filter]);\n\n return (\n <div className=\"h-full flex flex-col bg-bg-canvas\">\n {/* Header */}\n <div className=\"flex-shrink-0 border-b border-border-default bg-bg-surface px-6 py-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-xl font-semibold text-text-primary\">Widget Demo</h1>\n <p className=\"text-sm text-text-secondary mt-1\">All 18 widget types - connect a DataSink for real data</p>\n </div>\n <div className=\"flex items-center gap-4\">\n {/* Search Filter */}\n <div className=\"relative\">\n <input\n type=\"text\"\n placeholder=\"Filter widgets...\"\n value={filter}\n onChange={(e) => setFilter(e.target.value)}\n className=\"\n w-64 px-3 py-2 pl-[3.25rem]\n text-sm\n bg-bg-sunken\n border border-border-default\n rounded-lg\n text-text-primary\n placeholder:text-text-tertiary\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n <svg\n className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-text-secondary\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\"\n />\n </svg>\n </div>\n\n {/* View Toggle */}\n <div className=\"flex items-center bg-bg-sunken rounded-lg p-1\">\n <button\n type=\"button\"\n onClick={() => setViewMode('grid')}\n className={`\n px-3 py-1.5 text-sm font-medium rounded\n transition-colors\n ${\n viewMode === 'grid'\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-secondary hover:text-text-primary'\n }\n `}\n >\n Grid\n </button>\n <button\n type=\"button\"\n onClick={() => setViewMode('list')}\n className={`\n px-3 py-1.5 text-sm font-medium rounded\n transition-colors\n ${\n viewMode === 'list'\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-secondary hover:text-text-primary'\n }\n `}\n >\n List\n </button>\n </div>\n </div>\n </div>\n </div>\n\n {/* Widget Grid */}\n <div className=\"flex-1 overflow-auto p-6\">\n <PagePurpose className=\"mb-[var(--space-sectionGap)]\">\n This gallery previews every widget type BigConsole can render on a dashboard — metrics, charts, tables, maps,\n kanban boards and more. Use it to see what each widget looks like and pick the right one before wiring it to a\n real DataSink in the dashboard builder.\n </PagePurpose>\n\n <div\n className={\n viewMode === 'grid' ? 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6' : 'flex flex-col gap-4'\n }\n >\n {demoWidgets.map((widget) => {\n const widgetDef = WIDGET_TYPES.find((w) => w.type === widget.type);\n return (\n <div key={widget.id} className={viewMode === 'grid' ? 'h-80' : 'h-64'}>\n <div className=\"h-full flex flex-col\">\n {/* Widget Description */}\n <div className=\"flex-shrink-0 mb-2\">\n <span className=\"text-xs text-text-tertiary\">\n Type: <code className=\"font-mono text-action-primary-text\">{widget.type}</code>\n </span>\n {widgetDef && <span className=\"text-xs text-text-tertiary ml-2\">- {widgetDef.description}</span>}\n </div>\n {/* Widget */}\n <div className=\"flex-1 min-h-0\">\n <WidgetWrapper widget={widget} />\n </div>\n </div>\n </div>\n );\n })}\n </div>\n\n {/* Empty State */}\n {demoWidgets.length === 0 && (\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No widgets match your filter\"\n description=\"Try a different search term to preview a widget type.\"\n />\n )}\n </div>\n\n {/* Footer Stats */}\n <div className=\"flex-shrink-0 border-t border-border-default bg-bg-surface px-6 py-3\">\n <div className=\"flex items-center justify-between text-sm text-text-secondary\">\n <span>\n Showing {demoWidgets.length} of {WIDGET_TYPES.length} widget types\n </span>\n <span>Widgets show empty state until connected to DataSink + Parser</span>\n </div>\n </div>\n </div>\n );\n};\n\nexport default WidgetDemoPage;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widgetTypeMapping.js","names":[],"sources":["../../../src/bigconsole/utils/widgetTypeMapping.ts"],"sourcesContent":["/**\n * Widget Type Mapping Utilities\n *\n * Maps internal UI widget types (snake_case) to federation-accessible GraphQL enum values (UPPER_CASE).\n * The supergraph only exposes certain WidgetType values - other values are marked @inaccessible.\n *\n * Federation-accessible values: AREA_CHART, BAR_CHART, FUNNEL, HEATMAP, KPI, LINE_CHART, PIE_CHART, RETENTION, TABLE\n */\n\nimport type { WidgetType as InternalWidgetType } from '../types';\n\n// Federation-accessible WidgetType enum values\nexport type FederationWidgetType =\n 'AREA_CHART'
|
|
1
|
+
{"version":3,"file":"widgetTypeMapping.js","names":[],"sources":["../../../src/bigconsole/utils/widgetTypeMapping.ts"],"sourcesContent":["/**\n * Widget Type Mapping Utilities\n *\n * Maps internal UI widget types (snake_case) to federation-accessible GraphQL enum values (UPPER_CASE).\n * The supergraph only exposes certain WidgetType values - other values are marked @inaccessible.\n *\n * Federation-accessible values: AREA_CHART, BAR_CHART, FUNNEL, HEATMAP, KPI, LINE_CHART, PIE_CHART, RETENTION, TABLE\n */\n\nimport type { WidgetType as InternalWidgetType } from '../types';\n\n// Federation-accessible WidgetType enum values\nexport type FederationWidgetType =\n | 'AREA_CHART'\n | 'BAR_CHART'\n | 'FUNNEL'\n | 'HEATMAP'\n | 'KPI'\n | 'LINE_CHART'\n | 'PIE_CHART'\n | 'RETENTION'\n | 'TABLE';\n\n/**\n * Maps internal UI widget types to federation-accessible GraphQL enum values.\n *\n * This mapping is necessary because:\n * 1. The UI uses snake_case widget types (e.g., 'kpi_card_comparison', 'metric_card')\n * 2. The BigConsole GraphQL schema defines many widget types\n * 3. But only some are exposed via federation (@inaccessible hides the rest)\n * 4. When creating/updating widgets through the gateway, we must use accessible values\n */\nexport function mapToFederationWidgetType(internalType: InternalWidgetType): FederationWidgetType {\n const mapping: Record<InternalWidgetType, FederationWidgetType> = {\n // KPI/Metric types -> KPI\n kpi_card_comparison: 'KPI',\n metric_card: 'KPI',\n\n // Chart types -> appropriate chart enum\n chart: 'LINE_CHART',\n funnel_chart: 'FUNNEL',\n\n // Direct mappings (already federation-accessible when uppercase)\n table: 'TABLE',\n pivot_table: 'TABLE',\n\n // Gauge and progress -> KPI (closest match)\n gauge: 'KPI',\n progress: 'KPI',\n\n // List -> TABLE\n list: 'TABLE',\n\n // Form -> TABLE (data display fallback)\n form: 'TABLE',\n\n // Text/iframe -> KPI (content display fallback)\n text: 'KPI',\n iframe: 'KPI',\n\n // Spatial/temporal types\n map: 'HEATMAP',\n heatmap: 'HEATMAP',\n calendar: 'TABLE',\n kanban: 'TABLE',\n timeline: 'TABLE',\n\n // Retention / cohort grid (federation-accessible)\n retention: 'RETENTION',\n\n // Custom -> KPI (generic fallback)\n custom: 'KPI',\n };\n\n return mapping[internalType] || 'KPI';\n}\n\n/**\n * Maps federation GraphQL enum values back to internal UI widget types.\n * Used when receiving data from the API.\n *\n * Note: This is a best-effort reverse mapping since multiple internal types\n * may map to the same federation type. The actual internal type should be\n * stored in widget metadata/config if precise type preservation is needed.\n */\nexport function mapFromFederationWidgetType(federationType: string): InternalWidgetType {\n // Normalize to uppercase for comparison\n const normalizedType = federationType.toUpperCase();\n\n const reverseMapping: Record<string, InternalWidgetType> = {\n KPI: 'kpi_card_comparison',\n LINE_CHART: 'chart',\n BAR_CHART: 'chart',\n AREA_CHART: 'chart',\n PIE_CHART: 'chart',\n TABLE: 'table',\n FUNNEL: 'funnel_chart',\n HEATMAP: 'heatmap',\n RETENTION: 'table',\n };\n\n return reverseMapping[normalizedType] || 'metric_card';\n}\n\n/**\n * Checks if a widget type is directly accessible via federation.\n * If true, it can be used as-is in GraphQL mutations through the gateway.\n */\nexport function isFederationAccessible(type: string): boolean {\n const accessibleTypes = new Set([\n 'AREA_CHART',\n 'BAR_CHART',\n 'FUNNEL',\n 'HEATMAP',\n 'KPI',\n 'LINE_CHART',\n 'PIE_CHART',\n 'RETENTION',\n 'TABLE',\n ]);\n\n return accessibleTypes.has(type.toUpperCase());\n}\n\n/**\n * Normalizes a widget type for API calls.\n * If the type is already federation-accessible, returns it uppercase.\n * Otherwise, maps it to the closest federation-accessible type.\n */\nexport function normalizeWidgetTypeForApi(type: string): FederationWidgetType {\n // Check if already a federation type (case-insensitive)\n if (isFederationAccessible(type)) {\n return type.toUpperCase() as FederationWidgetType;\n }\n\n // Otherwise, map from internal type\n return mapToFederationWidgetType(type as InternalWidgetType);\n}\n"],"mappings":";AAgCA,SAAgB,EAA0B,GAAwD;AA0ChG,QAzCkE;EAEhE,qBAAqB;EACrB,aAAa;EAGb,OAAO;EACP,cAAc;EAGd,OAAO;EACP,aAAa;EAGb,OAAO;EACP,UAAU;EAGV,MAAM;EAGN,MAAM;EAGN,MAAM;EACN,QAAQ;EAGR,KAAK;EACL,SAAS;EACT,UAAU;EACV,QAAQ;EACR,UAAU;EAGV,WAAW;EAGX,QAAQ;EACT,CAEc,MAAiB;;AAWlC,SAAgB,EAA4B,GAA4C;AAgBtF,QAZ2D;EACzD,KAAK;EACL,YAAY;EACZ,WAAW;EACX,YAAY;EACZ,WAAW;EACX,OAAO;EACP,QAAQ;EACR,SAAS;EACT,WAAW;EACZ,CAZsB,EAAe,aAAa,KAcV;;AAO3C,SAAgB,EAAuB,GAAuB;AAa5D,QAZwB,IAAI,IAAI;EAC9B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,CAEqB,IAAI,EAAK,aAAa,CAAC;;AAQhD,SAAgB,EAA0B,GAAoC;AAO5E,QALI,EAAuB,EAAK,GACvB,EAAK,aAAa,GAIpB,EAA0B,EAA2B"}
|
|
@@ -1433,18 +1433,25 @@ ${f}`, Be = e`
|
|
|
1433
1433
|
}
|
|
1434
1434
|
}
|
|
1435
1435
|
${p}`, Ye = e`
|
|
1436
|
-
query GetDataSinkData($id: ID, $key: String, $dataPath: String, $forceRefresh: Boolean) {
|
|
1436
|
+
query GetDataSinkData($id: ID, $key: String, $dataPath: String, $forceRefresh: Boolean, $limit: Int, $offset: Int, $filter: JSON) {
|
|
1437
1437
|
getDataSinkData(
|
|
1438
1438
|
id: $id
|
|
1439
1439
|
key: $key
|
|
1440
1440
|
dataPath: $dataPath
|
|
1441
1441
|
forceRefresh: $forceRefresh
|
|
1442
|
+
limit: $limit
|
|
1443
|
+
offset: $offset
|
|
1444
|
+
filter: $filter
|
|
1442
1445
|
) {
|
|
1443
1446
|
raw
|
|
1444
1447
|
extracted
|
|
1445
1448
|
cached
|
|
1446
1449
|
version
|
|
1447
1450
|
fetchedAt
|
|
1451
|
+
totalCount
|
|
1452
|
+
limit
|
|
1453
|
+
offset
|
|
1454
|
+
hasMore
|
|
1448
1455
|
}
|
|
1449
1456
|
}
|
|
1450
1457
|
`, Xe = e`
|