@burdenoff/microfe-bigconsole 2026.1008.10 → 2026.1008.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/dist/bigconsole/BigConsoleRoutes.d.ts.map +1 -1
  2. package/dist/bigconsole/BigConsoleRoutes.js +136 -127
  3. package/dist/bigconsole/BigConsoleRoutes.js.map +1 -1
  4. package/dist/bigconsole/assistant/assistantProduct.d.ts.map +1 -1
  5. package/dist/bigconsole/assistant/assistantProduct.js +3 -1
  6. package/dist/bigconsole/assistant/assistantProduct.js.map +1 -1
  7. package/dist/bigconsole/components/builder/inspector/DataBindingSection.js +31 -31
  8. package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js +44 -44
  9. package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js.map +1 -1
  10. package/dist/bigconsole/components/dashboard/DashboardCanvas.js +36 -36
  11. package/dist/bigconsole/components/dashboard/DashboardCanvas.js.map +1 -1
  12. package/dist/bigconsole/components/dashboard/DashboardToolbar.js +59 -59
  13. package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js +15 -15
  14. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterChip.js +30 -30
  15. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js +41 -41
  16. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js +34 -34
  17. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js +34 -34
  18. package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js +110 -110
  19. package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js.map +1 -1
  20. package/dist/bigconsole/components/dashboard/PublishToStoreDialog.js +21 -21
  21. package/dist/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.js +46 -46
  22. package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js +91 -91
  23. package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js.map +1 -1
  24. package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js +101 -101
  25. package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js.map +1 -1
  26. package/dist/bigconsole/components/dashboard/TemplateInstallOptions.js +31 -31
  27. package/dist/bigconsole/components/dashboard/TemplateLayoutPreview.js +15 -15
  28. package/dist/bigconsole/components/dashboard/TemplatePicker/TemplatePicker.js +1 -1
  29. package/dist/bigconsole/components/dashboard/WidgetPalette.js +46 -46
  30. package/dist/bigconsole/components/datasink/AlertExecutionHistory.js +37 -37
  31. package/dist/bigconsole/components/datasink/AlertRuleEditor.js +66 -66
  32. package/dist/bigconsole/components/datasink/CacheTTLSelector.js +35 -35
  33. package/dist/bigconsole/components/datasink/DataSinkCard.js +29 -29
  34. package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js +18 -18
  35. package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js +20 -20
  36. package/dist/bigconsole/components/datasink/ImportDataGuideDialog.js +47 -47
  37. package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js +91 -91
  38. package/dist/bigconsole/components/datasink/RefreshTypeSelector.js +35 -35
  39. package/dist/bigconsole/components/parser/DataSinkSelector.js +40 -40
  40. package/dist/bigconsole/components/parser/ImportParserDialog.js +120 -120
  41. package/dist/bigconsole/components/parser/ImportParserDialog.js.map +1 -1
  42. package/dist/bigconsole/components/parser/ParserSelector.js +51 -51
  43. package/dist/bigconsole/components/pipeline/PipelineScopePicker.js +10 -10
  44. package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js +27 -27
  45. package/dist/bigconsole/components/preview/AiPreviewPanel.js +30 -30
  46. package/dist/bigconsole/components/widgets/ActionConfigDialog.js +4 -4
  47. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js +93 -93
  48. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js.map +1 -1
  49. package/dist/bigconsole/components/widgets/PropertiesPanel.d.ts.map +1 -1
  50. package/dist/bigconsole/components/widgets/PropertiesPanel.js +280 -273
  51. package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
  52. package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js +4 -4
  53. package/dist/bigconsole/components/widgets/chart/ChartConfig.js +48 -48
  54. package/dist/bigconsole/components/widgets/comments/WidgetComments.js +46 -46
  55. package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js +61 -61
  56. package/dist/bigconsole/components/widgets/form/FormWidget.js +36 -36
  57. package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js +42 -42
  58. package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js +25 -25
  59. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +4 -4
  60. package/dist/bigconsole/components/widgets/list/ListConfig.js +30 -30
  61. package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js +38 -38
  62. package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js +9 -9
  63. package/dist/bigconsole/components/widgets/metric-card/TrendIndicator.js +9 -9
  64. package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js +49 -49
  65. package/dist/bigconsole/components/widgets/progress/ProgressConfig.js +39 -39
  66. package/dist/bigconsole/components/widgets/table/TableConfig.js +73 -73
  67. package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js +64 -64
  68. package/dist/bigconsole/components/workflow/WorkflowOpenGuard.js +15 -15
  69. package/dist/bigconsole/components/workflow/WorkflowSinkLinkForm.js +15 -15
  70. package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js +9 -9
  71. package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js +67 -67
  72. package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js.map +1 -1
  73. package/dist/bigconsole/hooks/useDashboardLayoutBaseline.d.ts +15 -0
  74. package/dist/bigconsole/hooks/useDashboardLayoutBaseline.d.ts.map +1 -0
  75. package/dist/bigconsole/hooks/useDashboardLayoutBaseline.js +34 -0
  76. package/dist/bigconsole/hooks/useDashboardLayoutBaseline.js.map +1 -0
  77. package/dist/bigconsole/hooks/useDrilldown.js +3 -3
  78. package/dist/bigconsole/hooks/useGlobalFilters.js +3 -3
  79. package/dist/bigconsole/pages/AdminPage.js +130 -130
  80. package/dist/bigconsole/pages/DashboardBuilderPage.d.ts.map +1 -1
  81. package/dist/bigconsole/pages/DashboardBuilderPage.js +72 -60
  82. package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
  83. package/dist/bigconsole/pages/DashboardViewPage.js +1 -1
  84. package/dist/bigconsole/pages/DataSinkAlertsPage.d.ts.map +1 -1
  85. package/dist/bigconsole/pages/DataSinkAlertsPage.js +30 -23
  86. package/dist/bigconsole/pages/DataSinkAlertsPage.js.map +1 -1
  87. package/dist/bigconsole/pages/DataSinkBuilderPage.d.ts.map +1 -1
  88. package/dist/bigconsole/pages/DataSinkBuilderPage.js +272 -263
  89. package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
  90. package/dist/bigconsole/pages/DataSinkViewPage.js +1 -1
  91. package/dist/bigconsole/pages/DataSinksPage.js +1 -1
  92. package/dist/bigconsole/pages/DataSourcesPage.js +5 -5
  93. package/dist/bigconsole/pages/InsightsPage.js +181 -181
  94. package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
  95. package/dist/bigconsole/pages/OverviewPage.js +47 -47
  96. package/dist/bigconsole/pages/OverviewPage.js.map +1 -1
  97. package/dist/bigconsole/pages/ParserBuilderPage.d.ts.map +1 -1
  98. package/dist/bigconsole/pages/ParserBuilderPage.js +227 -211
  99. package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
  100. package/dist/bigconsole/pages/ParserViewPage.js +97 -97
  101. package/dist/bigconsole/pages/PipelineBuilderPage.d.ts.map +1 -1
  102. package/dist/bigconsole/pages/PipelineBuilderPage.js +256 -214
  103. package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
  104. package/dist/bigconsole/pages/PipelineViewPage.js +146 -146
  105. package/dist/bigconsole/pages/PipelinesPage.js +88 -88
  106. package/dist/bigconsole/pages/PipelinesPage.js.map +1 -1
  107. package/dist/bigconsole/pages/SettingsPage.d.ts.map +1 -1
  108. package/dist/bigconsole/pages/SettingsPage.js +179 -173
  109. package/dist/bigconsole/pages/SettingsPage.js.map +1 -1
  110. package/dist/bigconsole/pages/WidgetDemoPage.js +42 -42
  111. package/dist/bigconsole/pages/WorkflowViewPage.js +1 -1
  112. package/dist/bigconsole/pages/WorkflowsPage.js +141 -141
  113. package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
  114. package/dist/bigconsole/providers/BigConsoleQuotaProvider.js +12 -12
  115. package/dist/bigconsole/renderers/adapters/AdaptiveCardRenderer.js +34 -34
  116. package/dist/bigconsole/renderers/adapters/BlockKitRenderer.js +79 -79
  117. package/dist/bigconsole/renderers/adapters/CustomRenderer.js +46 -46
  118. package/dist/bigconsole/store/widgetStore.d.ts +12 -0
  119. package/dist/bigconsole/store/widgetStore.d.ts.map +1 -1
  120. package/dist/bigconsole/store/widgetStore.js +3 -1
  121. package/dist/bigconsole/store/widgetStore.js.map +1 -1
  122. package/dist/bigconsole/utils/formDirty.d.ts +83 -0
  123. package/dist/bigconsole/utils/formDirty.d.ts.map +1 -0
  124. package/dist/bigconsole/utils/formDirty.js +23 -0
  125. package/dist/bigconsole/utils/formDirty.js.map +1 -0
  126. package/dist/bigconsole/utils/layoutBaseline.d.ts +131 -0
  127. package/dist/bigconsole/utils/layoutBaseline.d.ts.map +1 -0
  128. package/dist/bigconsole/utils/layoutBaseline.js +98 -0
  129. package/dist/bigconsole/utils/layoutBaseline.js.map +1 -0
  130. package/dist/translations/en.d.ts.map +1 -1
  131. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"DataSinkBuilderPage.js","names":[],"sources":["../../../src/bigconsole/pages/DataSinkBuilderPage.tsx"],"sourcesContent":["/**\n * DataSink Builder Page\n *\n * Simplified page for creating and editing DataSinks.\n * DataSinks are now standalone - workflows push data to them via unique keys.\n * Required fields: name, key\n */\n\nimport { memo, useState, useMemo, useEffect, useCallback } from 'react';\nimport { useParams } from 'react-router';\nimport { useAppNavigate } from '../contexts';\nimport { isNative, nativeCopyText, nativeToast } from '../../utils/nativeBridge';\nimport { useDataSinkOperations } from '../hooks/useDataSinkOperations';\nimport { loadBigConsoleSettings } from '../hooks/useBigConsoleSettings';\nimport { CacheTTLSelector } from '../components/datasink/CacheTTLSelector';\nimport { RefreshTypeSelector } from '../components/datasink/RefreshTypeSelector';\nimport type { CreateDataSinkInput, UpdateDataSinkInput, DataSinkRefreshType } from '../types';\n\n// fe-libs UI components\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { Textarea } from '@burdenoff/fe-libs/ui';\nimport { Label } from '@burdenoff/fe-libs/ui';\nimport { IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\n\n// Section-emphasis primitives (BOFF-5632)\nimport { Section, SectionStack } from '../components/common';\n\n// Lucide icons\nimport { ArrowLeft, Save, Loader2, AlertCircle, Database, Settings, Eye, Copy, Check, ListChecks } from 'lucide-react';\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';\nimport { reportBigConsoleQuotaError } from '../utils/quota';\n\ntype TranslateFn = (key: string, fallback: string, params?: Record<string, string | number>) => string;\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface RefreshConfig {\n type: 'manual' | 'scheduled';\n schedule?: {\n cron: string;\n timezone: string;\n };\n}\n\ninterface FormState {\n name: string;\n key: string;\n description: string;\n ttl: number;\n refresh: RefreshConfig;\n data: string; // JSON string for data payload\n}\n\ninterface FormErrors {\n name?: string;\n key?: string;\n data?: string;\n}\n\n// ============================================================================\n// HELPERS\n// ============================================================================\n\n/**\n * Generate a key from name (slug format)\n */\nfunction generateKey(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '_')\n .replace(/^_+|_+$/g, '')\n .substring(0, 64);\n}\n\n/**\n * Validate form data\n */\nfunction validateForm(form: FormState, t: TranslateFn): FormErrors {\n const errors: FormErrors = {};\n\n if (!form.name.trim()) {\n errors.name = t('bigconsole.dataSinks.builder.validation.nameRequired', 'Name is required');\n } else if (form.name.length < 2) {\n errors.name = t('bigconsole.dataSinks.builder.validation.nameMinLength', 'Name must be at least 2 characters');\n } else if (form.name.length > 100) {\n errors.name = t('bigconsole.dataSinks.builder.validation.nameMaxLength', 'Name must be less than 100 characters');\n }\n\n if (!form.key.trim()) {\n errors.key = t('bigconsole.dataSinks.builder.validation.keyRequired', 'Key is required');\n } else if (!/^[a-z0-9_]+$/.test(form.key)) {\n errors.key = t(\n 'bigconsole.dataSinks.builder.validation.keyFormat',\n 'Key can only contain lowercase letters, numbers, and underscores'\n );\n } else if (form.key.length > 64) {\n errors.key = t('bigconsole.dataSinks.builder.validation.keyMaxLength', 'Key must be less than 64 characters');\n }\n\n // Validate JSON data if provided\n if (form.data && form.data.trim()) {\n try {\n JSON.parse(form.data);\n } catch {\n errors.data = t('bigconsole.dataSinks.builder.validation.invalidJson', 'Invalid JSON format');\n }\n }\n\n return errors;\n}\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const DataSinkBuilderPage = memo(function DataSinkBuilderPage() {\n const { dataSinkId } = useParams<{ dataSinkId?: string }>();\n const navigate = useAppNavigate();\n const { t } = useI18n();\n\n const isEdit = dataSinkId !== 'new' && !!dataSinkId;\n\n // RBAC — Save requires UPDATE when editing an existing sink, CREATE when\n // creating a new one. In edit mode the page also requires READ to be viewed.\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const canRead = hasPermission(BIGCONSOLE_PERMISSIONS.DATASINK_READ);\n const savePermission = isEdit ? BIGCONSOLE_PERMISSIONS.DATASINK_UPDATE : BIGCONSOLE_PERMISSIONS.DATASINK_CREATE;\n\n // Form state\n const [form, setForm] = useState<FormState>({\n name: '',\n key: '',\n description: '',\n ttl: (() => {\n const defaults = loadBigConsoleSettings();\n return defaults.cacheEnabled ? defaults.cacheTTLSeconds : 0;\n })(),\n refresh: {\n type: 'manual',\n },\n data: '{}', // Default empty JSON object\n });\n const [errors, setErrors] = useState<FormErrors>({});\n const [keyManuallyEdited, setKeyManuallyEdited] = useState(false);\n const [isSaving, setIsSaving] = useState(false);\n const [submitError, setSubmitError] = useState<string | null>(null);\n const [keyCopied, setKeyCopied] = useState(false);\n\n // Data preview state\n const [isLoadingPreview, setIsLoadingPreview] = useState(false);\n const [previewData, setPreviewData] = useState<unknown[] | null>(null);\n const [previewError, setPreviewError] = useState<string | null>(null);\n\n // Operations\n const { loading, error, dataSinks, fetchDataSink, createDataSink, updateDataSink, getDataSinkData } =\n useDataSinkOperations({\n skipFetch: true,\n });\n\n // Get existing data sink if editing\n const existingDataSink = isEdit ? dataSinks.find((ds) => ds.id === dataSinkId) : null;\n\n // Load existing data sink for editing\n useEffect(() => {\n if (isEdit && dataSinkId && !existingDataSink) {\n fetchDataSink(dataSinkId);\n }\n }, [isEdit, dataSinkId, existingDataSink, fetchDataSink]);\n\n // Track if form has been initialized\n const [formInitialized, setFormInitialized] = useState(false);\n\n // Populate form with existing data when editing (only once)\n useEffect(() => {\n if (existingDataSink && !formInitialized) {\n // Format existing data as pretty JSON string\n let dataString = '';\n if (existingDataSink.data) {\n try {\n // Check if data is already a string (JSON string from API)\n if (typeof existingDataSink.data === 'string') {\n // Parse and re-stringify to ensure proper formatting\n const parsed = JSON.parse(existingDataSink.data);\n dataString = JSON.stringify(parsed, null, 2);\n } else {\n // It's an object, just stringify it\n dataString = JSON.stringify(existingDataSink.data, null, 2);\n }\n } catch {\n // If parsing fails, use as-is if string, otherwise empty\n dataString = typeof existingDataSink.data === 'string' ? existingDataSink.data : '';\n }\n }\n\n setForm({\n name: existingDataSink.name || '',\n key: existingDataSink.key || '',\n description: existingDataSink.description || '',\n ttl: existingDataSink.ttl ?? 300,\n refresh: existingDataSink.refresh\n ? {\n type: existingDataSink.refresh.type === 'scheduled' ? 'scheduled' : 'manual',\n schedule: existingDataSink.refresh.schedule\n ? {\n cron: existingDataSink.refresh.schedule.cron,\n timezone: existingDataSink.refresh.schedule.timezone,\n }\n : undefined,\n }\n : { type: 'manual' },\n data: dataString,\n });\n setKeyManuallyEdited(true); // Don't auto-generate key when editing\n setFormInitialized(true); // Mark as initialized\n setErrors({}); // Clear any errors\n }\n }, [existingDataSink, formInitialized]);\n\n // Auto-generate key from name\n const handleNameChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const name = e.target.value;\n setForm((prev) => ({\n ...prev,\n name,\n key: keyManuallyEdited ? prev.key : generateKey(name),\n }));\n setErrors((prev) => ({ ...prev, name: undefined }));\n },\n [keyManuallyEdited]\n );\n\n // Handle key change\n const handleKeyChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const key = e.target.value.toLowerCase().replace(/[^a-z0-9_]/g, '');\n setForm((prev) => ({ ...prev, key }));\n setKeyManuallyEdited(true);\n setErrors((prev) => ({ ...prev, key: undefined }));\n }, []);\n\n // Handle description change\n const handleDescriptionChange = useCallback((e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setForm((prev) => ({ ...prev, description: e.target.value }));\n }, []);\n\n // Handle TTL change\n const handleTTLChange = useCallback((ttl: number | null) => {\n setForm((prev) => ({ ...prev, ttl: ttl || 0 }));\n }, []);\n\n // Handle refresh config change\n const handleRefreshChange = useCallback((config: RefreshConfig) => {\n setForm((prev) => ({ ...prev, refresh: config }));\n }, []);\n\n // Handle data change\n const handleDataChange = useCallback((e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setForm((prev) => ({ ...prev, data: e.target.value }));\n setErrors((prev) => ({ ...prev, data: undefined }));\n }, []);\n\n // Format JSON data\n const handleFormatData = useCallback(() => {\n try {\n const parsed = JSON.parse(form.data);\n setForm((prev) => ({ ...prev, data: JSON.stringify(parsed, null, 2) }));\n setErrors((prev) => ({ ...prev, data: undefined }));\n } catch {\n setErrors((prev) => ({\n ...prev,\n data: t('bigconsole.dataSinks.builder.validation.invalidJson', 'Invalid JSON format'),\n }));\n }\n }, [form.data, t]);\n\n // Copy key to clipboard\n const handleCopyKey = useCallback(async () => {\n if (form.key) {\n await nativeCopyText(form.key);\n setKeyCopied(true);\n if (isNative()) void nativeToast(t('bigconsole.dataSinks.builder.toolbar.keyCopied', 'Key copied'));\n setTimeout(() => setKeyCopied(false), 2000);\n }\n }, [form.key, t]);\n\n // Handle back navigation\n const handleBack = useCallback(() => {\n navigate('/datasinks');\n }, [navigate]);\n\n // Load data preview\n const handleShowData = useCallback(async () => {\n if (!isEdit || !existingDataSink) return;\n\n setIsLoadingPreview(true);\n setPreviewError(null);\n\n try {\n const result = await getDataSinkData({ key: existingDataSink.key });\n if (result?.raw) {\n // Get first 20 items if it's an array, otherwise wrap in array\n const data = Array.isArray(result.raw) ? result.raw.slice(0, 20) : [result.raw];\n setPreviewData(data);\n } else {\n setPreviewData([]);\n }\n } catch (err) {\n setPreviewError(\n err instanceof Error\n ? err.message\n : t('bigconsole.dataSinks.builder.errors.loadDataFailed', 'Failed to load data')\n );\n } finally {\n setIsLoadingPreview(false);\n }\n }, [isEdit, existingDataSink, getDataSinkData, t]);\n\n // Handle form submission\n const handleSubmit = useCallback(\n async (e: React.FormEvent) => {\n e.preventDefault();\n setSubmitError(null);\n\n // Validate form\n const validationErrors = validateForm(form, t);\n if (Object.keys(validationErrors).length > 0) {\n setErrors(validationErrors);\n return;\n }\n\n setIsSaving(true);\n try {\n // Parse data JSON\n let parsedData: Record<string, unknown> = {};\n if (form.data && form.data.trim()) {\n try {\n parsedData = JSON.parse(form.data) as Record<string, unknown>;\n } catch {\n setErrors((prev) => ({\n ...prev,\n data: t('bigconsole.dataSinks.builder.validation.invalidJson', 'Invalid JSON format'),\n }));\n setIsSaving(false);\n return;\n }\n }\n\n if (isEdit && existingDataSink) {\n // Update existing\n const input: UpdateDataSinkInput = {\n id: existingDataSink.id,\n version: existingDataSink.version,\n name: form.name,\n description: form.description || undefined,\n ttl: form.ttl,\n refresh: {\n type: form.refresh.type as DataSinkRefreshType,\n schedule: form.refresh.schedule,\n },\n data: parsedData, // Include data in update\n };\n const result = await updateDataSink(input);\n if (!result) {\n throw new Error(t('bigconsole.dataSinks.builder.errors.updateFailed', 'Failed to update DataSink'));\n }\n } else {\n // Create new - simplified flow (standalone DataSinks)\n const input: CreateDataSinkInput = {\n key: form.key,\n name: form.name,\n description: form.description || undefined,\n ttl: form.ttl,\n refresh: {\n type: form.refresh.type as DataSinkRefreshType,\n schedule: form.refresh.schedule,\n },\n data: parsedData, // Include data in create\n };\n const result = await createDataSink(input);\n if (!result) {\n throw new Error(t('bigconsole.dataSinks.builder.errors.createFailed', 'Failed to create DataSink'));\n }\n }\n navigate('/datasinks');\n } catch (err) {\n // A quota refusal opens the billing dialog (for a new org: \"Set up\n // billing\", BOFF-7913) instead of a dead-end error banner. The form\n // keeps its values so the user can retry once billing is set up.\n if (reportBigConsoleQuotaError(err)) {\n return;\n }\n setSubmitError(\n err instanceof Error\n ? err.message\n : t('bigconsole.dataSinks.builder.errors.saveFailed', 'Failed to save DataSink')\n );\n } finally {\n setIsSaving(false);\n }\n },\n [form, isEdit, existingDataSink, createDataSink, updateDataSink, navigate, t]\n );\n\n // Check if form is valid\n const isFormValid = useMemo(() => {\n const nameValid = form.name.trim().length >= 2;\n const keyValid = form.key.trim().length > 0;\n\n // Check JSON validity if data is provided\n let dataValid = true;\n if (form.data && form.data.trim()) {\n try {\n JSON.parse(form.data);\n } catch {\n dataValid = false;\n }\n }\n\n return nameValid && keyValid && dataValid;\n }, [form.name, form.key, form.data]);\n\n // Loading state\n if (loading && isEdit) {\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 if (error) {\n return (\n <div className=\"mx-auto w-full max-w-7xl p-card-padding\">\n <Section\n tone=\"danger\"\n headingLevel={2}\n title={t('bigconsole.dataSinks.builder.errors.loadFailed', '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.builder.header.backToDataSinks', 'Back to DataSinks')}\n </Button>\n }\n />\n </div>\n );\n }\n\n // Read gate — the edit surface requires read access to the existing sink.\n if (isEdit && !permissionsLoading && !canRead) {\n return (\n <AccessDenied\n title={t('bigconsole.dataSinks.builder.accessDenied.title', 'Access Denied')}\n description={t(\n 'bigconsole.dataSinks.builder.accessDenied.description',\n \"You don't have permission to view this data sink.\"\n )}\n />\n );\n }\n\n return (\n <div className=\"mx-auto w-full min-w-0 max-w-7xl p-card-padding\">\n {/* Page header strip */}\n <header className=\"mb-form-gap\">\n <Button onClick={handleBack} variant=\"ghost\" size=\"sm\" className=\"mb-4\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.builder.header.backToDataSinks', 'Back to DataSinks')}\n </Button>\n <h1 className=\"text-2xl font-bold text-text-primary\">\n {isEdit\n ? t('bigconsole.dataSinks.builder.header.editTitle', 'Edit DataSink')\n : t('bigconsole.dataSinks.builder.header.createTitle', 'Create DataSink')}\n </h1>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {isEdit\n ? t('bigconsole.dataSinks.builder.header.editSubtitle', 'Update the DataSink configuration.')\n : t(\n 'bigconsole.dataSinks.builder.header.createSubtitle',\n 'Create a new DataSink to store and cache data. Use the unique key to connect workflows.'\n )}\n </p>\n </header>\n\n <PagePurpose className=\"mb-section-gap\">\n {t(\n 'bigconsole.dataSinks.builder.header.purpose',\n 'A data sink is the named, structured store your dashboards read from. Give it a unique key, configure how long data is cached and how it refreshes, then point a workflow at that key to push data in. Get the basics right here and everything downstream connects to it.'\n )}\n </PagePurpose>\n\n {/* Submit failure — a status section, not a hand-rolled tinted div. */}\n {submitError && (\n <Section\n tone=\"danger\"\n headingLevel={2}\n title={t('bigconsole.dataSinks.builder.errors.saveFailed', 'Failed to save DataSink')}\n description={submitError}\n icon={<AlertCircle className=\"h-icon-sm w-icon-sm\" />}\n className=\"mb-section-gap\"\n />\n )}\n\n {/* Form */}\n <form data-tour=\"bigconsole-datasink-builder\" onSubmit={handleSubmit}>\n <SectionStack>\n {/* The point of this route: the sink's identity. */}\n <Section\n emphasis=\"primary\"\n headingLevel={2}\n title={t('bigconsole.dataSinks.builder.basicInfo.title', 'Basic Information')}\n description={t('bigconsole.dataSinks.builder.basicInfo.subtitle', 'Essential details for your DataSink')}\n icon={<Database className=\"h-icon-sm w-icon-sm\" />}\n bodyClassName=\"grid gap-form-gap md:grid-cols-2\"\n >\n <>\n {/* Name field */}\n <div className=\"space-y-2\">\n <Label htmlFor=\"name\">\n {t('bigconsole.dataSinks.builder.basicInfo.nameLabel', 'Name')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </Label>\n <Input\n id=\"name\"\n type=\"text\"\n value={form.name}\n onChange={handleNameChange}\n placeholder={t('bigconsole.dataSinks.builder.basicInfo.namePlaceholder', 'e.g., Sales Metrics')}\n className={errors.name ? 'border-status-error-border' : ''}\n />\n {errors.name && <p className=\"text-xs text-status-error-text\">{errors.name}</p>}\n </div>\n\n {/* Key field */}\n <div className=\"space-y-2\">\n <Label htmlFor=\"key\">\n {t('bigconsole.dataSinks.builder.basicInfo.keyLabel', 'Unique Key')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </Label>\n <div className=\"flex gap-2\">\n <Input\n id=\"key\"\n type=\"text\"\n value={form.key}\n onChange={handleKeyChange}\n placeholder={t('bigconsole.dataSinks.builder.basicInfo.keyPlaceholder', 'sales_metrics')}\n disabled={isEdit}\n className={`font-mono flex-1 ${errors.key ? 'border-status-error-border' : ''}`}\n />\n {form.key && (\n <Button\n type=\"button\"\n onClick={handleCopyKey}\n aria-label={t('bigconsole.dataSinks.builder.basicInfo.copyKey', 'Copy unique key')}\n variant=\"outline\"\n size=\"sm\"\n className=\"px-3\"\n >\n {keyCopied ? (\n <Check className=\"w-4 h-4 text-status-success-text\" />\n ) : (\n <Copy className=\"w-4 h-4\" />\n )}\n </Button>\n )}\n </div>\n {errors.key && <p className=\"text-xs text-status-error-text\">{errors.key}</p>}\n <p className=\"text-xs text-text-muted\">\n {isEdit\n ? t(\n 'bigconsole.dataSinks.builder.basicInfo.keyHelpEdit',\n 'Key cannot be changed. Use this key in your workflows to push data.'\n )\n : t(\n 'bigconsole.dataSinks.builder.basicInfo.keyHelpCreate',\n 'Auto-generated from name. This key will be used by workflows to push data.'\n )}\n </p>\n </div>\n\n {/* Description field */}\n <div className=\"space-y-2 md:col-span-2\">\n <Label htmlFor=\"description\">\n {t('bigconsole.dataSinks.builder.basicInfo.descriptionLabel', 'Description')}\n </Label>\n <Textarea\n id=\"description\"\n value={form.description}\n onChange={handleDescriptionChange}\n placeholder={t(\n 'bigconsole.dataSinks.builder.basicInfo.descriptionPlaceholder',\n 'Describe what data this sink stores...'\n )}\n rows={2}\n className=\"resize-none\"\n />\n </div>\n </>\n </Section>\n\n {/* Configuration */}\n <Section\n headingLevel={2}\n title={t('bigconsole.dataSinks.builder.config.title', 'Configuration')}\n description={t('bigconsole.dataSinks.builder.config.subtitle', 'Cache and refresh settings')}\n icon={<Settings className=\"h-icon-sm w-icon-sm\" />}\n bodyClassName=\"grid gap-form-gap md:grid-cols-2\"\n >\n <>\n {/* Cache TTL — the field label lives here, so the selector's own\n heading is suppressed to avoid a duplicated label. */}\n <div className=\"space-y-2\">\n <Label>{t('bigconsole.dataSinks.builder.config.cacheDurationLabel', 'Cache Duration')}</Label>\n <CacheTTLSelector value={form.ttl} onChange={handleTTLChange} hideLabel />\n <p className=\"text-xs text-text-muted\">\n {t(\n 'bigconsole.dataSinks.builder.config.cacheDurationHelp',\n 'How long cached data remains valid before requiring refresh.'\n )}\n </p>\n </div>\n\n {/* Refresh Type */}\n <RefreshTypeSelector value={form.refresh} onChange={handleRefreshChange} />\n </>\n </Section>\n\n {/* Data Payload */}\n <Section\n headingLevel={2}\n title={t('bigconsole.dataSinks.builder.dataPayload.title', 'Data Payload')}\n description={\n isEdit\n ? t(\n 'bigconsole.dataSinks.builder.dataPayload.subtitleEdit',\n 'Edit the JSON data stored in this DataSink'\n )\n : t('bigconsole.dataSinks.builder.dataPayload.subtitleCreate', 'Optional initial data (JSON format)')\n }\n icon={<Database className=\"h-icon-sm w-icon-sm\" />}\n actions={\n <Button type=\"button\" onClick={handleFormatData} variant=\"outline\" size=\"sm\">\n {t('bigconsole.dataSinks.builder.dataPayload.formatJson', 'Format JSON')}\n </Button>\n }\n bodyClassName=\"space-y-2\"\n >\n <>\n <Textarea\n aria-label={t('bigconsole.dataSinks.builder.dataPayload.title', 'Data Payload')}\n value={form.data}\n onChange={handleDataChange}\n placeholder={t('bigconsole.dataSinks.builder.dataPayload.dataPlaceholder', '{\"key\": \"value\"}')}\n rows={10}\n className={`resize-y font-mono text-xs ${errors.data ? 'border-status-error-border' : ''}`}\n />\n {errors.data && <p className=\"text-xs text-status-error-text\">{errors.data}</p>}\n <p className=\"text-xs text-text-muted\">\n {t(\n 'bigconsole.dataSinks.builder.dataPayload.help',\n 'Enter valid JSON data. This data will be stored and can be accessed by widgets via parsers.'\n )}\n </p>\n </>\n </Section>\n\n {/* Data Preview — read-only inspector, so it sits below the editable\n sections at `muted`, not level with them. */}\n {isEdit && existingDataSink && (\n <Section\n emphasis=\"muted\"\n headingLevel={2}\n title={t('bigconsole.dataSinks.builder.preview.title', 'Data Preview')}\n description={t('bigconsole.dataSinks.builder.preview.subtitle', 'Preview the first 20 records')}\n icon={<Eye className=\"h-icon-sm w-icon-sm\" />}\n actions={\n <Button type=\"button\" onClick={handleShowData} variant=\"outline\" size=\"sm\" disabled={isLoadingPreview}>\n {isLoadingPreview ? (\n <>\n <Loader2 className=\"w-4 h-4 mr-2 animate-spin\" />\n {t('bigconsole.dataSinks.builder.preview.loading', 'Loading...')}\n </>\n ) : (\n <>\n <Eye className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.builder.preview.showData', 'Show Data')}\n </>\n )}\n </Button>\n }\n >\n {previewError ? (\n <Section tone=\"danger\" padding=\"compact\" headingLevel={3} title=\"Could not load the preview\">\n <p className=\"text-sm text-status-error-text\">{previewError}</p>\n </Section>\n ) : previewData && previewData.length > 0 ? (\n <pre className=\"max-h-[300px] min-w-0 overflow-auto rounded-input bg-bg-surface p-3 font-mono text-xs\">\n {JSON.stringify(previewData, null, 2)}\n </pre>\n ) : previewData ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title={t('bigconsole.dataSinks.builder.preview.emptyTitle', 'No data available yet')}\n description={t(\n 'bigconsole.dataSinks.builder.preview.emptyDescription',\n \"Connect a workflow to this sink's key to start pushing data.\"\n )}\n />\n ) : (\n <p className=\"text-sm text-text-secondary\">\n Select &quot;Show data&quot; to load the records this sink currently holds.\n </p>\n )}\n </Section>\n )}\n\n {/* Guidance sits before the commit row — it is no longer advice that\n appears after the action which ends the task. */}\n {!isEdit && (\n <Section\n tone=\"info\"\n emphasis=\"muted\"\n headingLevel={2}\n title={t('bigconsole.dataSinks.builder.whatsNext.title', \"What's Next?\")}\n icon={<ListChecks className=\"h-icon-sm w-icon-sm\" />}\n >\n <ol className=\"list-inside list-decimal space-y-1 text-xs text-text-secondary\">\n <li>\n {t('bigconsole.dataSinks.builder.whatsNext.step1', 'Create this DataSink to get your unique key')}\n </li>\n <li>\n {t('bigconsole.dataSinks.builder.whatsNext.step2Prefix', 'Go to')}{' '}\n <strong>{t('bigconsole.dataSinks.builder.whatsNext.workflows', 'Workflows')}</strong>{' '}\n {t('bigconsole.dataSinks.builder.whatsNext.step2Suffix', 'and create a FluidGrids workflow')}\n </li>\n <li>\n {t(\n 'bigconsole.dataSinks.builder.whatsNext.step3',\n 'Use the unique key in your workflow to push data to this DataSink'\n )}\n </li>\n <li>\n {t('bigconsole.dataSinks.builder.whatsNext.step4Prefix', 'Create')}{' '}\n <strong>{t('bigconsole.dataSinks.builder.whatsNext.parsers', 'Parsers')}</strong>{' '}\n {t('bigconsole.dataSinks.builder.whatsNext.step4Suffix', 'to transform the data using JQ or JSONata')}\n </li>\n </ol>\n </Section>\n )}\n\n {/* Commit row — structural strip with a rule so the actions zone reads\n as the end of the form. */}\n <Section\n emphasis=\"bare\"\n padding=\"none\"\n aria-label=\"Save or discard this data sink\"\n className=\"border-t border-[var(--color-border-subtle)] pt-form-gap\"\n bodyClassName=\"flex flex-wrap items-center justify-end gap-control-gap\"\n >\n <Button type=\"button\" onClick={handleBack} variant=\"secondary\">\n {t('bigconsole.dataSinks.builder.actions.cancel', 'Cancel')}\n </Button>\n <PermissionButton permission={savePermission} deniedBehavior=\"disable\">\n <Button type=\"submit\" disabled={!isFormValid || isSaving} variant=\"default\">\n {isSaving ? (\n <>\n <Loader2 className=\"w-4 h-4 mr-2 animate-spin\" />\n {t('bigconsole.dataSinks.builder.actions.saving', 'Saving...')}\n </>\n ) : (\n <>\n <Save className=\"w-4 h-4 mr-2\" />\n {isEdit\n ? t('bigconsole.dataSinks.builder.actions.saveChanges', 'Save Changes')\n : t('bigconsole.dataSinks.builder.actions.create', 'Create DataSink')}\n </>\n )}\n </Button>\n </PermissionButton>\n </Section>\n </SectionStack>\n </form>\n </div>\n );\n});\n\nexport default DataSinkBuilderPage;\n"],"mappings":"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"}
1
+ {"version":3,"file":"DataSinkBuilderPage.js","names":[],"sources":["../../../src/bigconsole/pages/DataSinkBuilderPage.tsx"],"sourcesContent":["/**\n * DataSink Builder Page\n *\n * Simplified page for creating and editing DataSinks.\n * DataSinks are now standalone - workflows push data to them via unique keys.\n * Required fields: name, key\n */\n\nimport { memo, useState, useMemo, useEffect, useCallback } from 'react';\nimport { useParams } from 'react-router';\nimport { useAppNavigate } from '../contexts';\nimport { isNative, nativeCopyText, nativeToast } from '../../utils/nativeBridge';\nimport { useDataSinkOperations } from '../hooks/useDataSinkOperations';\nimport { loadBigConsoleSettings } from '../hooks/useBigConsoleSettings';\nimport { CacheTTLSelector } from '../components/datasink/CacheTTLSelector';\nimport { RefreshTypeSelector } from '../components/datasink/RefreshTypeSelector';\nimport type { CreateDataSinkInput, UpdateDataSinkInput, DataSinkRefreshType } from '../types';\n\n// fe-libs UI components\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { Textarea } from '@burdenoff/fe-libs/ui';\nimport { Label } from '@burdenoff/fe-libs/ui';\nimport { IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\n\n// Section-emphasis primitives (BOFF-5632)\nimport { Section, SectionStack } from '../components/common';\n\n// Lucide icons\nimport { ArrowLeft, Save, Loader2, AlertCircle, Database, Settings, Eye, Copy, Check, ListChecks } from 'lucide-react';\n\n// RBAC\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useUnsavedChanges } from '@burdenoff/fe-libs/shared/hooks';\nimport { AccessDenied, PermissionButton } from '@burdenoff/fe-libs/shared/components';\nimport { BIGCONSOLE_PERMISSIONS } from '../../constants/permissions';\nimport { reportBigConsoleQuotaError } from '../utils/quota';\nimport { isDirty } from '../utils/formDirty';\n\ntype TranslateFn = (key: string, fallback: string, params?: Record<string, string | number>) => string;\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface RefreshConfig {\n type: 'manual' | 'scheduled';\n schedule?: {\n cron: string;\n timezone: string;\n };\n}\n\ninterface FormState {\n name: string;\n key: string;\n description: string;\n ttl: number;\n refresh: RefreshConfig;\n data: string; // JSON string for data payload\n}\n\ninterface FormErrors {\n name?: string;\n key?: string;\n data?: string;\n}\n\n// ============================================================================\n// HELPERS\n// ============================================================================\n\n/**\n * Generate a key from name (slug format)\n */\nfunction generateKey(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '_')\n .replace(/^_+|_+$/g, '')\n .substring(0, 64);\n}\n\n/**\n * Validate form data\n */\nfunction validateForm(form: FormState, t: TranslateFn): FormErrors {\n const errors: FormErrors = {};\n\n if (!form.name.trim()) {\n errors.name = t('bigconsole.dataSinks.builder.validation.nameRequired', 'Name is required');\n } else if (form.name.length < 2) {\n errors.name = t('bigconsole.dataSinks.builder.validation.nameMinLength', 'Name must be at least 2 characters');\n } else if (form.name.length > 100) {\n errors.name = t('bigconsole.dataSinks.builder.validation.nameMaxLength', 'Name must be less than 100 characters');\n }\n\n if (!form.key.trim()) {\n errors.key = t('bigconsole.dataSinks.builder.validation.keyRequired', 'Key is required');\n } else if (!/^[a-z0-9_]+$/.test(form.key)) {\n errors.key = t(\n 'bigconsole.dataSinks.builder.validation.keyFormat',\n 'Key can only contain lowercase letters, numbers, and underscores'\n );\n } else if (form.key.length > 64) {\n errors.key = t('bigconsole.dataSinks.builder.validation.keyMaxLength', 'Key must be less than 64 characters');\n }\n\n // Validate JSON data if provided\n if (form.data && form.data.trim()) {\n try {\n JSON.parse(form.data);\n } catch {\n errors.data = t('bigconsole.dataSinks.builder.validation.invalidJson', 'Invalid JSON format');\n }\n }\n\n return errors;\n}\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const DataSinkBuilderPage = memo(function DataSinkBuilderPage() {\n const { dataSinkId } = useParams<{ dataSinkId?: string }>();\n const navigate = useAppNavigate();\n const { t } = useI18n();\n\n const isEdit = dataSinkId !== 'new' && !!dataSinkId;\n\n // RBAC — Save requires UPDATE when editing an existing sink, CREATE when\n // creating a new one. In edit mode the page also requires READ to be viewed.\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const canRead = hasPermission(BIGCONSOLE_PERMISSIONS.DATASINK_READ);\n const savePermission = isEdit ? BIGCONSOLE_PERMISSIONS.DATASINK_UPDATE : BIGCONSOLE_PERMISSIONS.DATASINK_CREATE;\n\n // Form state\n const [form, setForm] = useState<FormState>({\n name: '',\n key: '',\n description: '',\n ttl: (() => {\n const defaults = loadBigConsoleSettings();\n return defaults.cacheEnabled ? defaults.cacheTTLSeconds : 0;\n })(),\n refresh: {\n type: 'manual',\n },\n data: '{}', // Default empty JSON object\n });\n // The whole form as first rendered (create; incl. the ttl default read once from the settings) or as loaded (edit;\n // null = clean until it lands). Whole-form compare, so it holds for any `data` seed ('{}' or '').\n const [baseline, setBaseline] = useState<FormState | null>(() => (isEdit ? null : form));\n useUnsavedChanges({\n id: 'datasink-editor',\n label: t('bigconsole.assistant.unsaved.dataSourceForm', 'the data source form'),\n dirty: isDirty(form, baseline),\n });\n const [errors, setErrors] = useState<FormErrors>({});\n const [keyManuallyEdited, setKeyManuallyEdited] = useState(false);\n const [isSaving, setIsSaving] = useState(false);\n const [submitError, setSubmitError] = useState<string | null>(null);\n const [keyCopied, setKeyCopied] = useState(false);\n\n // Data preview state\n const [isLoadingPreview, setIsLoadingPreview] = useState(false);\n const [previewData, setPreviewData] = useState<unknown[] | null>(null);\n const [previewError, setPreviewError] = useState<string | null>(null);\n\n // Operations\n const { loading, error, dataSinks, fetchDataSink, createDataSink, updateDataSink, getDataSinkData } =\n useDataSinkOperations({\n skipFetch: true,\n });\n\n // Get existing data sink if editing\n const existingDataSink = isEdit ? dataSinks.find((ds) => ds.id === dataSinkId) : null;\n\n // Load existing data sink for editing\n useEffect(() => {\n if (isEdit && dataSinkId && !existingDataSink) {\n fetchDataSink(dataSinkId);\n }\n }, [isEdit, dataSinkId, existingDataSink, fetchDataSink]);\n\n // Track if form has been initialized\n const [formInitialized, setFormInitialized] = useState(false);\n\n // Populate form with existing data when editing (only once)\n useEffect(() => {\n if (existingDataSink && !formInitialized) {\n // Format existing data as pretty JSON string\n let dataString = '';\n if (existingDataSink.data) {\n try {\n // Check if data is already a string (JSON string from API)\n if (typeof existingDataSink.data === 'string') {\n // Parse and re-stringify to ensure proper formatting\n const parsed = JSON.parse(existingDataSink.data);\n dataString = JSON.stringify(parsed, null, 2);\n } else {\n // It's an object, just stringify it\n dataString = JSON.stringify(existingDataSink.data, null, 2);\n }\n } catch {\n // If parsing fails, use as-is if string, otherwise empty\n dataString = typeof existingDataSink.data === 'string' ? existingDataSink.data : '';\n }\n }\n\n const seeded: FormState = {\n name: existingDataSink.name || '',\n key: existingDataSink.key || '',\n description: existingDataSink.description || '',\n ttl: existingDataSink.ttl ?? 300,\n refresh: existingDataSink.refresh\n ? {\n type: existingDataSink.refresh.type === 'scheduled' ? 'scheduled' : 'manual',\n schedule: existingDataSink.refresh.schedule\n ? {\n cron: existingDataSink.refresh.schedule.cron,\n timezone: existingDataSink.refresh.schedule.timezone,\n }\n : undefined,\n }\n : { type: 'manual' },\n data: dataString,\n };\n setForm(seeded);\n setBaseline(seeded);\n setKeyManuallyEdited(true); // Don't auto-generate key when editing\n setFormInitialized(true); // Mark as initialized\n setErrors({}); // Clear any errors\n }\n }, [existingDataSink, formInitialized]);\n\n // Auto-generate key from name\n const handleNameChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const name = e.target.value;\n setForm((prev) => ({\n ...prev,\n name,\n key: keyManuallyEdited ? prev.key : generateKey(name),\n }));\n setErrors((prev) => ({ ...prev, name: undefined }));\n },\n [keyManuallyEdited]\n );\n\n // Handle key change\n const handleKeyChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const key = e.target.value.toLowerCase().replace(/[^a-z0-9_]/g, '');\n setForm((prev) => ({ ...prev, key }));\n setKeyManuallyEdited(true);\n setErrors((prev) => ({ ...prev, key: undefined }));\n }, []);\n\n // Handle description change\n const handleDescriptionChange = useCallback((e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setForm((prev) => ({ ...prev, description: e.target.value }));\n }, []);\n\n // Handle TTL change\n const handleTTLChange = useCallback((ttl: number | null) => {\n setForm((prev) => ({ ...prev, ttl: ttl || 0 }));\n }, []);\n\n // Handle refresh config change\n const handleRefreshChange = useCallback((config: RefreshConfig) => {\n setForm((prev) => ({ ...prev, refresh: config }));\n }, []);\n\n // Handle data change\n const handleDataChange = useCallback((e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setForm((prev) => ({ ...prev, data: e.target.value }));\n setErrors((prev) => ({ ...prev, data: undefined }));\n }, []);\n\n // Format JSON data\n const handleFormatData = useCallback(() => {\n try {\n const parsed = JSON.parse(form.data);\n setForm((prev) => ({ ...prev, data: JSON.stringify(parsed, null, 2) }));\n setErrors((prev) => ({ ...prev, data: undefined }));\n } catch {\n setErrors((prev) => ({\n ...prev,\n data: t('bigconsole.dataSinks.builder.validation.invalidJson', 'Invalid JSON format'),\n }));\n }\n }, [form.data, t]);\n\n // Copy key to clipboard\n const handleCopyKey = useCallback(async () => {\n if (form.key) {\n await nativeCopyText(form.key);\n setKeyCopied(true);\n if (isNative()) void nativeToast(t('bigconsole.dataSinks.builder.toolbar.keyCopied', 'Key copied'));\n setTimeout(() => setKeyCopied(false), 2000);\n }\n }, [form.key, t]);\n\n // Handle back navigation\n const handleBack = useCallback(() => {\n navigate('/datasinks');\n }, [navigate]);\n\n // Load data preview\n const handleShowData = useCallback(async () => {\n if (!isEdit || !existingDataSink) return;\n\n setIsLoadingPreview(true);\n setPreviewError(null);\n\n try {\n const result = await getDataSinkData({ key: existingDataSink.key });\n if (result?.raw) {\n // Get first 20 items if it's an array, otherwise wrap in array\n const data = Array.isArray(result.raw) ? result.raw.slice(0, 20) : [result.raw];\n setPreviewData(data);\n } else {\n setPreviewData([]);\n }\n } catch (err) {\n setPreviewError(\n err instanceof Error\n ? err.message\n : t('bigconsole.dataSinks.builder.errors.loadDataFailed', 'Failed to load data')\n );\n } finally {\n setIsLoadingPreview(false);\n }\n }, [isEdit, existingDataSink, getDataSinkData, t]);\n\n // Handle form submission\n const handleSubmit = useCallback(\n async (e: React.FormEvent) => {\n e.preventDefault();\n setSubmitError(null);\n\n // Validate form\n const validationErrors = validateForm(form, t);\n if (Object.keys(validationErrors).length > 0) {\n setErrors(validationErrors);\n return;\n }\n\n setIsSaving(true);\n try {\n // Parse data JSON\n let parsedData: Record<string, unknown> = {};\n if (form.data && form.data.trim()) {\n try {\n parsedData = JSON.parse(form.data) as Record<string, unknown>;\n } catch {\n setErrors((prev) => ({\n ...prev,\n data: t('bigconsole.dataSinks.builder.validation.invalidJson', 'Invalid JSON format'),\n }));\n setIsSaving(false);\n return;\n }\n }\n\n if (isEdit && existingDataSink) {\n // Update existing\n const input: UpdateDataSinkInput = {\n id: existingDataSink.id,\n version: existingDataSink.version,\n name: form.name,\n description: form.description || undefined,\n ttl: form.ttl,\n refresh: {\n type: form.refresh.type as DataSinkRefreshType,\n schedule: form.refresh.schedule,\n },\n data: parsedData, // Include data in update\n };\n const result = await updateDataSink(input);\n if (!result) {\n throw new Error(t('bigconsole.dataSinks.builder.errors.updateFailed', 'Failed to update DataSink'));\n }\n } else {\n // Create new - simplified flow (standalone DataSinks)\n const input: CreateDataSinkInput = {\n key: form.key,\n name: form.name,\n description: form.description || undefined,\n ttl: form.ttl,\n refresh: {\n type: form.refresh.type as DataSinkRefreshType,\n schedule: form.refresh.schedule,\n },\n data: parsedData, // Include data in create\n };\n const result = await createDataSink(input);\n if (!result) {\n throw new Error(t('bigconsole.dataSinks.builder.errors.createFailed', 'Failed to create DataSink'));\n }\n }\n setBaseline(form);\n navigate('/datasinks');\n } catch (err) {\n // A quota refusal opens the billing dialog (for a new org: \"Set up\n // billing\", BOFF-7913) instead of a dead-end error banner. The form\n // keeps its values so the user can retry once billing is set up.\n if (reportBigConsoleQuotaError(err)) {\n return;\n }\n setSubmitError(\n err instanceof Error\n ? err.message\n : t('bigconsole.dataSinks.builder.errors.saveFailed', 'Failed to save DataSink')\n );\n } finally {\n setIsSaving(false);\n }\n },\n [form, isEdit, existingDataSink, createDataSink, updateDataSink, navigate, t]\n );\n\n // Check if form is valid\n const isFormValid = useMemo(() => {\n const nameValid = form.name.trim().length >= 2;\n const keyValid = form.key.trim().length > 0;\n\n // Check JSON validity if data is provided\n let dataValid = true;\n if (form.data && form.data.trim()) {\n try {\n JSON.parse(form.data);\n } catch {\n dataValid = false;\n }\n }\n\n return nameValid && keyValid && dataValid;\n }, [form.name, form.key, form.data]);\n\n // Loading state\n if (loading && isEdit) {\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 if (error) {\n return (\n <div className=\"mx-auto w-full max-w-7xl p-card-padding\">\n <Section\n tone=\"danger\"\n headingLevel={2}\n title={t('bigconsole.dataSinks.builder.errors.loadFailed', '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.builder.header.backToDataSinks', 'Back to DataSinks')}\n </Button>\n }\n />\n </div>\n );\n }\n\n // Read gate — the edit surface requires read access to the existing sink.\n if (isEdit && !permissionsLoading && !canRead) {\n return (\n <AccessDenied\n title={t('bigconsole.dataSinks.builder.accessDenied.title', 'Access Denied')}\n description={t(\n 'bigconsole.dataSinks.builder.accessDenied.description',\n \"You don't have permission to view this data sink.\"\n )}\n />\n );\n }\n\n return (\n <div className=\"mx-auto w-full min-w-0 max-w-7xl p-card-padding\">\n {/* Page header strip */}\n <header className=\"mb-form-gap\">\n <Button onClick={handleBack} variant=\"ghost\" size=\"sm\" className=\"mb-4\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.builder.header.backToDataSinks', 'Back to DataSinks')}\n </Button>\n <h1 className=\"text-2xl font-bold text-text-primary\">\n {isEdit\n ? t('bigconsole.dataSinks.builder.header.editTitle', 'Edit DataSink')\n : t('bigconsole.dataSinks.builder.header.createTitle', 'Create DataSink')}\n </h1>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {isEdit\n ? t('bigconsole.dataSinks.builder.header.editSubtitle', 'Update the DataSink configuration.')\n : t(\n 'bigconsole.dataSinks.builder.header.createSubtitle',\n 'Create a new DataSink to store and cache data. Use the unique key to connect workflows.'\n )}\n </p>\n </header>\n\n <PagePurpose className=\"mb-section-gap\">\n {t(\n 'bigconsole.dataSinks.builder.header.purpose',\n 'A data sink is the named, structured store your dashboards read from. Give it a unique key, configure how long data is cached and how it refreshes, then point a workflow at that key to push data in. Get the basics right here and everything downstream connects to it.'\n )}\n </PagePurpose>\n\n {/* Submit failure — a status section, not a hand-rolled tinted div. */}\n {submitError && (\n <Section\n tone=\"danger\"\n headingLevel={2}\n title={t('bigconsole.dataSinks.builder.errors.saveFailed', 'Failed to save DataSink')}\n description={submitError}\n icon={<AlertCircle className=\"h-icon-sm w-icon-sm\" />}\n className=\"mb-section-gap\"\n />\n )}\n\n {/* Form */}\n <form data-tour=\"bigconsole-datasink-builder\" onSubmit={handleSubmit}>\n <SectionStack>\n {/* The point of this route: the sink's identity. */}\n <Section\n emphasis=\"primary\"\n headingLevel={2}\n title={t('bigconsole.dataSinks.builder.basicInfo.title', 'Basic Information')}\n description={t('bigconsole.dataSinks.builder.basicInfo.subtitle', 'Essential details for your DataSink')}\n icon={<Database className=\"h-icon-sm w-icon-sm\" />}\n bodyClassName=\"grid gap-form-gap md:grid-cols-2\"\n >\n <>\n {/* Name field */}\n <div className=\"space-y-2\">\n <Label htmlFor=\"name\">\n {t('bigconsole.dataSinks.builder.basicInfo.nameLabel', 'Name')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </Label>\n <Input\n id=\"name\"\n type=\"text\"\n value={form.name}\n onChange={handleNameChange}\n placeholder={t('bigconsole.dataSinks.builder.basicInfo.namePlaceholder', 'e.g., Sales Metrics')}\n className={errors.name ? 'border-status-error-border' : ''}\n />\n {errors.name && <p className=\"text-xs text-status-error-text\">{errors.name}</p>}\n </div>\n\n {/* Key field */}\n <div className=\"space-y-2\">\n <Label htmlFor=\"key\">\n {t('bigconsole.dataSinks.builder.basicInfo.keyLabel', 'Unique Key')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </Label>\n <div className=\"flex gap-2\">\n <Input\n id=\"key\"\n type=\"text\"\n value={form.key}\n onChange={handleKeyChange}\n placeholder={t('bigconsole.dataSinks.builder.basicInfo.keyPlaceholder', 'sales_metrics')}\n disabled={isEdit}\n className={`font-mono flex-1 ${errors.key ? 'border-status-error-border' : ''}`}\n />\n {form.key && (\n <Button\n type=\"button\"\n onClick={handleCopyKey}\n aria-label={t('bigconsole.dataSinks.builder.basicInfo.copyKey', 'Copy unique key')}\n variant=\"outline\"\n size=\"sm\"\n className=\"px-3\"\n >\n {keyCopied ? (\n <Check className=\"w-4 h-4 text-status-success-text\" />\n ) : (\n <Copy className=\"w-4 h-4\" />\n )}\n </Button>\n )}\n </div>\n {errors.key && <p className=\"text-xs text-status-error-text\">{errors.key}</p>}\n <p className=\"text-xs text-text-muted\">\n {isEdit\n ? t(\n 'bigconsole.dataSinks.builder.basicInfo.keyHelpEdit',\n 'Key cannot be changed. Use this key in your workflows to push data.'\n )\n : t(\n 'bigconsole.dataSinks.builder.basicInfo.keyHelpCreate',\n 'Auto-generated from name. This key will be used by workflows to push data.'\n )}\n </p>\n </div>\n\n {/* Description field */}\n <div className=\"space-y-2 md:col-span-2\">\n <Label htmlFor=\"description\">\n {t('bigconsole.dataSinks.builder.basicInfo.descriptionLabel', 'Description')}\n </Label>\n <Textarea\n id=\"description\"\n value={form.description}\n onChange={handleDescriptionChange}\n placeholder={t(\n 'bigconsole.dataSinks.builder.basicInfo.descriptionPlaceholder',\n 'Describe what data this sink stores...'\n )}\n rows={2}\n className=\"resize-none\"\n />\n </div>\n </>\n </Section>\n\n {/* Configuration */}\n <Section\n headingLevel={2}\n title={t('bigconsole.dataSinks.builder.config.title', 'Configuration')}\n description={t('bigconsole.dataSinks.builder.config.subtitle', 'Cache and refresh settings')}\n icon={<Settings className=\"h-icon-sm w-icon-sm\" />}\n bodyClassName=\"grid gap-form-gap md:grid-cols-2\"\n >\n <>\n {/* Cache TTL — the field label lives here, so the selector's own\n heading is suppressed to avoid a duplicated label. */}\n <div className=\"space-y-2\">\n <Label>{t('bigconsole.dataSinks.builder.config.cacheDurationLabel', 'Cache Duration')}</Label>\n <CacheTTLSelector value={form.ttl} onChange={handleTTLChange} hideLabel />\n <p className=\"text-xs text-text-muted\">\n {t(\n 'bigconsole.dataSinks.builder.config.cacheDurationHelp',\n 'How long cached data remains valid before requiring refresh.'\n )}\n </p>\n </div>\n\n {/* Refresh Type */}\n <RefreshTypeSelector value={form.refresh} onChange={handleRefreshChange} />\n </>\n </Section>\n\n {/* Data Payload */}\n <Section\n headingLevel={2}\n title={t('bigconsole.dataSinks.builder.dataPayload.title', 'Data Payload')}\n description={\n isEdit\n ? t(\n 'bigconsole.dataSinks.builder.dataPayload.subtitleEdit',\n 'Edit the JSON data stored in this DataSink'\n )\n : t('bigconsole.dataSinks.builder.dataPayload.subtitleCreate', 'Optional initial data (JSON format)')\n }\n icon={<Database className=\"h-icon-sm w-icon-sm\" />}\n actions={\n <Button type=\"button\" onClick={handleFormatData} variant=\"outline\" size=\"sm\">\n {t('bigconsole.dataSinks.builder.dataPayload.formatJson', 'Format JSON')}\n </Button>\n }\n bodyClassName=\"space-y-2\"\n >\n <>\n <Textarea\n aria-label={t('bigconsole.dataSinks.builder.dataPayload.title', 'Data Payload')}\n value={form.data}\n onChange={handleDataChange}\n placeholder={t('bigconsole.dataSinks.builder.dataPayload.dataPlaceholder', '{\"key\": \"value\"}')}\n rows={10}\n className={`resize-y font-mono text-xs ${errors.data ? 'border-status-error-border' : ''}`}\n />\n {errors.data && <p className=\"text-xs text-status-error-text\">{errors.data}</p>}\n <p className=\"text-xs text-text-muted\">\n {t(\n 'bigconsole.dataSinks.builder.dataPayload.help',\n 'Enter valid JSON data. This data will be stored and can be accessed by widgets via parsers.'\n )}\n </p>\n </>\n </Section>\n\n {/* Data Preview — read-only inspector, so it sits below the editable\n sections at `muted`, not level with them. */}\n {isEdit && existingDataSink && (\n <Section\n emphasis=\"muted\"\n headingLevel={2}\n title={t('bigconsole.dataSinks.builder.preview.title', 'Data Preview')}\n description={t('bigconsole.dataSinks.builder.preview.subtitle', 'Preview the first 20 records')}\n icon={<Eye className=\"h-icon-sm w-icon-sm\" />}\n actions={\n <Button type=\"button\" onClick={handleShowData} variant=\"outline\" size=\"sm\" disabled={isLoadingPreview}>\n {isLoadingPreview ? (\n <>\n <Loader2 className=\"w-4 h-4 mr-2 animate-spin\" />\n {t('bigconsole.dataSinks.builder.preview.loading', 'Loading...')}\n </>\n ) : (\n <>\n <Eye className=\"w-4 h-4 mr-2\" />\n {t('bigconsole.dataSinks.builder.preview.showData', 'Show Data')}\n </>\n )}\n </Button>\n }\n >\n {previewError ? (\n <Section tone=\"danger\" padding=\"compact\" headingLevel={3} title=\"Could not load the preview\">\n <p className=\"text-sm text-status-error-text\">{previewError}</p>\n </Section>\n ) : previewData && previewData.length > 0 ? (\n <pre className=\"max-h-[300px] min-w-0 overflow-auto rounded-input bg-bg-surface p-3 font-mono text-xs\">\n {JSON.stringify(previewData, null, 2)}\n </pre>\n ) : previewData ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title={t('bigconsole.dataSinks.builder.preview.emptyTitle', 'No data available yet')}\n description={t(\n 'bigconsole.dataSinks.builder.preview.emptyDescription',\n \"Connect a workflow to this sink's key to start pushing data.\"\n )}\n />\n ) : (\n <p className=\"text-sm text-text-secondary\">\n Select &quot;Show data&quot; to load the records this sink currently holds.\n </p>\n )}\n </Section>\n )}\n\n {/* Guidance sits before the commit row — it is no longer advice that\n appears after the action which ends the task. */}\n {!isEdit && (\n <Section\n tone=\"info\"\n emphasis=\"muted\"\n headingLevel={2}\n title={t('bigconsole.dataSinks.builder.whatsNext.title', \"What's Next?\")}\n icon={<ListChecks className=\"h-icon-sm w-icon-sm\" />}\n >\n <ol className=\"list-inside list-decimal space-y-1 text-xs text-text-secondary\">\n <li>\n {t('bigconsole.dataSinks.builder.whatsNext.step1', 'Create this DataSink to get your unique key')}\n </li>\n <li>\n {t('bigconsole.dataSinks.builder.whatsNext.step2Prefix', 'Go to')}{' '}\n <strong>{t('bigconsole.dataSinks.builder.whatsNext.workflows', 'Workflows')}</strong>{' '}\n {t('bigconsole.dataSinks.builder.whatsNext.step2Suffix', 'and create a FluidGrids workflow')}\n </li>\n <li>\n {t(\n 'bigconsole.dataSinks.builder.whatsNext.step3',\n 'Use the unique key in your workflow to push data to this DataSink'\n )}\n </li>\n <li>\n {t('bigconsole.dataSinks.builder.whatsNext.step4Prefix', 'Create')}{' '}\n <strong>{t('bigconsole.dataSinks.builder.whatsNext.parsers', 'Parsers')}</strong>{' '}\n {t('bigconsole.dataSinks.builder.whatsNext.step4Suffix', 'to transform the data using JQ or JSONata')}\n </li>\n </ol>\n </Section>\n )}\n\n {/* Commit row — structural strip with a rule so the actions zone reads\n as the end of the form. */}\n <Section\n emphasis=\"bare\"\n padding=\"none\"\n aria-label=\"Save or discard this data sink\"\n className=\"border-t border-[var(--color-border-subtle)] pt-form-gap\"\n bodyClassName=\"flex flex-wrap items-center justify-end gap-control-gap\"\n >\n <Button type=\"button\" onClick={handleBack} variant=\"secondary\">\n {t('bigconsole.dataSinks.builder.actions.cancel', 'Cancel')}\n </Button>\n <PermissionButton permission={savePermission} deniedBehavior=\"disable\">\n <Button type=\"submit\" disabled={!isFormValid || isSaving} variant=\"default\">\n {isSaving ? (\n <>\n <Loader2 className=\"w-4 h-4 mr-2 animate-spin\" />\n {t('bigconsole.dataSinks.builder.actions.saving', 'Saving...')}\n </>\n ) : (\n <>\n <Save className=\"w-4 h-4 mr-2\" />\n {isEdit\n ? t('bigconsole.dataSinks.builder.actions.saveChanges', 'Save Changes')\n : t('bigconsole.dataSinks.builder.actions.create', 'Create DataSink')}\n </>\n )}\n </Button>\n </PermissionButton>\n </Section>\n </SectionStack>\n </form>\n </div>\n );\n});\n\nexport default DataSinkBuilderPage;\n"],"mappings":"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"}
@@ -25,8 +25,8 @@ import { AccessDenied as ge, PermissionButton as d } from "@burdenoff/fe-libs/sh
25
25
  import { usePermissions as _e } from "@burdenoff/fe-libs/shared/providers/shell";
26
26
  import { AlertCircle as ve, ArrowLeft as f, Bell as ye, Code as be, Database as p, Download as xe, Edit as Se, Eye as Ce, EyeOff as we, Grid3X3 as Te, Loader2 as m, RefreshCw as Ee, Trash2 as De, Upload as h } from "lucide-react";
27
27
  import { Button as g, IllustratedEmptyState as Oe, NextSteps as ke, PagePurpose as Ae } from "@burdenoff/fe-libs/ui";
28
- import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
29
28
  import { useI18n as je } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
29
+ import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
30
30
  import { formatDistanceToNow as b } from "date-fns";
31
31
  //#region src/bigconsole/pages/DataSinkViewPage.tsx
32
32
  var x = "focus-visible:ring-inset focus-visible:ring-offset-0", S = c(function() {
@@ -20,9 +20,9 @@ import { AccessDenied as ue, PermissionButton as de } from "@burdenoff/fe-libs/s
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
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";
23
+ import { useI18n as Ne } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
23
24
  import { getProfileScopedKey as v } from "@burdenoff/fe-libs/shared/utils";
24
25
  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) => {
@@ -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 { jsx as n } from "react/jsx-runtime";
5
- import { useI18n as r } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
4
+ import { useI18n as n } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
5
+ import { jsx as r } from "react/jsx-runtime";
6
6
  //#region src/bigconsole/pages/DataSourcesPage.tsx
7
7
  function i() {
8
- let i = e(), { t: a } = r();
8
+ let i = e(), { t: a } = n();
9
9
  return t(() => {
10
10
  i("/datasinks", { replace: !0 });
11
- }, []), /* @__PURE__ */ n("div", {
11
+ }, []), /* @__PURE__ */ r("div", {
12
12
  className: "p-card-padding",
13
- children: /* @__PURE__ */ n("p", {
13
+ children: /* @__PURE__ */ r("p", {
14
14
  role: "status",
15
15
  "aria-live": "polite",
16
16
  className: "text-sm text-text-secondary",