@burdenoff/microfe-bigconsole 2026.924.1 → 2026.924.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bigconsole/BigConsoleRoutes.js +137 -138
- package/dist/bigconsole/BigConsoleRoutes.js.map +1 -1
- package/dist/bigconsole/assistant/previewController.js +10 -10
- package/dist/bigconsole/assistant/useAssistantPanelShowsPreview.js +25 -0
- package/dist/bigconsole/assistant/useAssistantPanelShowsPreview.js.map +1 -0
- package/dist/bigconsole/components/DrilldownDashboardRenderer.js +17 -17
- package/dist/bigconsole/components/builder/inspector/DataBindingSection.js +32 -32
- package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js +52 -52
- package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/DashboardCanvas.js +7 -7
- package/dist/bigconsole/components/dashboard/DashboardStatusPill.js +53 -0
- package/dist/bigconsole/components/dashboard/DashboardStatusPill.js.map +1 -0
- package/dist/bigconsole/components/dashboard/DashboardToolbar.js +60 -60
- package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js +21 -21
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterChip.js +30 -30
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js +36 -36
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js +34 -34
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js +38 -38
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js.map +1 -1
- package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js +121 -121
- package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/PublishToStoreDialog.js +22 -22
- package/dist/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.js +46 -46
- package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js +53 -53
- package/dist/bigconsole/components/dashboard/TemplatePicker/TemplatePicker.js +1 -1
- package/dist/bigconsole/components/dashboard/WidgetPalette.js +47 -47
- package/dist/bigconsole/components/dashboard/index.js +1 -0
- package/dist/bigconsole/components/datasink/CacheTTLSelector.js +35 -35
- package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js +18 -18
- package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js +20 -20
- package/dist/bigconsole/components/datasink/DataSinkStatusBadge.js +30 -29
- package/dist/bigconsole/components/datasink/DataSinkStatusBadge.js.map +1 -1
- package/dist/bigconsole/components/datasink/ImportDataGuideDialog.js +48 -48
- package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js +103 -103
- package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js.map +1 -1
- package/dist/bigconsole/components/datasink/RefreshTypeSelector.js +35 -35
- package/dist/bigconsole/components/overview/DashboardGuide.js +214 -0
- package/dist/bigconsole/components/overview/DashboardGuide.js.map +1 -0
- package/dist/bigconsole/components/overview/DataHealthCard.js +97 -0
- package/dist/bigconsole/components/overview/DataHealthCard.js.map +1 -0
- package/dist/bigconsole/components/overview/OverviewQuickActions.js +32 -0
- package/dist/bigconsole/components/overview/OverviewQuickActions.js.map +1 -0
- package/dist/bigconsole/components/overview/OverviewStatCard.js +57 -0
- package/dist/bigconsole/components/overview/OverviewStatCard.js.map +1 -0
- package/dist/bigconsole/components/overview/RecentDashboardsPanel.js +107 -0
- package/dist/bigconsole/components/overview/RecentDashboardsPanel.js.map +1 -0
- package/dist/bigconsole/components/overview/dashboardGuideSteps.js +119 -0
- package/dist/bigconsole/components/overview/dashboardGuideSteps.js.map +1 -0
- package/dist/bigconsole/components/overview/index.js +8 -0
- package/dist/bigconsole/components/overview/overviewModel.js +119 -0
- package/dist/bigconsole/components/overview/overviewModel.js.map +1 -0
- package/dist/bigconsole/components/overview/useOverviewData.js +48 -0
- package/dist/bigconsole/components/overview/useOverviewData.js.map +1 -0
- package/dist/bigconsole/components/parser/DataSinkSelector.js +40 -40
- package/dist/bigconsole/components/parser/ImportParserDialog.js +127 -127
- package/dist/bigconsole/components/parser/ImportParserDialog.js.map +1 -1
- package/dist/bigconsole/components/parser/ParserSelector.js +51 -51
- package/dist/bigconsole/components/preview/AiPreviewContent.js +5 -5
- package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js +62 -61
- package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js.map +1 -1
- package/dist/bigconsole/components/preview/AiPreviewPanel.js +82 -81
- package/dist/bigconsole/components/preview/AiPreviewPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/ActionConfigDialog.js +13 -13
- package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js +70 -70
- package/dist/bigconsole/components/widgets/PropertiesPanel.js +28 -28
- package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js +25 -25
- package/dist/bigconsole/components/widgets/chart/ChartConfig.js +48 -48
- package/dist/bigconsole/components/widgets/comments/WidgetComments.js +46 -46
- package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js +61 -61
- package/dist/bigconsole/components/widgets/form/FormWidget.js +36 -36
- package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js +42 -42
- package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js +25 -25
- package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +21 -21
- package/dist/bigconsole/components/widgets/list/ListConfig.js +30 -30
- package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js +38 -38
- package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js +9 -9
- package/dist/bigconsole/components/widgets/metric-card/TrendIndicator.js +9 -9
- package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js +49 -49
- package/dist/bigconsole/components/widgets/progress/ProgressConfig.js +39 -39
- package/dist/bigconsole/components/widgets/table/TableConfig.js +73 -73
- package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js +64 -64
- package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js +10 -10
- package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js +68 -68
- package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js.map +1 -1
- package/dist/bigconsole/pages/AdminPage.js +136 -136
- package/dist/bigconsole/pages/DashboardBuilderPage.js +10 -10
- package/dist/bigconsole/pages/DashboardViewPage.js +61 -61
- package/dist/bigconsole/pages/DashboardViewPage.js.map +1 -1
- package/dist/bigconsole/pages/DashboardsPage.js +327 -348
- package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
- package/dist/bigconsole/pages/DataParsersPage.js +5 -5
- package/dist/bigconsole/pages/DataSinkBuilderPage.js +10 -10
- package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkViewPage.js +83 -83
- package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinksPage.js +11 -11
- package/dist/bigconsole/pages/DataSourcesPage.js +5 -5
- package/dist/bigconsole/pages/InsightsPage.js +315 -315
- package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
- package/dist/bigconsole/pages/OverviewPage.js +244 -0
- package/dist/bigconsole/pages/OverviewPage.js.map +1 -0
- package/dist/bigconsole/pages/ParserBuilderPage.js +5 -5
- package/dist/bigconsole/pages/ParserViewPage.js +98 -98
- package/dist/bigconsole/pages/ParserViewPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelineBuilderPage.js +8 -8
- package/dist/bigconsole/pages/PipelineViewPage.js +46 -46
- package/dist/bigconsole/pages/PipelineViewPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelinesPage.js +80 -80
- package/dist/bigconsole/pages/PipelinesPage.js.map +1 -1
- package/dist/bigconsole/pages/SettingsPage.js +70 -70
- package/dist/bigconsole/pages/WidgetDemoPage.js +42 -42
- package/dist/bigconsole/pages/WorkflowViewPage.js +200 -200
- package/dist/bigconsole/pages/WorkflowViewPage.js.map +1 -1
- package/dist/bigconsole/pages/WorkflowsPage.js +78 -78
- package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
- package/dist/bigconsole/renderers/adapters/AdaptiveCardRenderer.js +34 -34
- package/dist/bigconsole/renderers/adapters/BlockKitRenderer.js +79 -79
- package/dist/bigconsole/renderers/adapters/CustomRenderer.js +46 -46
- package/dist/bigconsole/utils/createDialogParam.js +14 -0
- package/dist/bigconsole/utils/createDialogParam.js.map +1 -0
- package/dist/generated/global-operations.js +1 -1
- package/dist/generated/wspace-operations.js +285 -222
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/shared/hooks/useTr.js +10 -7
- package/dist/shared/hooks/useTr.js.map +1 -1
- package/package.json +1 -1
- package/dist/bigconsole/pages/HomePage.js +0 -318
- package/dist/bigconsole/pages/HomePage.js.map +0 -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';\nimport { useAppNavigate } from '../contexts';\nimport { newWorkflowPath } from '../BigConsoleRoutes';\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';\nimport { ImportDataGuideDialog } from '../components/datasink/ImportDataGuideDialog';\n\n// fe-libs UI components\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { IllustratedEmptyState, PagePurpose, NextSteps } from '@burdenoff/fe-libs/ui';\n\n// Section-emphasis primitives (BOFF-5632)\nimport { Section, SectionStack, SECTION_FOCUS_RING } from '../components/common';\n\n// RBAC\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { AccessDenied, PermissionButton } from '@burdenoff/fe-libs/shared/components';\nimport { BIGCONSOLE_PERMISSIONS } from '../../constants/permissions';\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 Upload,\n Grid3X3,\n Code,\n} from 'lucide-react';\n\n/**\n * The preview-format segmented control clips its children (`overflow-hidden`\n * preserves the group's rounded corners), which would swallow an offset focus\n * ring entirely — and `SECTION_FOCUS_RING` also suppresses the native outline,\n * so the buttons would have no visible focus at all. Painting the ring inside\n * the button keeps it visible without dropping the group's rounding.\n */\nconst SEGMENT_RING_FIX = 'focus-visible:ring-inset focus-visible:ring-offset-0' as const;\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 const { t } = useI18n();\n\n // RBAC — PermissionButton gates the action buttons directly; here we only need\n // the read gate that blocks the whole page.\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const canRead = hasPermission(BIGCONSOLE_PERMISSIONS.DATASINK_READ);\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 [isImportDialogOpen, setIsImportDialogOpen] = 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, updateDataSink, deleteDataSink } =\n 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: t('bigconsole.dataSinks.view.deleteConfirmTitle', 'Delete DataSink?'),\n message: t('bigconsole.dataSinks.view.deleteConfirmMessage', 'Are you sure you want to delete this DataSink?'),\n okButtonTitle: t('bigconsole.dataSinks.view.delete', 'Delete'),\n cancelButtonTitle: t('bigconsole.dataSinks.view.cancel', 'Cancel'),\n });\n const ok =\n native === null\n ? window.confirm(\n t('bigconsole.dataSinks.view.deleteConfirmMessage', 'Are you sure you want to delete this DataSink?')\n )\n : 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, t]);\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 // Handle import — opens a guide explaining that data is imported via a workflow.\n const handleImport = useCallback(() => {\n setIsImportDialogOpen(true);\n }, []);\n\n const handleImportClose = useCallback(() => {\n setIsImportDialogOpen(false);\n }, []);\n\n const handleGoToWorkflows = useCallback(() => {\n setIsImportDialogOpen(false);\n // Navigate straight to the builder path (basePath-aware via useAppNavigate).\n // Going via /workflows/new would hit a <Navigate> redirect to an absolute\n // path that drops the MFE base path — see WorkflowsPage for the same pattern.\n navigate(newWorkflowPath());\n }, [navigate]);\n\n // Direct CSV import — write the parsed rows straight to the sink (no workflow).\n const handleImportCsv = useCallback(\n async (rows: Record<string, unknown>[]): Promise<boolean> => {\n if (!dataSink) return false;\n // The DataSink `data` payload is a JSON scalar that accepts any JSON value;\n // tabular imports are stored as an array of row objects — the shape the\n // table viewer and parsers read. The generated input type narrows JSON to\n // Record<string, unknown>, so cast the row array to satisfy it.\n const updated = await updateDataSink({\n id: dataSink.id,\n version: dataSink.version,\n data: rows as unknown as Record<string, unknown>,\n });\n if (!updated) return false;\n // The import already succeeded. Revealing the data is best-effort — a\n // failure here must not turn a persisted import into a reported failure\n // (which would prompt a retry and hit a version conflict).\n try {\n await loadDataPage(0, pageSize);\n setShowData(true);\n } catch {\n // Data is saved; the user can open the preview manually.\n }\n return true;\n },\n [dataSink, updateDataSink, loadDataPage, pageSize]\n );\n\n // Loading state\n if (loading && !dataSink) {\n return (\n <div className=\"flex min-h-[240px] items-center justify-center p-card-padding\">\n <Loader2 className=\"h-icon-lg w-icon-lg animate-spin text-text-secondary\" />\n </div>\n );\n }\n\n // Error state\n // Only treat the shared hook error as fatal when the sink never loaded. Once\n // it is loaded, transient action errors (e.g. a failed CSV import) surface\n // inline in their own UI and must not replace the whole page.\n if (error && !dataSink) {\n return (\n <div className=\"p-card-padding\">\n <Section\n tone=\"danger\"\n headingLevel={2}\n title={t('bigconsole.dataSinks.view.loadError', 'Failed to load DataSink')}\n description={error.message}\n icon={<AlertCircle className=\"h-icon-sm w-icon-sm\" />}\n actions={\n <Button onClick={handleBack} variant=\"secondary\" size=\"sm\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.view.goBack', 'Go back')}\n </Button>\n }\n />\n </div>\n );\n }\n\n // Read gate — once permissions have loaded, block actors without read access.\n if (!permissionsLoading && !canRead) {\n return (\n <AccessDenied\n title={t('bigconsole.dataSinks.view.accessDeniedTitle', 'Access Denied')}\n description={t(\n 'bigconsole.dataSinks.view.accessDeniedDescription',\n \"You don't have permission to view this data sink.\"\n )}\n />\n );\n }\n\n // Not found state\n if (!dataSink) {\n return (\n <div className=\"flex min-h-[240px] items-center justify-center p-card-padding\">\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('bigconsole.dataSinks.view.notFoundTitle', 'DataSink not found')}\n description={t(\n 'bigconsole.dataSinks.view.notFoundDescription',\n \"The DataSink you're looking for doesn't exist or has been deleted.\"\n )}\n action={\n <Button onClick={handleBack} variant=\"default\" size=\"default\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.view.goBackToDataSinks', 'Go back to DataSinks')}\n </Button>\n }\n />\n </div>\n );\n }\n\n return (\n <div className=\"min-w-0 p-card-padding\">\n {/* Page header strip — structural only, no surface of its own. */}\n <header className=\"mb-section-gap flex flex-col gap-form-gap sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"min-w-0 flex-1\">\n <Button onClick={handleBack} variant=\"ghost\" size=\"sm\" className=\"mb-4\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.view.backToDataSinks', 'Back to DataSinks')}\n </Button>\n <div className=\"flex flex-wrap items-center gap-2\">\n <h1 className=\"text-2xl font-bold text-text-primary\">\n {dataSink.name || t('bigconsole.dataSinks.view.untitled', 'Untitled')}\n </h1>\n <DataSinkStatusBadge status={dataSink.status} />\n </div>\n <p className=\"mt-1 break-all font-mono text-sm text-text-muted\">{dataSink.key}</p>\n {dataSink.description && <p className=\"mt-2 text-sm text-text-secondary\">{dataSink.description}</p>}\n </div>\n\n {/* Actions. Refresh is the primary act on this route, so the destructive\n button is no longer the loudest thing under the title. */}\n <div className=\"flex flex-wrap items-center gap-2\">\n <PermissionButton permission={BIGCONSOLE_PERMISSIONS.DATASINK_EXECUTE} deniedBehavior=\"disable\">\n <Button onClick={handleRefresh} disabled={isRefreshing} variant=\"default\" size=\"default\">\n <RefreshCw className={`w-4 h-4 mr-2 ${isRefreshing ? 'animate-spin' : ''}`} />\n {isRefreshing\n ? t('bigconsole.dataSinks.view.refreshing', 'Refreshing...')\n : t('bigconsole.dataSinks.view.refresh', 'Refresh')}\n </Button>\n </PermissionButton>\n <Button onClick={handleImport} variant=\"secondary\" size=\"default\">\n <Upload className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.view.importData', 'Import Data')}\n </Button>\n <Button onClick={handleExport} variant=\"secondary\" size=\"default\">\n <Download className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.view.export', 'Export')}\n </Button>\n <PermissionButton permission={BIGCONSOLE_PERMISSIONS.DATASINK_UPDATE} deniedBehavior=\"disable\">\n <Button onClick={handleEdit} variant=\"secondary\" size=\"default\">\n <Edit className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.view.edit', 'Edit')}\n </Button>\n </PermissionButton>\n <PermissionButton permission={BIGCONSOLE_PERMISSIONS.DATASINK_DELETE} deniedBehavior=\"hide\">\n <Button onClick={handleDelete} disabled={isDeleting} variant=\"destructive\" size=\"default\">\n <Trash2 className=\"w-4 h-4 mr-2\" />\n {isDeleting\n ? t('bigconsole.dataSinks.view.deleting', 'Deleting...')\n : t('bigconsole.dataSinks.view.delete', 'Delete')}\n </Button>\n </PermissionButton>\n </div>\n </header>\n\n <PagePurpose className=\"mb-section-gap\">\n {t(\n 'bigconsole.dataSinks.view.pagePurpose',\n 'A data sink is a structured store that holds your processed data and serves it to dashboards. From here you can inspect its schema and stats, preview the cached rows, refresh it from its linked workflow, or export it.'\n )}\n </PagePurpose>\n\n <NextSteps\n storageKey=\"bigconsole-datasink-view\"\n steps={[\n {\n id: 'preview',\n label: t('bigconsole.dataSinks.view.nextSteps.previewLabel', 'Preview the data'),\n description: t(\n 'bigconsole.dataSinks.view.nextSteps.previewDescription',\n 'Open the cached rows to confirm the sink holds what you expect.'\n ),\n onClick: handleShowData,\n },\n {\n id: 'refresh',\n label: t('bigconsole.dataSinks.view.nextSteps.refreshLabel', 'Refresh from source'),\n description: t(\n 'bigconsole.dataSinks.view.nextSteps.refreshDescription',\n 'Re-run the linked workflow to pull the latest data.'\n ),\n onClick: handleRefresh,\n },\n {\n id: 'build-dashboard',\n label: t('bigconsole.dataSinks.view.nextSteps.dashboardLabel', 'Visualize it on a dashboard'),\n description: t(\n 'bigconsole.dataSinks.view.nextSteps.dashboardDescription',\n 'Add widgets that query this sink to see your data live.'\n ),\n onClick: () => navigate('/dashboards'),\n },\n {\n id: 'export',\n label: t('bigconsole.dataSinks.view.nextSteps.exportLabel', 'Export the data'),\n description: t(\n 'bigconsole.dataSinks.view.nextSteps.exportDescription',\n 'Download the contents for use elsewhere.'\n ),\n onClick: handleExport,\n },\n ]}\n />\n\n <SectionStack className=\"mt-section-gap\">\n {/* Supporting context: four peer panels, one container idiom. */}\n <div className=\"grid min-w-0 gap-section-gap md:grid-cols-2\">\n {/* Reference metadata. `standard`, matching the three sibling panels in\n this grid — one recessed cell beside three raised ones read as a\n rendering fault rather than as hierarchy. The `primary` preview\n below still carries the elevation that separates it from all four. */}\n <Section\n headingLevel={2}\n title={t('bigconsole.dataSinks.view.details', 'Details')}\n description=\"Cache, refresh and storage settings for this sink.\"\n >\n <dl className=\"divide-y divide-[var(--color-border-subtle)] text-sm\">\n <div className=\"flex flex-wrap items-center justify-between gap-x-form-gap gap-y-1 py-2 first:pt-0\">\n <dt className=\"min-w-0 text-text-secondary\">{t('bigconsole.dataSinks.view.status', 'Status')}</dt>\n <dd>\n <DataSinkStatusBadge status={dataSink.status} size=\"sm\" />\n </dd>\n </div>\n <div className=\"flex flex-wrap items-center justify-between gap-x-form-gap gap-y-1 py-2\">\n <dt className=\"min-w-0 text-text-secondary\">{t('bigconsole.dataSinks.view.cacheTtl', 'Cache TTL')}</dt>\n <dd className=\"font-medium text-text-primary\">\n {dataSink.ttl ? `${dataSink.ttl}s` : t('bigconsole.dataSinks.view.none', 'None')}\n </dd>\n </div>\n <div className=\"flex flex-wrap items-center justify-between gap-x-form-gap gap-y-1 py-2\">\n <dt className=\"min-w-0 text-text-secondary\">\n {t('bigconsole.dataSinks.view.refreshType', 'Refresh Type')}\n </dt>\n <dd className=\"font-medium capitalize text-text-primary\">\n {dataSink.refresh?.type || t('bigconsole.dataSinks.view.manual', 'Manual')}\n </dd>\n </div>\n <div className=\"flex flex-wrap items-center justify-between gap-x-form-gap gap-y-1 py-2\">\n <dt className=\"min-w-0 text-text-secondary\">{t('bigconsole.dataSinks.view.size', 'Size')}</dt>\n <dd className=\"font-medium text-text-primary\">\n {dataSink.sizeBytes ? `${(dataSink.sizeBytes / 1024).toFixed(2)} KB` : '0 KB'}\n </dd>\n </div>\n <div className=\"flex flex-wrap items-center justify-between gap-x-form-gap gap-y-1 py-2\">\n <dt className=\"min-w-0 text-text-secondary\">{t('bigconsole.dataSinks.view.version', 'Version')}</dt>\n <dd className=\"font-medium text-text-primary\">{dataSink.version || 1}</dd>\n </div>\n <div className=\"flex flex-wrap items-center justify-between gap-x-form-gap gap-y-1 py-2\">\n <dt className=\"min-w-0 text-text-secondary\">\n {t('bigconsole.dataSinks.view.lastRefreshed', 'Last Refreshed')}\n </dt>\n <dd className=\"font-medium text-text-primary\">\n {dataSink.lastRefreshedAt\n ? formatDistanceToNow(new Date(dataSink.lastRefreshedAt), { addSuffix: true })\n : t('bigconsole.dataSinks.view.never', 'Never')}\n </dd>\n </div>\n <div className=\"flex flex-wrap items-center justify-between gap-x-form-gap gap-y-1 py-2 last:pb-0\">\n <dt className=\"min-w-0 text-text-secondary\">{t('bigconsole.dataSinks.view.created', 'Created')}</dt>\n <dd className=\"font-medium text-text-primary\">\n {formatDistanceToNow(new Date(dataSink.createdAt), { addSuffix: true })}\n </dd>\n </div>\n </dl>\n </Section>\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 {/* The point of this route: the cached rows themselves. */}\n <Section\n emphasis=\"primary\"\n headingLevel={2}\n title={t('bigconsole.dataSinks.view.dataPreview', 'Data Preview')}\n description=\"The rows this sink is currently serving to dashboards.\"\n icon={<Database className=\"h-icon-sm w-icon-sm\" />}\n actions={\n <>\n {showData && (\n <div\n role=\"group\"\n aria-label={t('bigconsole.dataSinks.view.dataPreview', 'Data Preview')}\n className=\"flex items-center overflow-hidden rounded-button border border-[var(--color-border-default)]\"\n >\n <button\n type=\"button\"\n onClick={() => setDataViewMode('table')}\n aria-pressed={dataViewMode === 'table'}\n className={`flex h-control-md w-[var(--size-controlHeight-md)] items-center justify-center ${SECTION_FOCUS_RING} ${SEGMENT_RING_FIX} ${\n dataViewMode === 'table'\n ? 'bg-bg-sunken text-text-primary'\n : 'text-text-secondary hover:text-text-primary'\n }`}\n title={t('bigconsole.dataSinks.view.tableView', 'Table view')}\n >\n <Grid3X3 className=\"w-4 h-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setDataViewMode('json')}\n aria-pressed={dataViewMode === 'json'}\n className={`flex h-control-md w-[var(--size-controlHeight-md)] items-center justify-center ${SECTION_FOCUS_RING} ${SEGMENT_RING_FIX} ${\n dataViewMode === 'json'\n ? 'bg-bg-sunken text-text-primary'\n : 'text-text-secondary hover:text-text-primary'\n }`}\n title={t('bigconsole.dataSinks.view.jsonView', '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 {t('bigconsole.dataSinks.view.loading', 'Loading...')}\n </>\n ) : showData ? (\n <>\n <EyeOff className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.view.hideData', 'Hide Data')}\n </>\n ) : (\n <>\n <Eye className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.view.showData', 'Show Data')}\n </>\n )}\n </Button>\n </>\n }\n >\n {showData && dataPreview && (\n <>\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=\"mt-form-gap flex flex-wrap items-center justify-between gap-form-gap border-t border-[var(--color-border-subtle)] pt-form-gap\">\n <label className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <span>{t('bigconsole.dataSinks.view.rowsPerPage', 'Rows per page')}</span>\n <select\n aria-label={t('bigconsole.dataSinks.view.rowsPerPage', 'Rows per page')}\n className={`h-control-md rounded-input border border-[var(--color-border-default)] bg-bg-canvas px-2 text-text-primary ${SECTION_FOCUS_RING}`}\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 </label>\n <div className=\"flex flex-wrap items-center gap-control-gap text-sm text-text-secondary\">\n <span>\n {dataTotalCount === 0\n ? t('bigconsole.dataSinks.view.zeroRows', '0 rows')\n : t('bigconsole.dataSinks.view.rowRange', '{{start}}–{{end}} of {{total}}', {\n start: pageOffset + 1,\n end: Math.min(pageOffset + pageSize, dataTotalCount),\n total: dataTotalCount,\n })}\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 {t('bigconsole.dataSinks.view.previous', 'Previous')}\n </Button>\n <Button\n variant=\"secondary\"\n size=\"sm\"\n disabled={!dataHasMore || dataLoading}\n onClick={() => void loadDataPage(pageOffset + pageSize, pageSize)}\n >\n {t('bigconsole.dataSinks.view.next', 'Next')}\n </Button>\n </div>\n </div>\n )}\n </>\n )}\n\n {!showData &&\n (dataSink.data && Object.keys(dataSink.data).length > 0 ? (\n <p className=\"flex items-center gap-icon-gap text-sm text-text-secondary\">\n <Database aria-hidden=\"true\" className=\"h-icon-sm w-icon-sm shrink-0 text-text-muted\" />\n {t('bigconsole.dataSinks.view.showDataHint', 'Click \"Show Data\" to preview the cached data.')}\n </p>\n ) : (\n // No data yet — surface the Import Data flow so a new user knows the next step.\n <div className=\"flex flex-col items-center gap-form-gap py-form-gap text-center\">\n <Database aria-hidden=\"true\" className=\"h-icon-lg w-icon-lg text-text-muted\" />\n <p className=\"text-sm text-text-secondary\">\n {t(\n 'bigconsole.dataSinks.view.noDataYet',\n 'This data sink has no data yet. Upload a CSV or build a workflow to import data.'\n )}\n </p>\n <Button onClick={handleImport} variant=\"default\" size=\"sm\">\n <Upload className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.view.importData', 'Import Data')}\n </Button>\n </div>\n ))}\n </Section>\n </SectionStack>\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\n {/* Import Data guide Dialog */}\n <ImportDataGuideDialog\n isOpen={isImportDialogOpen}\n dataSinkName={dataSink.name || dataSink.key}\n hasExistingData={Boolean(dataSink.data && Object.keys(dataSink.data).length > 0)}\n onClose={handleImportClose}\n onGoToWorkflows={handleGoToWorkflows}\n onImportCsv={handleImportCsv}\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';\nimport { useAppNavigate } from '../contexts';\nimport { newWorkflowPath } from '../BigConsoleRoutes';\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';\nimport { ImportDataGuideDialog } from '../components/datasink/ImportDataGuideDialog';\n\n// fe-libs UI components\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { IllustratedEmptyState, PagePurpose, NextSteps } from '@burdenoff/fe-libs/ui';\n\n// Section-emphasis primitives (BOFF-5632)\nimport { Section, SectionStack, SECTION_FOCUS_RING } from '../components/common';\n\n// RBAC\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { AccessDenied, PermissionButton } from '@burdenoff/fe-libs/shared/components';\nimport { BIGCONSOLE_PERMISSIONS } from '../../constants/permissions';\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 Upload,\n Grid3X3,\n Code,\n} from 'lucide-react';\n\n/**\n * The preview-format segmented control clips its children (`overflow-hidden`\n * preserves the group's rounded corners), which would swallow an offset focus\n * ring entirely — and `SECTION_FOCUS_RING` also suppresses the native outline,\n * so the buttons would have no visible focus at all. Painting the ring inside\n * the button keeps it visible without dropping the group's rounding.\n */\nconst SEGMENT_RING_FIX = 'focus-visible:ring-inset focus-visible:ring-offset-0' as const;\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 const { t } = useI18n();\n\n // RBAC — PermissionButton gates the action buttons directly; here we only need\n // the read gate that blocks the whole page.\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const canRead = hasPermission(BIGCONSOLE_PERMISSIONS.DATASINK_READ);\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 [isImportDialogOpen, setIsImportDialogOpen] = 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, updateDataSink, deleteDataSink } =\n 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: t('bigconsole.dataSinks.view.deleteConfirmTitle', 'Delete DataSink?'),\n message: t('bigconsole.dataSinks.view.deleteConfirmMessage', 'Are you sure you want to delete this DataSink?'),\n okButtonTitle: t('bigconsole.dataSinks.view.delete', 'Delete'),\n cancelButtonTitle: t('bigconsole.dataSinks.view.cancel', 'Cancel'),\n });\n const ok =\n native === null\n ? window.confirm(\n t('bigconsole.dataSinks.view.deleteConfirmMessage', 'Are you sure you want to delete this DataSink?')\n )\n : 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, t]);\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 // Handle import — opens a guide explaining that data is imported via a workflow.\n const handleImport = useCallback(() => {\n setIsImportDialogOpen(true);\n }, []);\n\n const handleImportClose = useCallback(() => {\n setIsImportDialogOpen(false);\n }, []);\n\n const handleGoToWorkflows = useCallback(() => {\n setIsImportDialogOpen(false);\n // Navigate straight to the builder path (basePath-aware via useAppNavigate).\n // Going via /workflows/new would hit a <Navigate> redirect to an absolute\n // path that drops the MFE base path — see WorkflowsPage for the same pattern.\n navigate(newWorkflowPath());\n }, [navigate]);\n\n // Direct CSV import — write the parsed rows straight to the sink (no workflow).\n const handleImportCsv = useCallback(\n async (rows: Record<string, unknown>[]): Promise<boolean> => {\n if (!dataSink) return false;\n // The DataSink `data` payload is a JSON scalar that accepts any JSON value;\n // tabular imports are stored as an array of row objects — the shape the\n // table viewer and parsers read. The generated input type narrows JSON to\n // Record<string, unknown>, so cast the row array to satisfy it.\n const updated = await updateDataSink({\n id: dataSink.id,\n version: dataSink.version,\n data: rows as unknown as Record<string, unknown>,\n });\n if (!updated) return false;\n // The import already succeeded. Revealing the data is best-effort — a\n // failure here must not turn a persisted import into a reported failure\n // (which would prompt a retry and hit a version conflict).\n try {\n await loadDataPage(0, pageSize);\n setShowData(true);\n } catch {\n // Data is saved; the user can open the preview manually.\n }\n return true;\n },\n [dataSink, updateDataSink, loadDataPage, pageSize]\n );\n\n // Loading state\n if (loading && !dataSink) {\n return (\n <div className=\"flex min-h-[240px] items-center justify-center p-card-padding\">\n <Loader2 className=\"h-icon-lg w-icon-lg animate-spin text-text-secondary\" />\n </div>\n );\n }\n\n // Error state\n // Only treat the shared hook error as fatal when the sink never loaded. Once\n // it is loaded, transient action errors (e.g. a failed CSV import) surface\n // inline in their own UI and must not replace the whole page.\n if (error && !dataSink) {\n return (\n <div className=\"p-card-padding\">\n <Section\n tone=\"danger\"\n headingLevel={2}\n title={t('bigconsole.dataSinks.view.loadError', 'Failed to load DataSink')}\n description={error.message}\n icon={<AlertCircle className=\"h-icon-sm w-icon-sm\" />}\n actions={\n <Button onClick={handleBack} variant=\"secondary\" size=\"sm\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.view.goBack', 'Go back')}\n </Button>\n }\n />\n </div>\n );\n }\n\n // Read gate — once permissions have loaded, block actors without read access.\n if (!permissionsLoading && !canRead) {\n return (\n <AccessDenied\n title={t('bigconsole.dataSinks.view.accessDeniedTitle', 'Access Denied')}\n description={t(\n 'bigconsole.dataSinks.view.accessDeniedDescription',\n \"You don't have permission to view this data sink.\"\n )}\n />\n );\n }\n\n // Not found state\n if (!dataSink) {\n return (\n <div className=\"flex min-h-[240px] items-center justify-center p-card-padding\">\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('bigconsole.dataSinks.view.notFoundTitle', 'DataSink not found')}\n description={t(\n 'bigconsole.dataSinks.view.notFoundDescription',\n \"The DataSink you're looking for doesn't exist or has been deleted.\"\n )}\n action={\n <Button onClick={handleBack} variant=\"default\" size=\"default\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.view.goBackToDataSinks', 'Go back to DataSinks')}\n </Button>\n }\n />\n </div>\n );\n }\n\n return (\n <div className=\"min-w-0 p-card-padding\">\n {/* Page header strip — structural only, no surface of its own. */}\n <header className=\"mb-section-gap flex flex-col gap-form-gap sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"min-w-0 flex-1\">\n <Button onClick={handleBack} variant=\"ghost\" size=\"sm\" className=\"mb-4\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.view.backToDataSinks', 'Back to DataSinks')}\n </Button>\n <div className=\"flex flex-wrap items-center gap-2\">\n <h1 className=\"text-2xl font-bold text-text-primary\">\n {dataSink.name || t('bigconsole.dataSinks.view.untitled', 'Untitled')}\n </h1>\n <DataSinkStatusBadge status={dataSink.status} />\n </div>\n <p className=\"mt-1 break-all font-mono text-sm text-text-muted\">{dataSink.key}</p>\n {dataSink.description && <p className=\"mt-2 text-sm text-text-secondary\">{dataSink.description}</p>}\n </div>\n\n {/* Actions. Refresh is the primary act on this route, so the destructive\n button is no longer the loudest thing under the title. */}\n <div className=\"flex flex-wrap items-center gap-2\">\n <PermissionButton permission={BIGCONSOLE_PERMISSIONS.DATASINK_EXECUTE} deniedBehavior=\"disable\">\n <Button onClick={handleRefresh} disabled={isRefreshing} variant=\"default\" size=\"default\">\n <RefreshCw className={`w-4 h-4 mr-2 ${isRefreshing ? 'animate-spin' : ''}`} />\n {isRefreshing\n ? t('bigconsole.dataSinks.view.refreshing', 'Refreshing...')\n : t('bigconsole.dataSinks.view.refresh', 'Refresh')}\n </Button>\n </PermissionButton>\n <Button onClick={handleImport} variant=\"secondary\" size=\"default\">\n <Upload className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.view.importData', 'Import Data')}\n </Button>\n <Button onClick={handleExport} variant=\"secondary\" size=\"default\">\n <Download className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.view.export', 'Export')}\n </Button>\n <PermissionButton permission={BIGCONSOLE_PERMISSIONS.DATASINK_UPDATE} deniedBehavior=\"disable\">\n <Button onClick={handleEdit} variant=\"secondary\" size=\"default\">\n <Edit className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.view.edit', 'Edit')}\n </Button>\n </PermissionButton>\n <PermissionButton permission={BIGCONSOLE_PERMISSIONS.DATASINK_DELETE} deniedBehavior=\"hide\">\n <Button onClick={handleDelete} disabled={isDeleting} variant=\"destructive\" size=\"default\">\n <Trash2 className=\"w-4 h-4 mr-2\" />\n {isDeleting\n ? t('bigconsole.dataSinks.view.deleting', 'Deleting...')\n : t('bigconsole.dataSinks.view.delete', 'Delete')}\n </Button>\n </PermissionButton>\n </div>\n </header>\n\n <PagePurpose className=\"mb-section-gap\">\n {t(\n 'bigconsole.dataSinks.view.pagePurpose',\n 'A data sink is a structured store that holds your processed data and serves it to dashboards. From here you can inspect its schema and stats, preview the cached rows, refresh it from its linked workflow, or export it.'\n )}\n </PagePurpose>\n\n <NextSteps\n storageKey=\"bigconsole-datasink-view\"\n steps={[\n {\n id: 'preview',\n label: t('bigconsole.dataSinks.view.nextSteps.previewLabel', 'Preview the data'),\n description: t(\n 'bigconsole.dataSinks.view.nextSteps.previewDescription',\n 'Open the cached rows to confirm the sink holds what you expect.'\n ),\n onClick: handleShowData,\n },\n {\n id: 'refresh',\n label: t('bigconsole.dataSinks.view.nextSteps.refreshLabel', 'Refresh from source'),\n description: t(\n 'bigconsole.dataSinks.view.nextSteps.refreshDescription',\n 'Re-run the linked workflow to pull the latest data.'\n ),\n onClick: handleRefresh,\n },\n {\n id: 'build-dashboard',\n label: t('bigconsole.dataSinks.view.nextSteps.dashboardLabel', 'Visualize it on a dashboard'),\n description: t(\n 'bigconsole.dataSinks.view.nextSteps.dashboardDescription',\n 'Add widgets that query this sink to see your data live.'\n ),\n onClick: () => navigate('/dashboards'),\n },\n {\n id: 'export',\n label: t('bigconsole.dataSinks.view.nextSteps.exportLabel', 'Export the data'),\n description: t(\n 'bigconsole.dataSinks.view.nextSteps.exportDescription',\n 'Download the contents for use elsewhere.'\n ),\n onClick: handleExport,\n },\n ]}\n />\n\n <SectionStack className=\"mt-section-gap\">\n {/* Supporting context: four peer panels, one container idiom. */}\n <div className=\"grid min-w-0 gap-section-gap md:grid-cols-2\">\n {/* Reference metadata. `standard`, matching the three sibling panels in\n this grid — one recessed cell beside three raised ones read as a\n rendering fault rather than as hierarchy. The `primary` preview\n below still carries the elevation that separates it from all four. */}\n <Section\n headingLevel={2}\n title={t('bigconsole.dataSinks.view.details', 'Details')}\n description=\"Cache, refresh and storage settings for this sink.\"\n >\n <dl className=\"divide-y divide-[var(--color-border-subtle)] text-sm\">\n <div className=\"flex flex-wrap items-center justify-between gap-x-form-gap gap-y-1 py-2 first:pt-0\">\n <dt className=\"min-w-0 text-text-secondary\">{t('bigconsole.dataSinks.view.status', 'Status')}</dt>\n <dd>\n <DataSinkStatusBadge status={dataSink.status} size=\"sm\" />\n </dd>\n </div>\n <div className=\"flex flex-wrap items-center justify-between gap-x-form-gap gap-y-1 py-2\">\n <dt className=\"min-w-0 text-text-secondary\">{t('bigconsole.dataSinks.view.cacheTtl', 'Cache TTL')}</dt>\n <dd className=\"font-medium text-text-primary\">\n {dataSink.ttl ? `${dataSink.ttl}s` : t('bigconsole.dataSinks.view.none', 'None')}\n </dd>\n </div>\n <div className=\"flex flex-wrap items-center justify-between gap-x-form-gap gap-y-1 py-2\">\n <dt className=\"min-w-0 text-text-secondary\">\n {t('bigconsole.dataSinks.view.refreshType', 'Refresh Type')}\n </dt>\n <dd className=\"font-medium capitalize text-text-primary\">\n {dataSink.refresh?.type || t('bigconsole.dataSinks.view.manual', 'Manual')}\n </dd>\n </div>\n <div className=\"flex flex-wrap items-center justify-between gap-x-form-gap gap-y-1 py-2\">\n <dt className=\"min-w-0 text-text-secondary\">{t('bigconsole.dataSinks.view.size', 'Size')}</dt>\n <dd className=\"font-medium text-text-primary\">\n {dataSink.sizeBytes ? `${(dataSink.sizeBytes / 1024).toFixed(2)} KB` : '0 KB'}\n </dd>\n </div>\n <div className=\"flex flex-wrap items-center justify-between gap-x-form-gap gap-y-1 py-2\">\n <dt className=\"min-w-0 text-text-secondary\">{t('bigconsole.dataSinks.view.version', 'Version')}</dt>\n <dd className=\"font-medium text-text-primary\">{dataSink.version || 1}</dd>\n </div>\n <div className=\"flex flex-wrap items-center justify-between gap-x-form-gap gap-y-1 py-2\">\n <dt className=\"min-w-0 text-text-secondary\">\n {t('bigconsole.dataSinks.view.lastRefreshed', 'Last Refreshed')}\n </dt>\n <dd className=\"font-medium text-text-primary\">\n {dataSink.lastRefreshedAt\n ? formatDistanceToNow(new Date(dataSink.lastRefreshedAt), { addSuffix: true })\n : t('bigconsole.dataSinks.view.never', 'Never')}\n </dd>\n </div>\n <div className=\"flex flex-wrap items-center justify-between gap-x-form-gap gap-y-1 py-2 last:pb-0\">\n <dt className=\"min-w-0 text-text-secondary\">{t('bigconsole.dataSinks.view.created', 'Created')}</dt>\n <dd className=\"font-medium text-text-primary\">\n {formatDistanceToNow(new Date(dataSink.createdAt), { addSuffix: true })}\n </dd>\n </div>\n </dl>\n </Section>\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 {/* The point of this route: the cached rows themselves. */}\n <Section\n emphasis=\"primary\"\n headingLevel={2}\n title={t('bigconsole.dataSinks.view.dataPreview', 'Data Preview')}\n description=\"The rows this sink is currently serving to dashboards.\"\n icon={<Database className=\"h-icon-sm w-icon-sm\" />}\n actions={\n <>\n {showData && (\n <div\n role=\"group\"\n aria-label={t('bigconsole.dataSinks.view.dataPreview', 'Data Preview')}\n className=\"flex items-center overflow-hidden rounded-button border border-[var(--color-border-default)]\"\n >\n <button\n type=\"button\"\n onClick={() => setDataViewMode('table')}\n aria-pressed={dataViewMode === 'table'}\n className={`flex h-control-md w-[var(--size-controlHeight-md)] items-center justify-center ${SECTION_FOCUS_RING} ${SEGMENT_RING_FIX} ${\n dataViewMode === 'table'\n ? 'bg-bg-sunken text-text-primary'\n : 'text-text-secondary hover:text-text-primary'\n }`}\n title={t('bigconsole.dataSinks.view.tableView', 'Table view')}\n >\n <Grid3X3 className=\"w-4 h-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setDataViewMode('json')}\n aria-pressed={dataViewMode === 'json'}\n className={`flex h-control-md w-[var(--size-controlHeight-md)] items-center justify-center ${SECTION_FOCUS_RING} ${SEGMENT_RING_FIX} ${\n dataViewMode === 'json'\n ? 'bg-bg-sunken text-text-primary'\n : 'text-text-secondary hover:text-text-primary'\n }`}\n title={t('bigconsole.dataSinks.view.jsonView', '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 {t('bigconsole.dataSinks.view.loading', 'Loading...')}\n </>\n ) : showData ? (\n <>\n <EyeOff className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.view.hideData', 'Hide Data')}\n </>\n ) : (\n <>\n <Eye className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.view.showData', 'Show Data')}\n </>\n )}\n </Button>\n </>\n }\n >\n {showData && dataPreview && (\n <>\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=\"mt-form-gap flex flex-wrap items-center justify-between gap-form-gap border-t border-[var(--color-border-subtle)] pt-form-gap\">\n <label className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <span>{t('bigconsole.dataSinks.view.rowsPerPage', 'Rows per page')}</span>\n <select\n aria-label={t('bigconsole.dataSinks.view.rowsPerPage', 'Rows per page')}\n className={`h-control-md rounded-input border border-[var(--color-border-default)] bg-bg-canvas px-2 text-text-primary ${SECTION_FOCUS_RING}`}\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 </label>\n <div className=\"flex flex-wrap items-center gap-control-gap text-sm text-text-secondary\">\n <span>\n {dataTotalCount === 0\n ? t('bigconsole.dataSinks.view.zeroRows', '0 rows')\n : t('bigconsole.dataSinks.view.rowRange', '{{start}}–{{end}} of {{total}}', {\n start: pageOffset + 1,\n end: Math.min(pageOffset + pageSize, dataTotalCount),\n total: dataTotalCount,\n })}\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 {t('bigconsole.dataSinks.view.previous', 'Previous')}\n </Button>\n <Button\n variant=\"secondary\"\n size=\"sm\"\n disabled={!dataHasMore || dataLoading}\n onClick={() => void loadDataPage(pageOffset + pageSize, pageSize)}\n >\n {t('bigconsole.dataSinks.view.next', 'Next')}\n </Button>\n </div>\n </div>\n )}\n </>\n )}\n\n {!showData &&\n (dataSink.data && Object.keys(dataSink.data).length > 0 ? (\n <p className=\"flex items-center gap-icon-gap text-sm text-text-secondary\">\n <Database aria-hidden=\"true\" className=\"h-icon-sm w-icon-sm shrink-0 text-text-muted\" />\n {t('bigconsole.dataSinks.view.showDataHint', 'Click \"Show Data\" to preview the cached data.')}\n </p>\n ) : (\n // No data yet — surface the Import Data flow so a new user knows the next step.\n <div className=\"flex flex-col items-center gap-form-gap py-form-gap text-center\">\n <Database aria-hidden=\"true\" className=\"h-icon-lg w-icon-lg text-text-muted\" />\n <p className=\"text-sm text-text-secondary\">\n {t(\n 'bigconsole.dataSinks.view.noDataYet',\n 'This data sink has no data yet. Upload a CSV or build a workflow to import data.'\n )}\n </p>\n <Button onClick={handleImport} variant=\"default\" size=\"sm\">\n <Upload className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.view.importData', 'Import Data')}\n </Button>\n </div>\n ))}\n </Section>\n </SectionStack>\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\n {/* Import Data guide Dialog */}\n <ImportDataGuideDialog\n isOpen={isImportDialogOpen}\n dataSinkName={dataSink.name || dataSink.key}\n hasExistingData={Boolean(dataSink.data && Object.keys(dataSink.data).length > 0)}\n onClose={handleImportClose}\n onGoToWorkflows={handleGoToWorkflows}\n onImportCsv={handleImportCsv}\n />\n </div>\n );\n});\n\nexport default DataSinkViewPage;\n"],"mappings":"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"}
|
|
@@ -19,10 +19,10 @@ import { memo as s, useCallback as c, useMemo as l, useState as u } from "react"
|
|
|
19
19
|
import { AccessDenied as ue, PermissionButton as de } from "@burdenoff/fe-libs/shared/components";
|
|
20
20
|
import { usePermissions as fe } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
21
21
|
import { AlertCircle as pe, Container as me, Download as he, Eye as ge, LayoutGrid as _e, Pencil as ve, Plus as d, RefreshCw as ye, Search as be, Table2 as xe, Trash2 as Se, Upload as Ce, X as we } from "lucide-react";
|
|
22
|
-
import {
|
|
23
|
-
import { AuroraBackground as Ee, Badge as De, Button as f, CTAOverflowMenu as Oe, GradientText as ke, IllustratedEmptyState as Ae, Input as je, PagePurpose as Me, Select as p, SelectContent as m, SelectItem as h, SelectTrigger as g, SelectValue as _, Spinner as Ne } from "@burdenoff/fe-libs/ui";
|
|
22
|
+
import { AuroraBackground as Te, Badge as Ee, Button as f, CTAOverflowMenu as De, GradientText as Oe, IllustratedEmptyState as ke, Input as Ae, PagePurpose as je, Select as p, SelectContent as m, SelectItem as h, SelectTrigger as g, SelectValue as _, Spinner as Me } from "@burdenoff/fe-libs/ui";
|
|
24
23
|
import { getProfileScopedKey as v } from "@burdenoff/fe-libs/shared/utils";
|
|
25
24
|
import { Fragment as y, jsx as b, jsxs as x } from "react/jsx-runtime";
|
|
25
|
+
import { useI18n as Ne } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
26
26
|
import { formatDistanceToNow as S } from "date-fns";
|
|
27
27
|
//#region src/bigconsole/pages/DataSinksPage.tsx
|
|
28
28
|
var Pe = "bigconsole-datasinks-view-mode", C = `inline-flex h-control-md w-[var(--size-controlHeight-md)] items-center justify-center rounded-button border-0 bg-transparent text-text-muted hover:bg-bg-surface hover:text-text-primary motion-safe:transition-colors ${n}`, Fe = "focus-visible:ring-inset focus-visible:ring-offset-0", Ie = (e) => e.setupState === "completed" || e.ttl !== null && e.ttl !== void 0 && e.ttl > 0 || e.fluidGridsWorkflowId && e.data && Object.keys(e.data).length > 0 ? "completed" : e.fluidGridsWorkflowId ? "workflow_running" : "workflow_pending", Le = (e) => {
|
|
@@ -30,7 +30,7 @@ var Pe = "bigconsole-datasinks-view-mode", C = `inline-flex h-control-md w-[var(
|
|
|
30
30
|
let t = new Date(e);
|
|
31
31
|
return Number.isNaN(t.getTime()) ? "—" : S(t, { addSuffix: !0 });
|
|
32
32
|
}, w = s(function() {
|
|
33
|
-
let s = t(), { t: S } =
|
|
33
|
+
let s = t(), { t: S } = Ne(), w = c((e, t) => {
|
|
34
34
|
let n = S(e);
|
|
35
35
|
return n === e ? t : n;
|
|
36
36
|
}, [S]), { hasPermission: T, isLoading: Re } = fe(), ze = T(i.DATASINK_READ), E = T(i.DATASINK_CREATE), D = T(i.DATASINK_UPDATE), O = T(i.DATASINK_DELETE), k = T(i.DATASINK_EXECUTE), [A, j] = u("all"), [Be, M] = u(!1), [N, Ve] = u(() => localStorage.getItem(v(Pe)) || "grid"), P = c((e) => {
|
|
@@ -126,7 +126,7 @@ var Pe = "bigconsole-datasinks-view-mode", C = `inline-flex h-control-md w-[var(
|
|
|
126
126
|
children: [
|
|
127
127
|
/* @__PURE__ */ x("header", {
|
|
128
128
|
className: "relative overflow-hidden border-b border-[var(--color-border-seam)] bg-[image:var(--gradient-gloss-card)]",
|
|
129
|
-
children: [/* @__PURE__ */ b(
|
|
129
|
+
children: [/* @__PURE__ */ b(Te, { intensity: "subtle" }), /* @__PURE__ */ b("div", {
|
|
130
130
|
style: { padding: "var(--space-pagePadding)" },
|
|
131
131
|
children: /* @__PURE__ */ x("div", {
|
|
132
132
|
style: {
|
|
@@ -163,13 +163,13 @@ var Pe = "bigconsole-datasinks-view-mode", C = `inline-flex h-control-md w-[var(
|
|
|
163
163
|
style: { minWidth: 0 },
|
|
164
164
|
children: [/* @__PURE__ */ b("h1", {
|
|
165
165
|
className: "m-0 text-2xl font-bold text-text-primary",
|
|
166
|
-
children: /* @__PURE__ */ b(
|
|
166
|
+
children: /* @__PURE__ */ b(Oe, { children: w("bigconsole.dataSinks.title", "Data Sinks") })
|
|
167
167
|
}), /* @__PURE__ */ b("p", {
|
|
168
168
|
className: "m-0 text-sm text-text-secondary",
|
|
169
169
|
children: w("bigconsole.dataSinks.subtitle", "Manage pre-processed data from FluidGrids workflows")
|
|
170
170
|
})]
|
|
171
171
|
})]
|
|
172
|
-
}), /* @__PURE__ */ b(
|
|
172
|
+
}), /* @__PURE__ */ b(De, {
|
|
173
173
|
primary: E ? {
|
|
174
174
|
label: w("bigconsole.dataSinks.actions.create", "Create Data Sink"),
|
|
175
175
|
onSelect: qe,
|
|
@@ -193,7 +193,7 @@ var Pe = "bigconsole-datasinks-view-mode", C = `inline-flex h-control-md w-[var(
|
|
|
193
193
|
}),
|
|
194
194
|
/* @__PURE__ */ x("div", {
|
|
195
195
|
style: { padding: "var(--space-pagePadding)" },
|
|
196
|
-
children: [/* @__PURE__ */ b(
|
|
196
|
+
children: [/* @__PURE__ */ b(je, {
|
|
197
197
|
className: "mb-[var(--space-sectionGap)]",
|
|
198
198
|
children: "Data sinks are the structured destinations that hold your processed data — define a schema once and every pipeline, parser, and workflow can write into it. Dashboards then query sinks directly, so a sink is where your data lives and where your charts read from."
|
|
199
199
|
}), /* @__PURE__ */ b(ee, { children: q ? /* @__PURE__ */ b(r, {
|
|
@@ -269,7 +269,7 @@ var Pe = "bigconsole-datasinks-view-mode", C = `inline-flex h-control-md w-[var(
|
|
|
269
269
|
height: "var(--size-icon-sm)",
|
|
270
270
|
width: "var(--size-icon-sm)",
|
|
271
271
|
color: "var(--color-text-muted)"
|
|
272
|
-
} }), /* @__PURE__ */ b(
|
|
272
|
+
} }), /* @__PURE__ */ b(Ae, {
|
|
273
273
|
type: "text",
|
|
274
274
|
placeholder: w("bigconsole.dataSinks.search.placeholder", "Search data sinks..."),
|
|
275
275
|
value: L,
|
|
@@ -347,7 +347,7 @@ var Pe = "bigconsole-datasinks-view-mode", C = `inline-flex h-control-md w-[var(
|
|
|
347
347
|
headingLevel: 2,
|
|
348
348
|
title: w("bigconsole.dataSinks.list.heading", "Data sinks"),
|
|
349
349
|
description: w("bigconsole.dataSinks.list.description", "Every sink in this workspace, most recently updated first."),
|
|
350
|
-
meta: /* @__PURE__ */ x(
|
|
350
|
+
meta: /* @__PURE__ */ x(Ee, {
|
|
351
351
|
variant: "secondary",
|
|
352
352
|
children: [
|
|
353
353
|
Z.length,
|
|
@@ -398,7 +398,7 @@ var Pe = "bigconsole-datasinks-view-mode", C = `inline-flex h-control-md w-[var(
|
|
|
398
398
|
className: "flex items-center justify-center py-12",
|
|
399
399
|
children: /* @__PURE__ */ x("div", {
|
|
400
400
|
style: { textAlign: "center" },
|
|
401
|
-
children: [/* @__PURE__ */ b(
|
|
401
|
+
children: [/* @__PURE__ */ b(Me, { style: {
|
|
402
402
|
height: "var(--size-icon-xl)",
|
|
403
403
|
width: "var(--size-icon-xl)",
|
|
404
404
|
margin: "0 auto var(--space-formGap)"
|
|
@@ -408,7 +408,7 @@ var Pe = "bigconsole-datasinks-view-mode", C = `inline-flex h-control-md w-[var(
|
|
|
408
408
|
})]
|
|
409
409
|
})
|
|
410
410
|
}),
|
|
411
|
-
!K && J.length === 0 && /* @__PURE__ */ b(
|
|
411
|
+
!K && J.length === 0 && /* @__PURE__ */ b(ke, {
|
|
412
412
|
illustration: "empty-data",
|
|
413
413
|
title: w("bigconsole.dataSinks.empty.title", "No Data Sinks yet"),
|
|
414
414
|
description: w("bigconsole.dataSinks.empty.description", "Data Sinks store pre-processed data from FluidGrids workflows for fast access in widgets."),
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { useAppNavigate as e } from "../contexts/NavigationContext.js";
|
|
2
2
|
import "../contexts/index.js";
|
|
3
3
|
import { useEffect as t } from "react";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { jsx as n } from "react/jsx-runtime";
|
|
5
|
+
import { useI18n as r } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
6
6
|
//#region src/bigconsole/pages/DataSourcesPage.tsx
|
|
7
7
|
function i() {
|
|
8
|
-
let i = e(), { t: a } =
|
|
8
|
+
let i = e(), { t: a } = r();
|
|
9
9
|
return t(() => {
|
|
10
10
|
i("/datasinks", { replace: !0 });
|
|
11
|
-
}, []), /* @__PURE__ */
|
|
11
|
+
}, []), /* @__PURE__ */ n("div", {
|
|
12
12
|
className: "p-card-padding",
|
|
13
|
-
children: /* @__PURE__ */
|
|
13
|
+
children: /* @__PURE__ */ n("p", {
|
|
14
14
|
role: "status",
|
|
15
15
|
"aria-live": "polite",
|
|
16
16
|
className: "text-sm text-text-secondary",
|