@burdenoff/microfe-bigconsole 2026.625.1 → 2026.626.2
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 +176 -119
- package/dist/bigconsole/BigConsoleRoutes.js.map +1 -1
- package/dist/bigconsole/assistant/index.js +3 -2
- package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
- package/dist/bigconsole/pages/DataParsersPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinksPage.js.map +1 -1
- package/dist/bigconsole/pages/HomePage.js.map +1 -1
- package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
- package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/ParserViewPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelineViewPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelinesPage.js.map +1 -1
- package/dist/bigconsole/pages/SettingsPage.js.map +1 -1
- package/dist/bigconsole/pages/WidgetDemoPage.js.map +1 -1
- package/dist/bigconsole/pages/WorkflowViewPage.js.map +1 -1
- package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -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-dom';\nimport { useAppNavigate } from '../contexts';\nimport { isNative, nativeCopyText, nativeToast } from '../../utils/nativeBridge';\nimport { useDataSinkOperations } from '../hooks/useDataSinkOperations';\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 { Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport { GlassCard, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\n\n// Lucide icons\nimport { ArrowLeft, Save, Loader2, AlertCircle, Database, Settings, Eye, Copy, Check } from 'lucide-react';\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): FormErrors {\n const errors: FormErrors = {};\n\n if (!form.name.trim()) {\n errors.name = 'Name is required';\n } else if (form.name.length < 2) {\n errors.name = 'Name must be at least 2 characters';\n } else if (form.name.length > 100) {\n errors.name = 'Name must be less than 100 characters';\n }\n\n if (!form.key.trim()) {\n errors.key = 'Key is required';\n } else if (!/^[a-z0-9_]+$/.test(form.key)) {\n errors.key = 'Key can only contain lowercase letters, numbers, and underscores';\n } else if (form.key.length > 64) {\n errors.key = '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 = '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\n const isEdit = dataSinkId !== 'new' && !!dataSinkId;\n\n // Form state\n const [form, setForm] = useState<FormState>({\n name: '',\n key: '',\n description: '',\n ttl: 300, // 5 minutes default\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) => ({ ...prev, data: 'Invalid JSON format' }));\n }\n }, [form.data]);\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('Key copied');\n setTimeout(() => setKeyCopied(false), 2000);\n }\n }, [form.key]);\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(err instanceof Error ? err.message : 'Failed to load data');\n } finally {\n setIsLoadingPreview(false);\n }\n }, [isEdit, existingDataSink, getDataSinkData]);\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);\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) => ({ ...prev, data: 'Invalid JSON format' }));\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('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('Failed to create DataSink');\n }\n }\n navigate('/datasinks');\n } catch (err) {\n setSubmitError(err instanceof Error ? err.message : 'Failed to save DataSink');\n } finally {\n setIsSaving(false);\n }\n },\n [form, isEdit, existingDataSink, createDataSink, updateDataSink, navigate]\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 items-center justify-center min-h-[400px]\">\n <Loader2 className=\"w-8 h-8 text-text-secondary animate-spin\" />\n </div>\n );\n }\n\n // Error state\n if (error) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px] p-card-padding\">\n <div className=\"text-center\">\n <AlertCircle className=\"w-12 h-12 text-state-error mx-auto mb-spacing-md\" />\n <p className=\"text-state-error text-body-sm font-medium mb-spacing-sm\">Failed to load DataSink</p>\n <p className=\"text-text-tertiary text-body-xs\">{error.message}</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"min-h-screen bg-bg-canvas\">\n <div className=\"max-w-3xl mx-auto p-card-padding\">\n {/* Header */}\n <div className=\"mb-spacing-lg\">\n <Button onClick={handleBack} variant=\"ghost\" size=\"sm\" className=\"mb-spacing-md\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n Back to DataSinks\n </Button>\n <h1 className=\"text-heading-h1 font-bold text-text-primary\">\n {isEdit ? 'Edit DataSink' : 'Create DataSink'}\n </h1>\n <p className=\"text-body-sm text-text-secondary mt-spacing-xs\">\n {isEdit\n ? 'Update the DataSink configuration.'\n : 'Create a new DataSink to store and cache data. Use the unique key to connect workflows.'}\n </p>\n </div>\n\n {/* Error Alert */}\n {submitError && (\n <div className=\"mb-spacing-lg p-4 bg-state-error/10 border border-state-error/30 rounded-lg flex items-start gap-3\">\n <AlertCircle className=\"w-5 h-5 text-state-error flex-shrink-0 mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium text-state-error\">Failed to save DataSink</p>\n <p className=\"text-xs text-state-error/80 mt-1\">{submitError}</p>\n </div>\n </div>\n )}\n\n <PagePurpose className=\"mb-spacing-lg\">\n A data sink is the named, structured store your dashboards read from. Give it a unique\n key, configure how long data is cached and how it refreshes, then point a workflow at\n that key to push data in. Get the basics right here and everything downstream connects to it.\n </PagePurpose>\n\n {/* Form */}\n <form onSubmit={handleSubmit} className=\"space-y-spacing-lg\">\n {/* Basic Information — primary emphasis zone */}\n <GlassCard treatment=\"glass\" glow>\n <CardHeader className=\"pb-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"w-8 h-8 rounded-full bg-action-primary-bg/10 flex items-center justify-center\">\n <Database className=\"w-4 h-4 text-action-primary-bg\" />\n </div>\n <div>\n <CardTitle className=\"text-base\">Basic Information</CardTitle>\n <p className=\"text-xs text-text-secondary mt-0.5\">Essential details for your DataSink</p>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-5\">\n {/* Name field */}\n <div className=\"space-y-spacing-sm\">\n <Label htmlFor=\"name\">\n Name <span className=\"text-state-error\">*</span>\n </Label>\n <Input\n id=\"name\"\n type=\"text\"\n value={form.name}\n onChange={handleNameChange}\n placeholder=\"e.g., Sales Metrics\"\n className={errors.name ? 'border-state-error' : ''}\n />\n {errors.name && <p className=\"text-body-xs text-state-error\">{errors.name}</p>}\n </div>\n\n {/* Key field */}\n <div className=\"space-y-spacing-sm\">\n <Label htmlFor=\"key\">\n Unique Key <span className=\"text-state-error\">*</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=\"sales_metrics\"\n disabled={isEdit}\n className={`font-mono flex-1 ${errors.key ? 'border-state-error' : ''}`}\n />\n {form.key && (\n <Button type=\"button\" onClick={handleCopyKey} variant=\"outline\" size=\"sm\" className=\"px-3\">\n {keyCopied ? <Check className=\"w-4 h-4 text-state-success\" /> : <Copy className=\"w-4 h-4\" />}\n </Button>\n )}\n </div>\n {errors.key && <p className=\"text-body-xs text-state-error\">{errors.key}</p>}\n <p className=\"text-body-xs text-text-tertiary\">\n {isEdit\n ? 'Key cannot be changed. Use this key in your workflows to push data.'\n : 'Auto-generated from name. This key will be used by workflows to push data.'}\n </p>\n </div>\n\n {/* Description field */}\n <div className=\"space-y-spacing-sm\">\n <Label htmlFor=\"description\">Description</Label>\n <Textarea\n id=\"description\"\n value={form.description}\n onChange={handleDescriptionChange}\n placeholder=\"Describe what data this sink stores...\"\n rows={2}\n className=\"resize-none\"\n />\n </div>\n </CardContent>\n </GlassCard>\n\n {/* Configuration */}\n <Card>\n <CardHeader className=\"pb-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"w-8 h-8 rounded-full bg-action-primary-bg/10 flex items-center justify-center\">\n <Settings className=\"w-4 h-4 text-action-primary-bg\" />\n </div>\n <div>\n <CardTitle className=\"text-base\">Configuration</CardTitle>\n <p className=\"text-xs text-text-secondary mt-0.5\">Cache and refresh settings</p>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-5\">\n {/* Cache TTL */}\n <div className=\"space-y-spacing-sm\">\n <Label>Cache Duration</Label>\n <CacheTTLSelector value={form.ttl} onChange={handleTTLChange} />\n <p className=\"text-body-xs text-text-tertiary\">\n How long cached data remains valid before requiring refresh.\n </p>\n </div>\n\n {/* Refresh Type */}\n <RefreshTypeSelector value={form.refresh} onChange={handleRefreshChange} />\n </CardContent>\n </Card>\n\n {/* Data Payload */}\n <Card>\n <CardHeader className=\"pb-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"w-8 h-8 rounded-full bg-action-primary-bg/10 flex items-center justify-center\">\n <Database className=\"w-4 h-4 text-action-primary-bg\" />\n </div>\n <div>\n <CardTitle className=\"text-base\">Data Payload</CardTitle>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {isEdit ? 'Edit the JSON data stored in this DataSink' : 'Optional initial data (JSON format)'}\n </p>\n </div>\n </div>\n <Button type=\"button\" onClick={handleFormatData} variant=\"outline\" size=\"sm\">\n Format JSON\n </Button>\n </div>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-spacing-sm\">\n <Textarea\n value={form.data}\n onChange={handleDataChange}\n placeholder='{\"key\": \"value\"}'\n rows={10}\n className={`font-mono text-xs resize-y ${errors.data ? 'border-state-error' : ''}`}\n />\n {errors.data && <p className=\"text-body-xs text-state-error\">{errors.data}</p>}\n <p className=\"text-body-xs text-text-tertiary\">\n Enter valid JSON data. This data will be stored and can be accessed by widgets via parsers.\n </p>\n </div>\n </CardContent>\n </Card>\n\n {/* Data Preview - Only show for existing DataSinks */}\n {isEdit && existingDataSink && (\n <Card>\n <CardHeader className=\"pb-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"w-8 h-8 rounded-full bg-action-primary-bg/10 flex items-center justify-center\">\n <Eye className=\"w-4 h-4 text-action-primary-bg\" />\n </div>\n <div>\n <CardTitle className=\"text-base\">Data Preview</CardTitle>\n <p className=\"text-xs text-text-secondary mt-0.5\">Preview the first 20 records</p>\n </div>\n </div>\n <Button\n type=\"button\"\n onClick={handleShowData}\n variant=\"outline\"\n size=\"sm\"\n disabled={isLoadingPreview}\n >\n {isLoadingPreview ? (\n <>\n <Loader2 className=\"w-4 h-4 mr-2 animate-spin\" />\n Loading...\n </>\n ) : (\n <>\n <Eye className=\"w-4 h-4 mr-2\" />\n Show Data\n </>\n )}\n </Button>\n </div>\n </CardHeader>\n {(previewData || previewError) && (\n <CardContent>\n {previewError ? (\n <div className=\"p-4 bg-state-error/10 border border-state-error/30 rounded-md\">\n <p className=\"text-sm text-state-error\">{previewError}</p>\n </div>\n ) : previewData && previewData.length > 0 ? (\n <pre className=\"p-4 bg-bg-sunken rounded-md overflow-auto max-h-[300px] text-xs font-mono\">\n {JSON.stringify(previewData, null, 2)}\n </pre>\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No data available yet\"\n description=\"Connect a workflow to this sink's key to start pushing data.\"\n />\n )}\n </CardContent>\n )}\n </Card>\n )}\n\n {/* Submit */}\n <div className=\"flex items-center justify-end gap-spacing-md pt-spacing-md\">\n <Button type=\"button\" onClick={handleBack} variant=\"secondary\">\n Cancel\n </Button>\n <Button type=\"submit\" disabled={!isFormValid || isSaving} variant=\"default\">\n {isSaving ? (\n <>\n <Loader2 className=\"w-4 h-4 mr-2 animate-spin\" />\n Saving...\n </>\n ) : (\n <>\n <Save className=\"w-4 h-4 mr-2\" />\n {isEdit ? 'Save Changes' : 'Create DataSink'}\n </>\n )}\n </Button>\n </div>\n </form>\n\n {/* Info Box for New DataSinks */}\n {!isEdit && (\n <div className=\"mt-spacing-lg p-4 bg-bg-sunken rounded-lg border border-border-default\">\n <h3 className=\"text-sm font-medium text-text-primary mb-2\">What's Next?</h3>\n <ol className=\"list-decimal list-inside text-xs text-text-secondary space-y-1\">\n <li>Create this DataSink to get your unique key</li>\n <li>\n Go to <strong>Workflows</strong> and create a FluidGrids workflow\n </li>\n <li>Use the unique key in your workflow to push data to this DataSink</li>\n <li>\n Create <strong>Parsers</strong> to transform the data using JQ or JSONata\n </li>\n </ol>\n </div>\n )}\n </div>\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-dom';\nimport { useAppNavigate } from '../contexts';\nimport { isNative, nativeCopyText, nativeToast } from '../../utils/nativeBridge';\nimport { useDataSinkOperations } from '../hooks/useDataSinkOperations';\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 { Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport { GlassCard, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\n\n// Lucide icons\nimport { ArrowLeft, Save, Loader2, AlertCircle, Database, Settings, Eye, Copy, Check } from 'lucide-react';\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): FormErrors {\n const errors: FormErrors = {};\n\n if (!form.name.trim()) {\n errors.name = 'Name is required';\n } else if (form.name.length < 2) {\n errors.name = 'Name must be at least 2 characters';\n } else if (form.name.length > 100) {\n errors.name = 'Name must be less than 100 characters';\n }\n\n if (!form.key.trim()) {\n errors.key = 'Key is required';\n } else if (!/^[a-z0-9_]+$/.test(form.key)) {\n errors.key = 'Key can only contain lowercase letters, numbers, and underscores';\n } else if (form.key.length > 64) {\n errors.key = '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 = '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\n const isEdit = dataSinkId !== 'new' && !!dataSinkId;\n\n // Form state\n const [form, setForm] = useState<FormState>({\n name: '',\n key: '',\n description: '',\n ttl: 300, // 5 minutes default\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) => ({ ...prev, data: 'Invalid JSON format' }));\n }\n }, [form.data]);\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('Key copied');\n setTimeout(() => setKeyCopied(false), 2000);\n }\n }, [form.key]);\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(err instanceof Error ? err.message : 'Failed to load data');\n } finally {\n setIsLoadingPreview(false);\n }\n }, [isEdit, existingDataSink, getDataSinkData]);\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);\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) => ({ ...prev, data: 'Invalid JSON format' }));\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('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('Failed to create DataSink');\n }\n }\n navigate('/datasinks');\n } catch (err) {\n setSubmitError(err instanceof Error ? err.message : 'Failed to save DataSink');\n } finally {\n setIsSaving(false);\n }\n },\n [form, isEdit, existingDataSink, createDataSink, updateDataSink, navigate]\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 items-center justify-center min-h-[400px]\">\n <Loader2 className=\"w-8 h-8 text-text-secondary animate-spin\" />\n </div>\n );\n }\n\n // Error state\n if (error) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px] p-card-padding\">\n <div className=\"text-center\">\n <AlertCircle className=\"w-12 h-12 text-state-error mx-auto mb-spacing-md\" />\n <p className=\"text-state-error text-body-sm font-medium mb-spacing-sm\">Failed to load DataSink</p>\n <p className=\"text-text-tertiary text-body-xs\">{error.message}</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"min-h-screen bg-bg-canvas\">\n <div className=\"max-w-3xl mx-auto p-card-padding\">\n {/* Header */}\n <div className=\"mb-spacing-lg\">\n <Button onClick={handleBack} variant=\"ghost\" size=\"sm\" className=\"mb-spacing-md\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n Back to DataSinks\n </Button>\n <h1 className=\"text-heading-h1 font-bold text-text-primary\">\n {isEdit ? 'Edit DataSink' : 'Create DataSink'}\n </h1>\n <p className=\"text-body-sm text-text-secondary mt-spacing-xs\">\n {isEdit\n ? 'Update the DataSink configuration.'\n : 'Create a new DataSink to store and cache data. Use the unique key to connect workflows.'}\n </p>\n </div>\n\n {/* Error Alert */}\n {submitError && (\n <div className=\"mb-spacing-lg p-4 bg-state-error/10 border border-state-error/30 rounded-lg flex items-start gap-3\">\n <AlertCircle className=\"w-5 h-5 text-state-error flex-shrink-0 mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium text-state-error\">Failed to save DataSink</p>\n <p className=\"text-xs text-state-error/80 mt-1\">{submitError}</p>\n </div>\n </div>\n )}\n\n <PagePurpose className=\"mb-spacing-lg\">\n A data sink is the named, structured store your dashboards read from. Give it a unique key, configure how long\n data is cached and how it refreshes, then point a workflow at that key to push data in. Get the basics right\n here and everything downstream connects to it.\n </PagePurpose>\n\n {/* Form */}\n <form onSubmit={handleSubmit} className=\"space-y-spacing-lg\">\n {/* Basic Information — primary emphasis zone */}\n <GlassCard treatment=\"glass\" glow>\n <CardHeader className=\"pb-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"w-8 h-8 rounded-full bg-action-primary-bg/10 flex items-center justify-center\">\n <Database className=\"w-4 h-4 text-action-primary-bg\" />\n </div>\n <div>\n <CardTitle className=\"text-base\">Basic Information</CardTitle>\n <p className=\"text-xs text-text-secondary mt-0.5\">Essential details for your DataSink</p>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-5\">\n {/* Name field */}\n <div className=\"space-y-spacing-sm\">\n <Label htmlFor=\"name\">\n Name <span className=\"text-state-error\">*</span>\n </Label>\n <Input\n id=\"name\"\n type=\"text\"\n value={form.name}\n onChange={handleNameChange}\n placeholder=\"e.g., Sales Metrics\"\n className={errors.name ? 'border-state-error' : ''}\n />\n {errors.name && <p className=\"text-body-xs text-state-error\">{errors.name}</p>}\n </div>\n\n {/* Key field */}\n <div className=\"space-y-spacing-sm\">\n <Label htmlFor=\"key\">\n Unique Key <span className=\"text-state-error\">*</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=\"sales_metrics\"\n disabled={isEdit}\n className={`font-mono flex-1 ${errors.key ? 'border-state-error' : ''}`}\n />\n {form.key && (\n <Button type=\"button\" onClick={handleCopyKey} variant=\"outline\" size=\"sm\" className=\"px-3\">\n {keyCopied ? <Check className=\"w-4 h-4 text-state-success\" /> : <Copy className=\"w-4 h-4\" />}\n </Button>\n )}\n </div>\n {errors.key && <p className=\"text-body-xs text-state-error\">{errors.key}</p>}\n <p className=\"text-body-xs text-text-tertiary\">\n {isEdit\n ? 'Key cannot be changed. Use this key in your workflows to push data.'\n : 'Auto-generated from name. This key will be used by workflows to push data.'}\n </p>\n </div>\n\n {/* Description field */}\n <div className=\"space-y-spacing-sm\">\n <Label htmlFor=\"description\">Description</Label>\n <Textarea\n id=\"description\"\n value={form.description}\n onChange={handleDescriptionChange}\n placeholder=\"Describe what data this sink stores...\"\n rows={2}\n className=\"resize-none\"\n />\n </div>\n </CardContent>\n </GlassCard>\n\n {/* Configuration */}\n <Card>\n <CardHeader className=\"pb-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"w-8 h-8 rounded-full bg-action-primary-bg/10 flex items-center justify-center\">\n <Settings className=\"w-4 h-4 text-action-primary-bg\" />\n </div>\n <div>\n <CardTitle className=\"text-base\">Configuration</CardTitle>\n <p className=\"text-xs text-text-secondary mt-0.5\">Cache and refresh settings</p>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-5\">\n {/* Cache TTL */}\n <div className=\"space-y-spacing-sm\">\n <Label>Cache Duration</Label>\n <CacheTTLSelector value={form.ttl} onChange={handleTTLChange} />\n <p className=\"text-body-xs text-text-tertiary\">\n How long cached data remains valid before requiring refresh.\n </p>\n </div>\n\n {/* Refresh Type */}\n <RefreshTypeSelector value={form.refresh} onChange={handleRefreshChange} />\n </CardContent>\n </Card>\n\n {/* Data Payload */}\n <Card>\n <CardHeader className=\"pb-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"w-8 h-8 rounded-full bg-action-primary-bg/10 flex items-center justify-center\">\n <Database className=\"w-4 h-4 text-action-primary-bg\" />\n </div>\n <div>\n <CardTitle className=\"text-base\">Data Payload</CardTitle>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {isEdit ? 'Edit the JSON data stored in this DataSink' : 'Optional initial data (JSON format)'}\n </p>\n </div>\n </div>\n <Button type=\"button\" onClick={handleFormatData} variant=\"outline\" size=\"sm\">\n Format JSON\n </Button>\n </div>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-spacing-sm\">\n <Textarea\n value={form.data}\n onChange={handleDataChange}\n placeholder='{\"key\": \"value\"}'\n rows={10}\n className={`font-mono text-xs resize-y ${errors.data ? 'border-state-error' : ''}`}\n />\n {errors.data && <p className=\"text-body-xs text-state-error\">{errors.data}</p>}\n <p className=\"text-body-xs text-text-tertiary\">\n Enter valid JSON data. This data will be stored and can be accessed by widgets via parsers.\n </p>\n </div>\n </CardContent>\n </Card>\n\n {/* Data Preview - Only show for existing DataSinks */}\n {isEdit && existingDataSink && (\n <Card>\n <CardHeader className=\"pb-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"w-8 h-8 rounded-full bg-action-primary-bg/10 flex items-center justify-center\">\n <Eye className=\"w-4 h-4 text-action-primary-bg\" />\n </div>\n <div>\n <CardTitle className=\"text-base\">Data Preview</CardTitle>\n <p className=\"text-xs text-text-secondary mt-0.5\">Preview the first 20 records</p>\n </div>\n </div>\n <Button\n type=\"button\"\n onClick={handleShowData}\n variant=\"outline\"\n size=\"sm\"\n disabled={isLoadingPreview}\n >\n {isLoadingPreview ? (\n <>\n <Loader2 className=\"w-4 h-4 mr-2 animate-spin\" />\n Loading...\n </>\n ) : (\n <>\n <Eye className=\"w-4 h-4 mr-2\" />\n Show Data\n </>\n )}\n </Button>\n </div>\n </CardHeader>\n {(previewData || previewError) && (\n <CardContent>\n {previewError ? (\n <div className=\"p-4 bg-state-error/10 border border-state-error/30 rounded-md\">\n <p className=\"text-sm text-state-error\">{previewError}</p>\n </div>\n ) : previewData && previewData.length > 0 ? (\n <pre className=\"p-4 bg-bg-sunken rounded-md overflow-auto max-h-[300px] text-xs font-mono\">\n {JSON.stringify(previewData, null, 2)}\n </pre>\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No data available yet\"\n description=\"Connect a workflow to this sink's key to start pushing data.\"\n />\n )}\n </CardContent>\n )}\n </Card>\n )}\n\n {/* Submit */}\n <div className=\"flex items-center justify-end gap-spacing-md pt-spacing-md\">\n <Button type=\"button\" onClick={handleBack} variant=\"secondary\">\n Cancel\n </Button>\n <Button type=\"submit\" disabled={!isFormValid || isSaving} variant=\"default\">\n {isSaving ? (\n <>\n <Loader2 className=\"w-4 h-4 mr-2 animate-spin\" />\n Saving...\n </>\n ) : (\n <>\n <Save className=\"w-4 h-4 mr-2\" />\n {isEdit ? 'Save Changes' : 'Create DataSink'}\n </>\n )}\n </Button>\n </div>\n </form>\n\n {/* Info Box for New DataSinks */}\n {!isEdit && (\n <div className=\"mt-spacing-lg p-4 bg-bg-sunken rounded-lg border border-border-default\">\n <h3 className=\"text-sm font-medium text-text-primary mb-2\">What's Next?</h3>\n <ol className=\"list-decimal list-inside text-xs text-text-secondary space-y-1\">\n <li>Create this DataSink to get your unique key</li>\n <li>\n Go to <strong>Workflows</strong> and create a FluidGrids workflow\n </li>\n <li>Use the unique key in your workflow to push data to this DataSink</li>\n <li>\n Create <strong>Parsers</strong> to transform the data using JQ or JSONata\n </li>\n </ol>\n </div>\n )}\n </div>\n </div>\n );\n});\n\nexport default DataSinkBuilderPage;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataSinkViewPage.js","names":[],"sources":["../../../src/bigconsole/pages/DataSinkViewPage.tsx"],"sourcesContent":["/**\n * DataSink View Page\n *\n * Page for viewing DataSink details, data preview, and actions.\n */\n\nimport { memo, useState, useEffect, useCallback } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { useAppNavigate } from '../contexts';\nimport { isNative, nativeConfirm, nativeImpact, nativeNotify } from '../../utils/nativeBridge';\nimport { formatDistanceToNow } from 'date-fns';\nimport { useDataSinkOperations } from '../hooks/useDataSinkOperations';\nimport { useDataSinkSubscription } from '../hooks/useDataSinkSubscription';\nimport { useDataSinkStore } from '../store/dataSinkStore';\nimport { DataSinkStatusBadge } from '../components/datasink/DataSinkStatusBadge';\nimport { DataSinkDataViewer } from '../components/datasink/DataSinkDataViewer';\nimport { DataSinkTableViewer } from '../components/datasink/DataSinkTableViewer';\nimport { LinkedWorkflowsPanel } from '../components/datasink/LinkedWorkflowsPanel';\nimport { LinkedParsersPanel } from '../components/datasink/LinkedParsersPanel';\nimport { WorkflowStatusPanel } from '../components/datasink/WorkflowStatusPanel';\nimport { ExportDataSinkDialog } from '../components/datasink/ExportDataSinkDialog';\n\n// fe-libs UI components\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport { GlassCard, IllustratedEmptyState, PagePurpose, NextSteps } from '@burdenoff/fe-libs/ui';\n\n// Lucide icons\nimport {\n ArrowLeft,\n Edit,\n RefreshCw,\n Trash2,\n Database,\n Loader2,\n AlertCircle,\n Eye,\n EyeOff,\n Download,\n Grid3X3,\n Code,\n} from 'lucide-react';\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const DataSinkViewPage = memo(function DataSinkViewPage() {\n const { dataSinkId } = useParams<{ dataSinkId: string; consoleId: string }>();\n const navigate = useAppNavigate();\n\n // Local state\n const [showData, setShowData] = useState(false);\n const [isRefreshing, setIsRefreshing] = useState(false);\n const [isDeleting, setIsDeleting] = useState(false);\n const [isExportDialogOpen, setIsExportDialogOpen] = useState(false);\n const [dataPreview, setDataPreview] = useState<Record<string, unknown> | null>(null);\n const [dataLoading, setDataLoading] = useState(false);\n const [dataViewMode, setDataViewMode] = useState<'table' | 'json'>('table');\n\n // Store\n const dataSink = useDataSinkStore((state) => (dataSinkId ? state.dataSinks.get(dataSinkId) : undefined));\n\n // Operations\n const { loading, error, fetchDataSink, getDataSinkData, refreshDataSink, deleteDataSink } = useDataSinkOperations({\n skipFetch: true,\n });\n\n // Subscribe to updates\n useDataSinkSubscription({\n dataSinkId,\n enabled: !!dataSinkId,\n });\n\n // Load DataSink on mount - always fetch full data to get workflowLinks\n useEffect(() => {\n if (dataSinkId) {\n fetchDataSink(dataSinkId);\n }\n }, [dataSinkId, fetchDataSink]);\n\n // Handle back navigation\n const handleBack = useCallback(() => {\n navigate(`/datasinks`);\n }, [navigate]);\n\n // Handle edit\n const handleEdit = useCallback(() => {\n navigate(`/datasinks/${dataSinkId}/edit`);\n }, [navigate, dataSinkId]);\n\n // Handle refresh\n const handleRefresh = useCallback(async () => {\n if (!dataSinkId) return;\n setIsRefreshing(true);\n try {\n await refreshDataSink({ id: dataSinkId });\n } catch (err) {\n } finally {\n setIsRefreshing(false);\n }\n }, [dataSinkId, refreshDataSink]);\n\n // Handle delete\n const handleDelete = useCallback(async () => {\n if (!dataSinkId) return;\n const native = await nativeConfirm({\n title: 'Delete DataSink?',\n message: 'Are you sure you want to delete this DataSink?',\n okButtonTitle: 'Delete',\n cancelButtonTitle: 'Cancel',\n });\n const ok = native === null ? window.confirm('Are you sure you want to delete this DataSink?') : native;\n if (!ok) return;\n nativeImpact('medium');\n setIsDeleting(true);\n try {\n await deleteDataSink(dataSinkId);\n if (isNative()) void nativeNotify('success');\n navigate(`/datasinks`);\n } catch (err) {\n if (isNative()) void nativeNotify('error');\n } finally {\n setIsDeleting(false);\n }\n }, [dataSinkId, deleteDataSink, navigate]);\n\n // Handle show data\n const handleShowData = useCallback(async () => {\n if (!dataSinkId) return;\n if (showData) {\n setShowData(false);\n return;\n }\n setDataLoading(true);\n try {\n const result = await getDataSinkData({ id: dataSinkId });\n if (result) {\n // Use raw data for preview\n setDataPreview((result.raw as Record<string, unknown>) || {});\n }\n setShowData(true);\n } catch (err) {\n } finally {\n setDataLoading(false);\n }\n }, [dataSinkId, showData, getDataSinkData]);\n\n // Handle export\n const handleExport = useCallback(() => {\n setIsExportDialogOpen(true);\n }, []);\n\n const handleExportClose = useCallback(() => {\n setIsExportDialogOpen(false);\n }, []);\n\n // Loading state\n if (loading && !dataSink) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <Loader2 className=\"w-8 h-8 text-text-secondary animate-spin\" />\n </div>\n );\n }\n\n // Error state\n if (error) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px] p-card-padding\">\n <div className=\"text-center\">\n <AlertCircle className=\"w-12 h-12 text-state-error mx-auto mb-spacing-md\" />\n <p className=\"text-state-error text-body-sm font-medium mb-spacing-sm\">Failed to load DataSink</p>\n <p className=\"text-text-tertiary text-body-xs mb-spacing-lg\">{error.message}</p>\n <Button onClick={handleBack} variant=\"ghost\" size=\"sm\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n Go back\n </Button>\n </div>\n </div>\n );\n }\n\n // Not found state\n if (!dataSink) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px] p-card-padding\">\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"DataSink not found\"\n description=\"The DataSink you're looking for doesn't exist or has been deleted.\"\n action={\n <Button onClick={handleBack} variant=\"default\" size=\"default\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n Go back to DataSinks\n </Button>\n }\n />\n </div>\n );\n }\n\n return (\n <div className=\"p-card-padding space-y-spacing-lg\">\n {/* Header */}\n <div className=\"flex flex-col sm:flex-row sm:items-start sm:justify-between gap-spacing-md\">\n <div className=\"flex-1\">\n <Button onClick={handleBack} variant=\"ghost\" size=\"sm\" className=\"mb-spacing-md\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n Back to DataSinks\n </Button>\n <div className=\"flex items-center gap-spacing-sm flex-wrap\">\n <h1 className=\"text-heading-h1 font-bold text-text-primary\">{dataSink.name || 'Untitled'}</h1>\n <DataSinkStatusBadge status={dataSink.status} />\n </div>\n <p className=\"text-body-sm text-text-tertiary font-mono mt-spacing-xs\">{dataSink.key}</p>\n {dataSink.description && (\n <p className=\"text-body-sm text-text-secondary mt-spacing-sm\">{dataSink.description}</p>\n )}\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center gap-spacing-sm flex-wrap\">\n <Button onClick={handleRefresh} disabled={isRefreshing} variant=\"secondary\" size=\"default\">\n <RefreshCw className={`w-4 h-4 mr-2 ${isRefreshing ? 'animate-spin' : ''}`} />\n {isRefreshing ? 'Refreshing...' : 'Refresh'}\n </Button>\n <Button onClick={handleExport} variant=\"secondary\" size=\"default\">\n <Download className=\"w-4 h-4 mr-2\" />\n Export\n </Button>\n <Button onClick={handleEdit} variant=\"secondary\" size=\"default\">\n <Edit className=\"w-4 h-4 mr-2\" />\n Edit\n </Button>\n <Button onClick={handleDelete} disabled={isDeleting} variant=\"destructive\" size=\"default\">\n <Trash2 className=\"w-4 h-4 mr-2\" />\n {isDeleting ? 'Deleting...' : 'Delete'}\n </Button>\n </div>\n </div>\n\n <PagePurpose>\n A data sink is a structured store that holds your processed data and serves it to\n dashboards. From here you can inspect its schema and stats, preview the cached rows,\n refresh it from its linked workflow, or export it.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"bigconsole-datasink-view\"\n steps={[\n {\n id: 'preview',\n label: 'Preview the data',\n description: 'Open the cached rows to confirm the sink holds what you expect.',\n onClick: handleShowData,\n },\n {\n id: 'refresh',\n label: 'Refresh from source',\n description: 'Re-run the linked workflow to pull the latest data.',\n onClick: handleRefresh,\n },\n {\n id: 'build-dashboard',\n label: 'Visualize it on a dashboard',\n description: 'Add widgets that query this sink to see your data live.',\n onClick: () => navigate('/dashboards'),\n },\n {\n id: 'export',\n label: 'Export the data',\n description: 'Download the contents for use elsewhere.',\n onClick: handleExport,\n },\n ]}\n />\n\n {/* Details Grid */}\n <div className=\"grid gap-spacing-lg md:grid-cols-2\">\n {/* Info Panel — primary emphasis zone */}\n <GlassCard treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle>Details</CardTitle>\n </CardHeader>\n <CardContent>\n <dl className=\"space-y-spacing-md text-body-sm\">\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Status</dt>\n <dd>\n <DataSinkStatusBadge status={dataSink.status} />\n </dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Cache TTL</dt>\n <dd className=\"text-text-primary font-medium\">{dataSink.ttl ? `${dataSink.ttl}s` : 'None'}</dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Refresh Type</dt>\n <dd className=\"text-text-primary font-medium capitalize\">{dataSink.refresh?.type || 'Manual'}</dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Size</dt>\n <dd className=\"text-text-primary font-medium\">\n {dataSink.sizeBytes ? `${(dataSink.sizeBytes / 1024).toFixed(2)} KB` : '0 KB'}\n </dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Version</dt>\n <dd className=\"text-text-primary font-medium\">{dataSink.version || 1}</dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Last Refreshed</dt>\n <dd className=\"text-text-primary font-medium\">\n {dataSink.lastRefreshedAt\n ? formatDistanceToNow(new Date(dataSink.lastRefreshedAt), { addSuffix: true })\n : 'Never'}\n </dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Created</dt>\n <dd className=\"text-text-primary font-medium\">\n {formatDistanceToNow(new Date(dataSink.createdAt), { addSuffix: true })}\n </dd>\n </div>\n </dl>\n </CardContent>\n </GlassCard>\n\n {/* Workflow Status Panel */}\n {dataSink.fluidGridsWorkflowId && (\n <WorkflowStatusPanel\n workflowId={dataSink.fluidGridsWorkflowId}\n executionId={dataSink.fluidGridsWorkflowExecutionId || undefined}\n lastRefreshedAt={dataSink.lastRefreshedAt || undefined}\n setupState={dataSink.setupState}\n status={dataSink.status}\n onRerunWorkflow={handleRefresh}\n disabled={isRefreshing}\n isRerunning={isRefreshing}\n />\n )}\n\n {/* Linked Workflows */}\n <LinkedWorkflowsPanel workflowLinks={dataSink.workflowLinks} />\n\n {/* Linked Parsers */}\n <LinkedParsersPanel dataSinkKey={dataSink.key} />\n </div>\n\n {/* Data Preview Section */}\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0\">\n <CardTitle className=\"flex items-center gap-spacing-sm\">\n <Database className=\"w-4 h-4 text-text-secondary\" />\n Data Preview\n </CardTitle>\n <div className=\"flex items-center gap-2\">\n {showData && (\n <div className=\"flex items-center border border-border-default rounded-md overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setDataViewMode('table')}\n className={`p-1.5 ${dataViewMode === 'table' ? 'bg-bg-sunken text-text-primary' : 'text-text-secondary hover:text-text-primary'}`}\n title=\"Table view\"\n >\n <Grid3X3 className=\"w-4 h-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setDataViewMode('json')}\n className={`p-1.5 ${dataViewMode === 'json' ? 'bg-bg-sunken text-text-primary' : 'text-text-secondary hover:text-text-primary'}`}\n title=\"JSON view\"\n >\n <Code className=\"w-4 h-4\" />\n </button>\n </div>\n )}\n <Button\n onClick={handleShowData}\n disabled={dataLoading}\n variant={showData ? 'secondary' : 'default'}\n size=\"sm\"\n >\n {dataLoading ? (\n <>\n <Loader2 className=\"w-4 h-4 mr-2 animate-spin\" />\n Loading...\n </>\n ) : showData ? (\n <>\n <EyeOff className=\"w-4 h-4 mr-2\" />\n Hide Data\n </>\n ) : (\n <>\n <Eye className=\"w-4 h-4 mr-2\" />\n Show Data\n </>\n )}\n </Button>\n </div>\n </CardHeader>\n\n {showData && dataPreview && (\n <CardContent>\n {dataViewMode === 'table' ? (\n <DataSinkTableViewer data={dataPreview} maxHeight=\"400px\" />\n ) : (\n <DataSinkDataViewer data={dataPreview} maxHeight=\"400px\" />\n )}\n </CardContent>\n )}\n\n {!showData && (\n <CardContent className=\"text-center p-spacing-xl\">\n <Database className=\"w-10 h-10 text-text-tertiary mx-auto mb-spacing-md\" />\n <p className=\"text-body-sm text-text-secondary\">Click "Show Data" to preview the cached data.</p>\n </CardContent>\n )}\n </Card>\n\n {/* Export DataSink Dialog */}\n <ExportDataSinkDialog\n isOpen={isExportDialogOpen}\n dataSinkId={dataSinkId || null}\n dataSinkName={dataSink.name || dataSink.key}\n onClose={handleExportClose}\n />\n </div>\n );\n});\n\nexport default DataSinkViewPage;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DataSinkViewPage.js","names":[],"sources":["../../../src/bigconsole/pages/DataSinkViewPage.tsx"],"sourcesContent":["/**\n * DataSink View Page\n *\n * Page for viewing DataSink details, data preview, and actions.\n */\n\nimport { memo, useState, useEffect, useCallback } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { useAppNavigate } from '../contexts';\nimport { isNative, nativeConfirm, nativeImpact, nativeNotify } from '../../utils/nativeBridge';\nimport { formatDistanceToNow } from 'date-fns';\nimport { useDataSinkOperations } from '../hooks/useDataSinkOperations';\nimport { useDataSinkSubscription } from '../hooks/useDataSinkSubscription';\nimport { useDataSinkStore } from '../store/dataSinkStore';\nimport { DataSinkStatusBadge } from '../components/datasink/DataSinkStatusBadge';\nimport { DataSinkDataViewer } from '../components/datasink/DataSinkDataViewer';\nimport { DataSinkTableViewer } from '../components/datasink/DataSinkTableViewer';\nimport { LinkedWorkflowsPanel } from '../components/datasink/LinkedWorkflowsPanel';\nimport { LinkedParsersPanel } from '../components/datasink/LinkedParsersPanel';\nimport { WorkflowStatusPanel } from '../components/datasink/WorkflowStatusPanel';\nimport { ExportDataSinkDialog } from '../components/datasink/ExportDataSinkDialog';\n\n// fe-libs UI components\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport { GlassCard, IllustratedEmptyState, PagePurpose, NextSteps } from '@burdenoff/fe-libs/ui';\n\n// Lucide icons\nimport {\n ArrowLeft,\n Edit,\n RefreshCw,\n Trash2,\n Database,\n Loader2,\n AlertCircle,\n Eye,\n EyeOff,\n Download,\n Grid3X3,\n Code,\n} from 'lucide-react';\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const DataSinkViewPage = memo(function DataSinkViewPage() {\n const { dataSinkId } = useParams<{ dataSinkId: string; consoleId: string }>();\n const navigate = useAppNavigate();\n\n // Local state\n const [showData, setShowData] = useState(false);\n const [isRefreshing, setIsRefreshing] = useState(false);\n const [isDeleting, setIsDeleting] = useState(false);\n const [isExportDialogOpen, setIsExportDialogOpen] = useState(false);\n const [dataPreview, setDataPreview] = useState<Record<string, unknown> | null>(null);\n const [dataLoading, setDataLoading] = useState(false);\n const [dataViewMode, setDataViewMode] = useState<'table' | 'json'>('table');\n\n // Store\n const dataSink = useDataSinkStore((state) => (dataSinkId ? state.dataSinks.get(dataSinkId) : undefined));\n\n // Operations\n const { loading, error, fetchDataSink, getDataSinkData, refreshDataSink, deleteDataSink } = useDataSinkOperations({\n skipFetch: true,\n });\n\n // Subscribe to updates\n useDataSinkSubscription({\n dataSinkId,\n enabled: !!dataSinkId,\n });\n\n // Load DataSink on mount - always fetch full data to get workflowLinks\n useEffect(() => {\n if (dataSinkId) {\n fetchDataSink(dataSinkId);\n }\n }, [dataSinkId, fetchDataSink]);\n\n // Handle back navigation\n const handleBack = useCallback(() => {\n navigate(`/datasinks`);\n }, [navigate]);\n\n // Handle edit\n const handleEdit = useCallback(() => {\n navigate(`/datasinks/${dataSinkId}/edit`);\n }, [navigate, dataSinkId]);\n\n // Handle refresh\n const handleRefresh = useCallback(async () => {\n if (!dataSinkId) return;\n setIsRefreshing(true);\n try {\n await refreshDataSink({ id: dataSinkId });\n } catch (err) {\n } finally {\n setIsRefreshing(false);\n }\n }, [dataSinkId, refreshDataSink]);\n\n // Handle delete\n const handleDelete = useCallback(async () => {\n if (!dataSinkId) return;\n const native = await nativeConfirm({\n title: 'Delete DataSink?',\n message: 'Are you sure you want to delete this DataSink?',\n okButtonTitle: 'Delete',\n cancelButtonTitle: 'Cancel',\n });\n const ok = native === null ? window.confirm('Are you sure you want to delete this DataSink?') : native;\n if (!ok) return;\n nativeImpact('medium');\n setIsDeleting(true);\n try {\n await deleteDataSink(dataSinkId);\n if (isNative()) void nativeNotify('success');\n navigate(`/datasinks`);\n } catch (err) {\n if (isNative()) void nativeNotify('error');\n } finally {\n setIsDeleting(false);\n }\n }, [dataSinkId, deleteDataSink, navigate]);\n\n // Handle show data\n const handleShowData = useCallback(async () => {\n if (!dataSinkId) return;\n if (showData) {\n setShowData(false);\n return;\n }\n setDataLoading(true);\n try {\n const result = await getDataSinkData({ id: dataSinkId });\n if (result) {\n // Use raw data for preview\n setDataPreview((result.raw as Record<string, unknown>) || {});\n }\n setShowData(true);\n } catch (err) {\n } finally {\n setDataLoading(false);\n }\n }, [dataSinkId, showData, getDataSinkData]);\n\n // Handle export\n const handleExport = useCallback(() => {\n setIsExportDialogOpen(true);\n }, []);\n\n const handleExportClose = useCallback(() => {\n setIsExportDialogOpen(false);\n }, []);\n\n // Loading state\n if (loading && !dataSink) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <Loader2 className=\"w-8 h-8 text-text-secondary animate-spin\" />\n </div>\n );\n }\n\n // Error state\n if (error) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px] p-card-padding\">\n <div className=\"text-center\">\n <AlertCircle className=\"w-12 h-12 text-state-error mx-auto mb-spacing-md\" />\n <p className=\"text-state-error text-body-sm font-medium mb-spacing-sm\">Failed to load DataSink</p>\n <p className=\"text-text-tertiary text-body-xs mb-spacing-lg\">{error.message}</p>\n <Button onClick={handleBack} variant=\"ghost\" size=\"sm\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n Go back\n </Button>\n </div>\n </div>\n );\n }\n\n // Not found state\n if (!dataSink) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px] p-card-padding\">\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"DataSink not found\"\n description=\"The DataSink you're looking for doesn't exist or has been deleted.\"\n action={\n <Button onClick={handleBack} variant=\"default\" size=\"default\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n Go back to DataSinks\n </Button>\n }\n />\n </div>\n );\n }\n\n return (\n <div className=\"p-card-padding space-y-spacing-lg\">\n {/* Header */}\n <div className=\"flex flex-col sm:flex-row sm:items-start sm:justify-between gap-spacing-md\">\n <div className=\"flex-1\">\n <Button onClick={handleBack} variant=\"ghost\" size=\"sm\" className=\"mb-spacing-md\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n Back to DataSinks\n </Button>\n <div className=\"flex items-center gap-spacing-sm flex-wrap\">\n <h1 className=\"text-heading-h1 font-bold text-text-primary\">{dataSink.name || 'Untitled'}</h1>\n <DataSinkStatusBadge status={dataSink.status} />\n </div>\n <p className=\"text-body-sm text-text-tertiary font-mono mt-spacing-xs\">{dataSink.key}</p>\n {dataSink.description && (\n <p className=\"text-body-sm text-text-secondary mt-spacing-sm\">{dataSink.description}</p>\n )}\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center gap-spacing-sm flex-wrap\">\n <Button onClick={handleRefresh} disabled={isRefreshing} variant=\"secondary\" size=\"default\">\n <RefreshCw className={`w-4 h-4 mr-2 ${isRefreshing ? 'animate-spin' : ''}`} />\n {isRefreshing ? 'Refreshing...' : 'Refresh'}\n </Button>\n <Button onClick={handleExport} variant=\"secondary\" size=\"default\">\n <Download className=\"w-4 h-4 mr-2\" />\n Export\n </Button>\n <Button onClick={handleEdit} variant=\"secondary\" size=\"default\">\n <Edit className=\"w-4 h-4 mr-2\" />\n Edit\n </Button>\n <Button onClick={handleDelete} disabled={isDeleting} variant=\"destructive\" size=\"default\">\n <Trash2 className=\"w-4 h-4 mr-2\" />\n {isDeleting ? 'Deleting...' : 'Delete'}\n </Button>\n </div>\n </div>\n\n <PagePurpose>\n A data sink is a structured store that holds your processed data and serves it to dashboards. From here you can\n inspect its schema and stats, preview the cached rows, refresh it from its linked workflow, or export it.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"bigconsole-datasink-view\"\n steps={[\n {\n id: 'preview',\n label: 'Preview the data',\n description: 'Open the cached rows to confirm the sink holds what you expect.',\n onClick: handleShowData,\n },\n {\n id: 'refresh',\n label: 'Refresh from source',\n description: 'Re-run the linked workflow to pull the latest data.',\n onClick: handleRefresh,\n },\n {\n id: 'build-dashboard',\n label: 'Visualize it on a dashboard',\n description: 'Add widgets that query this sink to see your data live.',\n onClick: () => navigate('/dashboards'),\n },\n {\n id: 'export',\n label: 'Export the data',\n description: 'Download the contents for use elsewhere.',\n onClick: handleExport,\n },\n ]}\n />\n\n {/* Details Grid */}\n <div className=\"grid gap-spacing-lg md:grid-cols-2\">\n {/* Info Panel — primary emphasis zone */}\n <GlassCard treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle>Details</CardTitle>\n </CardHeader>\n <CardContent>\n <dl className=\"space-y-spacing-md text-body-sm\">\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Status</dt>\n <dd>\n <DataSinkStatusBadge status={dataSink.status} />\n </dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Cache TTL</dt>\n <dd className=\"text-text-primary font-medium\">{dataSink.ttl ? `${dataSink.ttl}s` : 'None'}</dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Refresh Type</dt>\n <dd className=\"text-text-primary font-medium capitalize\">{dataSink.refresh?.type || 'Manual'}</dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Size</dt>\n <dd className=\"text-text-primary font-medium\">\n {dataSink.sizeBytes ? `${(dataSink.sizeBytes / 1024).toFixed(2)} KB` : '0 KB'}\n </dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Version</dt>\n <dd className=\"text-text-primary font-medium\">{dataSink.version || 1}</dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Last Refreshed</dt>\n <dd className=\"text-text-primary font-medium\">\n {dataSink.lastRefreshedAt\n ? formatDistanceToNow(new Date(dataSink.lastRefreshedAt), { addSuffix: true })\n : 'Never'}\n </dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Created</dt>\n <dd className=\"text-text-primary font-medium\">\n {formatDistanceToNow(new Date(dataSink.createdAt), { addSuffix: true })}\n </dd>\n </div>\n </dl>\n </CardContent>\n </GlassCard>\n\n {/* Workflow Status Panel */}\n {dataSink.fluidGridsWorkflowId && (\n <WorkflowStatusPanel\n workflowId={dataSink.fluidGridsWorkflowId}\n executionId={dataSink.fluidGridsWorkflowExecutionId || undefined}\n lastRefreshedAt={dataSink.lastRefreshedAt || undefined}\n setupState={dataSink.setupState}\n status={dataSink.status}\n onRerunWorkflow={handleRefresh}\n disabled={isRefreshing}\n isRerunning={isRefreshing}\n />\n )}\n\n {/* Linked Workflows */}\n <LinkedWorkflowsPanel workflowLinks={dataSink.workflowLinks} />\n\n {/* Linked Parsers */}\n <LinkedParsersPanel dataSinkKey={dataSink.key} />\n </div>\n\n {/* Data Preview Section */}\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0\">\n <CardTitle className=\"flex items-center gap-spacing-sm\">\n <Database className=\"w-4 h-4 text-text-secondary\" />\n Data Preview\n </CardTitle>\n <div className=\"flex items-center gap-2\">\n {showData && (\n <div className=\"flex items-center border border-border-default rounded-md overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setDataViewMode('table')}\n className={`p-1.5 ${dataViewMode === 'table' ? 'bg-bg-sunken text-text-primary' : 'text-text-secondary hover:text-text-primary'}`}\n title=\"Table view\"\n >\n <Grid3X3 className=\"w-4 h-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setDataViewMode('json')}\n className={`p-1.5 ${dataViewMode === 'json' ? 'bg-bg-sunken text-text-primary' : 'text-text-secondary hover:text-text-primary'}`}\n title=\"JSON view\"\n >\n <Code className=\"w-4 h-4\" />\n </button>\n </div>\n )}\n <Button\n onClick={handleShowData}\n disabled={dataLoading}\n variant={showData ? 'secondary' : 'default'}\n size=\"sm\"\n >\n {dataLoading ? (\n <>\n <Loader2 className=\"w-4 h-4 mr-2 animate-spin\" />\n Loading...\n </>\n ) : showData ? (\n <>\n <EyeOff className=\"w-4 h-4 mr-2\" />\n Hide Data\n </>\n ) : (\n <>\n <Eye className=\"w-4 h-4 mr-2\" />\n Show Data\n </>\n )}\n </Button>\n </div>\n </CardHeader>\n\n {showData && dataPreview && (\n <CardContent>\n {dataViewMode === 'table' ? (\n <DataSinkTableViewer data={dataPreview} maxHeight=\"400px\" />\n ) : (\n <DataSinkDataViewer data={dataPreview} maxHeight=\"400px\" />\n )}\n </CardContent>\n )}\n\n {!showData && (\n <CardContent className=\"text-center p-spacing-xl\">\n <Database className=\"w-10 h-10 text-text-tertiary mx-auto mb-spacing-md\" />\n <p className=\"text-body-sm text-text-secondary\">Click "Show Data" to preview the cached data.</p>\n </CardContent>\n )}\n </Card>\n\n {/* Export DataSink Dialog */}\n <ExportDataSinkDialog\n isOpen={isExportDialogOpen}\n dataSinkId={dataSinkId || null}\n dataSinkName={dataSink.name || dataSink.key}\n onClose={handleExportClose}\n />\n </div>\n );\n});\n\nexport default DataSinkViewPage;\n"],"mappings":"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"}
|