@burdenoff/microfe-bigconsole 2026.728.1 → 2026.729.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/components/DrilldownDashboardRenderer.js +1 -1
- package/dist/bigconsole/components/DrilldownDashboardRenderer.js.map +1 -1
- package/dist/bigconsole/components/builder/inspector/DataBindingSection.js +4 -4
- package/dist/bigconsole/components/builder/inspector/DataBindingSection.js.map +1 -1
- package/dist/bigconsole/components/datasink/CacheTTLSelector.js +5 -5
- package/dist/bigconsole/components/datasink/CacheTTLSelector.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkCard.js +3 -3
- package/dist/bigconsole/components/datasink/DataSinkCard.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js +4 -4
- package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkStatusBadge.js +6 -6
- package/dist/bigconsole/components/datasink/DataSinkStatusBadge.js.map +1 -1
- package/dist/bigconsole/components/datasink/LinkedWorkflowsPanel.js +9 -9
- package/dist/bigconsole/components/datasink/LinkedWorkflowsPanel.js.map +1 -1
- package/dist/bigconsole/components/datasink/RefreshTypeSelector.js +2 -2
- package/dist/bigconsole/components/datasink/RefreshTypeSelector.js.map +1 -1
- package/dist/bigconsole/components/datasink/SetupStateBadge.js +8 -8
- package/dist/bigconsole/components/datasink/SetupStateBadge.js.map +1 -1
- package/dist/bigconsole/components/datasink/WorkflowStatusPanel.js +13 -13
- package/dist/bigconsole/components/datasink/WorkflowStatusPanel.js.map +1 -1
- package/dist/bigconsole/components/parser/DataSinkSelector.js +2 -2
- package/dist/bigconsole/components/parser/DataSinkSelector.js.map +1 -1
- package/dist/bigconsole/components/parser/ExpressionEditor.js +1 -1
- package/dist/bigconsole/components/parser/ExpressionEditor.js.map +1 -1
- package/dist/bigconsole/components/parser/ParserCard.js +1 -1
- package/dist/bigconsole/components/parser/ParserCard.js.map +1 -1
- package/dist/bigconsole/components/parser/ParserSelector.js +2 -2
- package/dist/bigconsole/components/parser/ParserSelector.js.map +1 -1
- package/dist/bigconsole/components/parser/ParserStatusBadge.js +2 -2
- package/dist/bigconsole/components/parser/ParserStatusBadge.js.map +1 -1
- package/dist/bigconsole/components/pipeline/PipelineCard.js +2 -2
- package/dist/bigconsole/components/pipeline/PipelineCard.js.map +1 -1
- package/dist/bigconsole/components/pipeline/PipelineDeleteDialog.js +5 -5
- package/dist/bigconsole/components/pipeline/PipelineDeleteDialog.js.map +1 -1
- package/dist/bigconsole/components/pipeline/PipelineStatusBadge.js +3 -3
- package/dist/bigconsole/components/pipeline/PipelineStatusBadge.js.map +1 -1
- package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js +1 -1
- package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/PropertiesPanel.js +3 -3
- package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetErrorBoundary.js +2 -2
- package/dist/bigconsole/components/widgets/WidgetErrorBoundary.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetMenu.js +1 -1
- package/dist/bigconsole/components/widgets/WidgetMenu.js.map +1 -1
- package/dist/bigconsole/components/widgets/adaptive-card/AdaptiveCardWidget.js +3 -3
- package/dist/bigconsole/components/widgets/adaptive-card/AdaptiveCardWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js +1 -1
- package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js +3 -3
- package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/heatmap/HeatmapWidget.js +52 -32
- package/dist/bigconsole/components/widgets/heatmap/HeatmapWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +3 -3
- package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/kpi/KPIWidget.js +1 -1
- package/dist/bigconsole/components/widgets/kpi/KPIWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js +2 -2
- package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/list/ListItem.js +3 -3
- package/dist/bigconsole/components/widgets/list/ListItem.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/ComparisonBadge.js +1 -1
- package/dist/bigconsole/components/widgets/metric-card/ComparisonBadge.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js +1 -1
- package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js +6 -6
- package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/TrendIndicator.js +1 -1
- package/dist/bigconsole/components/widgets/metric-card/TrendIndicator.js.map +1 -1
- package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js +2 -2
- package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/progress/ProgressBar.js +4 -4
- package/dist/bigconsole/components/widgets/progress/ProgressBar.js.map +1 -1
- package/dist/bigconsole/components/widgets/progress/ProgressConfig.js +1 -1
- package/dist/bigconsole/components/widgets/progress/ProgressConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/progress/ProgressWidget.js +1 -1
- package/dist/bigconsole/components/widgets/progress/ProgressWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/retention/RetentionWidget.js +2 -2
- package/dist/bigconsole/components/widgets/retention/RetentionWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/states/ErrorState.js +2 -2
- package/dist/bigconsole/components/widgets/states/ErrorState.js.map +1 -1
- package/dist/bigconsole/components/widgets/table/TableConfig.js +2 -2
- package/dist/bigconsole/components/widgets/table/TableConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js +1 -1
- package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js +6 -6
- package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js.map +1 -1
- package/dist/bigconsole/components/workflow/WorkflowCard.js +1 -1
- package/dist/bigconsole/components/workflow/WorkflowCard.js.map +1 -1
- package/dist/bigconsole/components/workflow/WorkflowDeleteDialog.js +5 -5
- package/dist/bigconsole/components/workflow/WorkflowDeleteDialog.js.map +1 -1
- package/dist/bigconsole/components/workflow/WorkflowStatusBadge.js +6 -6
- package/dist/bigconsole/components/workflow/WorkflowStatusBadge.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkBuilderPage.js +17 -17
- package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkViewPage.js +2 -2
- package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
- package/dist/bigconsole/pages/ParserBuilderPage.js +24 -24
- package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/ParserViewPage.js +8 -8
- package/dist/bigconsole/pages/ParserViewPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelineBuilderPage.js +9 -9
- package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelineViewPage.js +12 -12
- package/dist/bigconsole/pages/PipelineViewPage.js.map +1 -1
- package/dist/bigconsole/pages/WorkflowViewPage.js +6 -6
- package/dist/bigconsole/pages/WorkflowViewPage.js.map +1 -1
- package/dist/bigconsole/renderers/adapters/AdaptiveCardRenderer.js +1 -1
- package/dist/bigconsole/renderers/adapters/AdaptiveCardRenderer.js.map +1 -1
- package/dist/bigconsole/renderers/adapters/BlockKitRenderer.js +2 -2
- package/dist/bigconsole/renderers/adapters/BlockKitRenderer.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ParserViewPage.js","names":[],"sources":["../../../src/bigconsole/pages/ParserViewPage.tsx"],"sourcesContent":["/**\n * Parser View Page\n *\n * Page for viewing Parser details, expression, and test execution.\n */\n\nimport { memo, useState, useEffect, useCallback } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { useAppNavigate } from '../contexts';\nimport { isNative, nativeCopyText, nativeImpact, nativeNotify, nativeToast } from '../../utils/nativeBridge';\nimport { formatDistanceToNow } from 'date-fns';\nimport { useParserOperations } from '../hooks/useParserOperations';\nimport { useParserStore } from '../store/parserStore';\nimport { useDataSinkOperations } from '../hooks/useDataSinkOperations';\nimport { ParserStatusBadge } from '../components/parser/ParserStatusBadge';\nimport { ParserTypeBadge } from '../components/parser/ParserTypeBadge';\nimport { ExpressionEditor } from '../components/parser/ExpressionEditor';\nimport { ExportParserDialog } from '../components/parser/ExportParserDialog';\n\n// fe-libs UI components\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport { Badge } from '@burdenoff/fe-libs/ui';\nimport { GlassCard, IllustratedEmptyState, PagePurpose, NextSteps } from '@burdenoff/fe-libs/ui';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@burdenoff/fe-libs/ui';\n\n// Lucide icons\nimport {\n ArrowLeft,\n Edit,\n Play,\n Trash2,\n Copy,\n Check,\n FileCode2,\n Database,\n ArrowDown,\n Loader2,\n AlertCircle,\n AlertTriangle,\n Download,\n} from 'lucide-react';\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\n// Default console ID for standalone parser viewing\nconst DEFAULT_CONSOLE_ID = 'default';\n\nexport const ParserViewPage = memo(function ParserViewPage() {\n const { parserId, consoleId: urlConsoleId } = useParams<{ parserId: string; consoleId?: string }>();\n const navigate = useAppNavigate();\n\n // Use URL consoleId or fall back to default\n const consoleId = urlConsoleId || DEFAULT_CONSOLE_ID;\n\n // Local state\n const [isDeleting, setIsDeleting] = useState(false);\n const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);\n const [expressionCopied, setExpressionCopied] = useState(false);\n const [isTesting, setIsTesting] = useState(false);\n const [isExportDialogOpen, setIsExportDialogOpen] = useState(false);\n const [testResult, setTestResult] = useState<{\n success: boolean;\n output: unknown;\n error: string | null;\n executionTimeMs: number;\n } | null>(null);\n\n // Store\n const parser = useParserStore((state) => (parserId ? state.parsers.get(parserId) : undefined));\n\n // Operations - use consoleId from URL or default\n const { loading, error, fetchParser, deleteParser, executeParser } = useParserOperations({\n consoleId,\n skipFetch: true,\n });\n\n // DataSink operations for source datasink info\n const { dataSinks, fetchDataSinks } = useDataSinkOperations({ skipFetch: true });\n\n // Load parser on mount - always fetch full data to get expression\n useEffect(() => {\n if (parserId) {\n fetchParser(parserId);\n }\n }, [parserId, fetchParser]);\n\n // Fetch datasinks to show source name\n useEffect(() => {\n fetchDataSinks();\n }, [fetchDataSinks]);\n\n // Get source datasink name\n const sourceDataSink = parser?.inputSinkKey ? dataSinks.find((ds) => ds.key === parser.inputSinkKey) : null;\n\n // Handle back navigation\n const handleBack = useCallback(() => {\n // Navigate to dashboard-scoped parsers list if consoleId is provided\n if (urlConsoleId) {\n navigate(`/dashboards/${urlConsoleId}/parsers`);\n } else {\n navigate(`/parsers`);\n }\n }, [navigate, urlConsoleId]);\n\n // Handle edit\n const handleEdit = useCallback(() => {\n // Navigate to dashboard-scoped parser edit if consoleId is provided\n if (urlConsoleId) {\n navigate(`/dashboards/${urlConsoleId}/parsers/${parserId}/edit`);\n } else {\n navigate(`/parsers/${parserId}/edit`);\n }\n }, [navigate, parserId, urlConsoleId]);\n\n // Handle delete\n const handleDelete = useCallback(async () => {\n if (!parserId) return;\n setIsDeleting(true);\n try {\n const success = await deleteParser(parserId);\n if (success) {\n if (isNative()) void nativeNotify('success');\n // Navigate to dashboard-scoped parsers list if consoleId is provided\n if (urlConsoleId) {\n navigate(`/dashboards/${urlConsoleId}/parsers`);\n } else {\n navigate(`/parsers`);\n }\n } else if (isNative()) {\n void nativeNotify('error');\n }\n } catch (err) {\n if (isNative()) void nativeNotify('error');\n } finally {\n setIsDeleting(false);\n setShowDeleteConfirm(false);\n }\n }, [parserId, deleteParser, navigate, urlConsoleId]);\n\n // Handle copy expression\n const handleCopyExpression = useCallback(async () => {\n if (!parser?.expression) return;\n try {\n await nativeCopyText(parser.expression);\n setExpressionCopied(true);\n if (isNative()) void nativeToast('Expression copied');\n setTimeout(() => setExpressionCopied(false), 2000);\n } catch (err) {}\n }, [parser?.expression]);\n\n // Handle test execution\n const handleTestExecute = useCallback(async () => {\n if (!parserId) return;\n setIsTesting(true);\n setTestResult(null);\n try {\n const result = await executeParser(parserId);\n if (result) {\n setTestResult({\n success: result.success,\n output: result.output,\n error: result.error,\n executionTimeMs: result.executionTimeMs,\n });\n }\n } catch (err) {\n setTestResult({\n success: false,\n output: null,\n error: err instanceof Error ? err.message : 'Execution failed',\n executionTimeMs: 0,\n });\n } finally {\n setIsTesting(false);\n }\n }, [parserId, executeParser]);\n\n // Navigate to source datasink\n const handleViewSourceDataSink = useCallback(() => {\n if (sourceDataSink) {\n navigate(`/datasinks/${sourceDataSink.id}`);\n }\n }, [navigate, sourceDataSink]);\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 && !parser) {\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-4\" />\n <p className=\"text-state-error text-body-sm font-medium mb-2\">Failed to load Parser</p>\n <p className=\"text-text-tertiary text-body-xs mb-6\">{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 (!parser) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px] p-card-padding\">\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"Parser not found\"\n description=\"The Parser 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 Parsers\n </Button>\n }\n />\n </div>\n );\n }\n\n return (\n <div className=\"p-card-padding space-y-6\">\n {/* Header */}\n <div className=\"flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4\">\n <div className=\"flex-1\">\n <Button onClick={handleBack} variant=\"ghost\" size=\"sm\" className=\"mb-4\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n Back to Parsers\n </Button>\n <div className=\"flex items-center gap-2 flex-wrap\">\n <h1 className=\"text-heading-h1 font-bold text-text-primary\">{parser.name || 'Untitled'}</h1>\n <ParserTypeBadge type={parser.type} />\n <ParserStatusBadge status={parser.status} />\n </div>\n {parser.description && <p className=\"text-body-sm text-text-secondary mt-2\">{parser.description}</p>}\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center gap-2 flex-wrap\">\n <Button onClick={handleTestExecute} disabled={isTesting} variant=\"secondary\" size=\"default\">\n <Play className=\"w-4 h-4 mr-2\" />\n {isTesting ? 'Running...' : 'Execute'}\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={() => setShowDeleteConfirm(true)} disabled={isDeleting} variant=\"destructive\" size=\"default\">\n <Trash2 className=\"w-4 h-4 mr-2\" />\n Delete\n </Button>\n </div>\n </div>\n\n <PagePurpose>\n A parser turns raw input into structured fields using its expression. Review or copy the expression, run it\n against a sample to see the output, then edit it or use it inside a pipeline to shape incoming data.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"bigconsole-parser-view\"\n steps={[\n {\n id: 'execute',\n label: 'Run a test execution',\n description: 'Check the expression produces the fields you expect.',\n onClick: handleTestExecute,\n },\n {\n id: 'edit',\n label: 'Edit the expression',\n description: 'Refine how this parser maps your input.',\n onClick: handleEdit,\n },\n {\n id: 'pipeline',\n label: 'Use it in a pipeline',\n description: 'Chain this parser with a data sink to process data end to end.',\n onClick: () => navigate('/pipelines'),\n },\n ]}\n />\n\n {/* Main Content Grid */}\n <div className=\"grid gap-6 lg:grid-cols-3\">\n {/* Expression Panel (2/3 width) — primary emphasis zone */}\n <div className=\"lg:col-span-2 space-y-6\">\n {/* Expression */}\n <GlassCard treatment=\"glass\" glow>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0\">\n <CardTitle className=\"flex items-center gap-2\">\n <FileCode2 className=\"w-4 h-4 text-text-secondary\" />\n Expression\n <Badge variant=\"secondary\" className=\"text-xs uppercase\">\n {parser.type}\n </Badge>\n </CardTitle>\n <Button onClick={handleCopyExpression} variant=\"ghost\" size=\"sm\">\n {expressionCopied ? (\n <>\n <Check className=\"w-3.5 h-3.5 text-state-success mr-2\" />\n Copied!\n </>\n ) : (\n <>\n <Copy className=\"w-3.5 h-3.5 mr-2\" />\n Copy\n </>\n )}\n </Button>\n </CardHeader>\n <CardContent>\n <ExpressionEditor value={parser.expression} type={parser.type} readOnly height=\"300px\" />\n </CardContent>\n </GlassCard>\n\n {/* Test Result Panel */}\n {testResult && (\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0\">\n <CardTitle className=\"flex items-center gap-2\">\n Execution Result\n <Badge variant={testResult.success ? 'default' : 'destructive'}>\n {testResult.success ? 'Success' : 'Failed'}\n </Badge>\n </CardTitle>\n <Badge variant=\"secondary\" className=\"text-xs\">\n {testResult.executionTimeMs}ms\n </Badge>\n </CardHeader>\n <CardContent>\n {testResult.error ? (\n <div className=\"bg-state-error/5 border border-state-error/20 rounded-md p-4\">\n <p className=\"text-body-sm text-state-error font-mono\">{testResult.error}</p>\n </div>\n ) : (\n <pre className=\"text-body-sm text-text-primary font-mono bg-bg-sunken rounded-md p-4 overflow-auto max-h-[300px]\">\n {JSON.stringify(testResult.output, null, 2)}\n </pre>\n )}\n </CardContent>\n </Card>\n )}\n </div>\n\n {/* Side Panel (1/3 width) */}\n <div className=\"space-y-6\">\n {/* Data Flow */}\n <Card>\n <CardHeader>\n <CardTitle>Data Flow</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n {/* Source DataSink */}\n <div>\n <label className=\"text-xs font-medium text-text-secondary\">Source DataSink</label>\n {parser.inputSinkKey ? (\n <div className=\"mt-1\">\n <p className=\"text-body-sm text-text-primary font-mono\">{parser.inputSinkKey}</p>\n {sourceDataSink && (\n <Button onClick={handleViewSourceDataSink} variant=\"link\" size=\"sm\" className=\"mt-1 p-0 h-auto\">\n <Database className=\"w-3 h-3 mr-1\" />\n View {sourceDataSink.name || 'DataSink'}\n </Button>\n )}\n </div>\n ) : (\n <p className=\"text-body-sm text-text-tertiary mt-1\">None configured</p>\n )}\n </div>\n\n {/* Arrow */}\n <div className=\"flex items-center justify-center py-1\">\n <ArrowDown className=\"w-4 h-4 text-text-tertiary\" />\n </div>\n\n {/* Output Key */}\n <div>\n <label className=\"text-xs font-medium text-text-secondary\">Output Key</label>\n <p className=\"text-body-sm text-text-primary font-mono mt-1\">\n {parser.outputKey || 'Not configured'}\n </p>\n </div>\n </div>\n </CardContent>\n </Card>\n\n {/* Configuration */}\n <Card>\n <CardHeader>\n <CardTitle>Configuration</CardTitle>\n </CardHeader>\n <CardContent>\n <dl className=\"space-y-4 text-body-sm\">\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Status</dt>\n <dd>\n <ParserStatusBadge status={parser.status} />\n </dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Type</dt>\n <dd>\n <ParserTypeBadge type={parser.type} />\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\">{parser.ttl ? `${parser.ttl}s` : 'No caching'}</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\">{parser.version || 1}</dd>\n </div>\n </dl>\n </CardContent>\n </Card>\n\n {/* Timestamps */}\n <Card>\n <CardHeader>\n <CardTitle>Timestamps</CardTitle>\n </CardHeader>\n <CardContent>\n <dl className=\"space-y-4 text-body-sm\">\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 {parser.createdAt\n ? formatDistanceToNow(new Date(parser.createdAt), { addSuffix: true })\n : 'Unknown'}\n </dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Updated</dt>\n <dd className=\"text-text-primary font-medium\">\n {parser.updatedAt\n ? formatDistanceToNow(new Date(parser.updatedAt), { addSuffix: true })\n : 'Unknown'}\n </dd>\n </div>\n </dl>\n </CardContent>\n </Card>\n </div>\n </div>\n\n {/* Delete Confirmation Dialog */}\n <Dialog open={showDeleteConfirm} onOpenChange={setShowDeleteConfirm}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Delete Parser</DialogTitle>\n <DialogDescription>\n Are you sure you want to delete <strong>{parser.name}</strong>? This action cannot be undone.\n </DialogDescription>\n </DialogHeader>\n <div className=\"bg-state-warning/10 border border-state-warning/20 rounded-md p-4 flex items-start gap-2\">\n <AlertTriangle className=\"w-4 h-4 text-state-warning flex-shrink-0 mt-0.5\" />\n <p className=\"text-body-xs text-state-warning\">\n Widgets and pipelines using this parser may stop working correctly after deletion.\n </p>\n </div>\n <DialogFooter>\n <Button onClick={() => setShowDeleteConfirm(false)} variant=\"secondary\">\n Cancel\n </Button>\n <Button\n onClick={() => {\n nativeImpact('medium');\n void handleDelete();\n }}\n disabled={isDeleting}\n variant=\"destructive\"\n >\n {isDeleting ? 'Deleting...' : 'Delete Parser'}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n\n {/* Export Parser Dialog */}\n <ExportParserDialog\n isOpen={isExportDialogOpen}\n parserId={parserId || null}\n parserName={parser.name}\n onClose={handleExportClose}\n />\n </div>\n );\n});\n\nexport default ParserViewPage;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ParserViewPage.js","names":[],"sources":["../../../src/bigconsole/pages/ParserViewPage.tsx"],"sourcesContent":["/**\n * Parser View Page\n *\n * Page for viewing Parser details, expression, and test execution.\n */\n\nimport { memo, useState, useEffect, useCallback } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { useAppNavigate } from '../contexts';\nimport { isNative, nativeCopyText, nativeImpact, nativeNotify, nativeToast } from '../../utils/nativeBridge';\nimport { formatDistanceToNow } from 'date-fns';\nimport { useParserOperations } from '../hooks/useParserOperations';\nimport { useParserStore } from '../store/parserStore';\nimport { useDataSinkOperations } from '../hooks/useDataSinkOperations';\nimport { ParserStatusBadge } from '../components/parser/ParserStatusBadge';\nimport { ParserTypeBadge } from '../components/parser/ParserTypeBadge';\nimport { ExpressionEditor } from '../components/parser/ExpressionEditor';\nimport { ExportParserDialog } from '../components/parser/ExportParserDialog';\n\n// fe-libs UI components\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport { Badge } from '@burdenoff/fe-libs/ui';\nimport { GlassCard, IllustratedEmptyState, PagePurpose, NextSteps } from '@burdenoff/fe-libs/ui';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@burdenoff/fe-libs/ui';\n\n// Lucide icons\nimport {\n ArrowLeft,\n Edit,\n Play,\n Trash2,\n Copy,\n Check,\n FileCode2,\n Database,\n ArrowDown,\n Loader2,\n AlertCircle,\n AlertTriangle,\n Download,\n} from 'lucide-react';\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\n// Default console ID for standalone parser viewing\nconst DEFAULT_CONSOLE_ID = 'default';\n\nexport const ParserViewPage = memo(function ParserViewPage() {\n const { parserId, consoleId: urlConsoleId } = useParams<{ parserId: string; consoleId?: string }>();\n const navigate = useAppNavigate();\n\n // Use URL consoleId or fall back to default\n const consoleId = urlConsoleId || DEFAULT_CONSOLE_ID;\n\n // Local state\n const [isDeleting, setIsDeleting] = useState(false);\n const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);\n const [expressionCopied, setExpressionCopied] = useState(false);\n const [isTesting, setIsTesting] = useState(false);\n const [isExportDialogOpen, setIsExportDialogOpen] = useState(false);\n const [testResult, setTestResult] = useState<{\n success: boolean;\n output: unknown;\n error: string | null;\n executionTimeMs: number;\n } | null>(null);\n\n // Store\n const parser = useParserStore((state) => (parserId ? state.parsers.get(parserId) : undefined));\n\n // Operations - use consoleId from URL or default\n const { loading, error, fetchParser, deleteParser, executeParser } = useParserOperations({\n consoleId,\n skipFetch: true,\n });\n\n // DataSink operations for source datasink info\n const { dataSinks, fetchDataSinks } = useDataSinkOperations({ skipFetch: true });\n\n // Load parser on mount - always fetch full data to get expression\n useEffect(() => {\n if (parserId) {\n fetchParser(parserId);\n }\n }, [parserId, fetchParser]);\n\n // Fetch datasinks to show source name\n useEffect(() => {\n fetchDataSinks();\n }, [fetchDataSinks]);\n\n // Get source datasink name\n const sourceDataSink = parser?.inputSinkKey ? dataSinks.find((ds) => ds.key === parser.inputSinkKey) : null;\n\n // Handle back navigation\n const handleBack = useCallback(() => {\n // Navigate to dashboard-scoped parsers list if consoleId is provided\n if (urlConsoleId) {\n navigate(`/dashboards/${urlConsoleId}/parsers`);\n } else {\n navigate(`/parsers`);\n }\n }, [navigate, urlConsoleId]);\n\n // Handle edit\n const handleEdit = useCallback(() => {\n // Navigate to dashboard-scoped parser edit if consoleId is provided\n if (urlConsoleId) {\n navigate(`/dashboards/${urlConsoleId}/parsers/${parserId}/edit`);\n } else {\n navigate(`/parsers/${parserId}/edit`);\n }\n }, [navigate, parserId, urlConsoleId]);\n\n // Handle delete\n const handleDelete = useCallback(async () => {\n if (!parserId) return;\n setIsDeleting(true);\n try {\n const success = await deleteParser(parserId);\n if (success) {\n if (isNative()) void nativeNotify('success');\n // Navigate to dashboard-scoped parsers list if consoleId is provided\n if (urlConsoleId) {\n navigate(`/dashboards/${urlConsoleId}/parsers`);\n } else {\n navigate(`/parsers`);\n }\n } else if (isNative()) {\n void nativeNotify('error');\n }\n } catch (err) {\n if (isNative()) void nativeNotify('error');\n } finally {\n setIsDeleting(false);\n setShowDeleteConfirm(false);\n }\n }, [parserId, deleteParser, navigate, urlConsoleId]);\n\n // Handle copy expression\n const handleCopyExpression = useCallback(async () => {\n if (!parser?.expression) return;\n try {\n await nativeCopyText(parser.expression);\n setExpressionCopied(true);\n if (isNative()) void nativeToast('Expression copied');\n setTimeout(() => setExpressionCopied(false), 2000);\n } catch (err) {}\n }, [parser?.expression]);\n\n // Handle test execution\n const handleTestExecute = useCallback(async () => {\n if (!parserId) return;\n setIsTesting(true);\n setTestResult(null);\n try {\n const result = await executeParser(parserId);\n if (result) {\n setTestResult({\n success: result.success,\n output: result.output,\n error: result.error,\n executionTimeMs: result.executionTimeMs,\n });\n }\n } catch (err) {\n setTestResult({\n success: false,\n output: null,\n error: err instanceof Error ? err.message : 'Execution failed',\n executionTimeMs: 0,\n });\n } finally {\n setIsTesting(false);\n }\n }, [parserId, executeParser]);\n\n // Navigate to source datasink\n const handleViewSourceDataSink = useCallback(() => {\n if (sourceDataSink) {\n navigate(`/datasinks/${sourceDataSink.id}`);\n }\n }, [navigate, sourceDataSink]);\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 && !parser) {\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-status-error-text mx-auto mb-4\" />\n <p className=\"text-status-error-text text-body-sm font-medium mb-2\">Failed to load Parser</p>\n <p className=\"text-text-tertiary text-body-xs mb-6\">{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 (!parser) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px] p-card-padding\">\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"Parser not found\"\n description=\"The Parser 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 Parsers\n </Button>\n }\n />\n </div>\n );\n }\n\n return (\n <div className=\"p-card-padding space-y-6\">\n {/* Header */}\n <div className=\"flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4\">\n <div className=\"flex-1\">\n <Button onClick={handleBack} variant=\"ghost\" size=\"sm\" className=\"mb-4\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n Back to Parsers\n </Button>\n <div className=\"flex items-center gap-2 flex-wrap\">\n <h1 className=\"text-heading-h1 font-bold text-text-primary\">{parser.name || 'Untitled'}</h1>\n <ParserTypeBadge type={parser.type} />\n <ParserStatusBadge status={parser.status} />\n </div>\n {parser.description && <p className=\"text-body-sm text-text-secondary mt-2\">{parser.description}</p>}\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center gap-2 flex-wrap\">\n <Button onClick={handleTestExecute} disabled={isTesting} variant=\"secondary\" size=\"default\">\n <Play className=\"w-4 h-4 mr-2\" />\n {isTesting ? 'Running...' : 'Execute'}\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={() => setShowDeleteConfirm(true)} disabled={isDeleting} variant=\"destructive\" size=\"default\">\n <Trash2 className=\"w-4 h-4 mr-2\" />\n Delete\n </Button>\n </div>\n </div>\n\n <PagePurpose>\n A parser turns raw input into structured fields using its expression. Review or copy the expression, run it\n against a sample to see the output, then edit it or use it inside a pipeline to shape incoming data.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"bigconsole-parser-view\"\n steps={[\n {\n id: 'execute',\n label: 'Run a test execution',\n description: 'Check the expression produces the fields you expect.',\n onClick: handleTestExecute,\n },\n {\n id: 'edit',\n label: 'Edit the expression',\n description: 'Refine how this parser maps your input.',\n onClick: handleEdit,\n },\n {\n id: 'pipeline',\n label: 'Use it in a pipeline',\n description: 'Chain this parser with a data sink to process data end to end.',\n onClick: () => navigate('/pipelines'),\n },\n ]}\n />\n\n {/* Main Content Grid */}\n <div className=\"grid gap-6 lg:grid-cols-3\">\n {/* Expression Panel (2/3 width) — primary emphasis zone */}\n <div className=\"lg:col-span-2 space-y-6\">\n {/* Expression */}\n <GlassCard treatment=\"glass\" glow>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0\">\n <CardTitle className=\"flex items-center gap-2\">\n <FileCode2 className=\"w-4 h-4 text-text-secondary\" />\n Expression\n <Badge variant=\"secondary\" className=\"text-xs uppercase\">\n {parser.type}\n </Badge>\n </CardTitle>\n <Button onClick={handleCopyExpression} variant=\"ghost\" size=\"sm\">\n {expressionCopied ? (\n <>\n <Check className=\"w-3.5 h-3.5 text-status-success-text mr-2\" />\n Copied!\n </>\n ) : (\n <>\n <Copy className=\"w-3.5 h-3.5 mr-2\" />\n Copy\n </>\n )}\n </Button>\n </CardHeader>\n <CardContent>\n <ExpressionEditor value={parser.expression} type={parser.type} readOnly height=\"300px\" />\n </CardContent>\n </GlassCard>\n\n {/* Test Result Panel */}\n {testResult && (\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0\">\n <CardTitle className=\"flex items-center gap-2\">\n Execution Result\n <Badge variant={testResult.success ? 'default' : 'destructive'}>\n {testResult.success ? 'Success' : 'Failed'}\n </Badge>\n </CardTitle>\n <Badge variant=\"secondary\" className=\"text-xs\">\n {testResult.executionTimeMs}ms\n </Badge>\n </CardHeader>\n <CardContent>\n {testResult.error ? (\n <div className=\"bg-status-error-bg/5 border border-status-error-border/20 rounded-md p-4\">\n <p className=\"text-body-sm text-status-error-text font-mono\">{testResult.error}</p>\n </div>\n ) : (\n <pre className=\"text-body-sm text-text-primary font-mono bg-bg-sunken rounded-md p-4 overflow-auto max-h-[300px]\">\n {JSON.stringify(testResult.output, null, 2)}\n </pre>\n )}\n </CardContent>\n </Card>\n )}\n </div>\n\n {/* Side Panel (1/3 width) */}\n <div className=\"space-y-6\">\n {/* Data Flow */}\n <Card>\n <CardHeader>\n <CardTitle>Data Flow</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n {/* Source DataSink */}\n <div>\n <label className=\"text-xs font-medium text-text-secondary\">Source DataSink</label>\n {parser.inputSinkKey ? (\n <div className=\"mt-1\">\n <p className=\"text-body-sm text-text-primary font-mono\">{parser.inputSinkKey}</p>\n {sourceDataSink && (\n <Button onClick={handleViewSourceDataSink} variant=\"link\" size=\"sm\" className=\"mt-1 p-0 h-auto\">\n <Database className=\"w-3 h-3 mr-1\" />\n View {sourceDataSink.name || 'DataSink'}\n </Button>\n )}\n </div>\n ) : (\n <p className=\"text-body-sm text-text-tertiary mt-1\">None configured</p>\n )}\n </div>\n\n {/* Arrow */}\n <div className=\"flex items-center justify-center py-1\">\n <ArrowDown className=\"w-4 h-4 text-text-tertiary\" />\n </div>\n\n {/* Output Key */}\n <div>\n <label className=\"text-xs font-medium text-text-secondary\">Output Key</label>\n <p className=\"text-body-sm text-text-primary font-mono mt-1\">\n {parser.outputKey || 'Not configured'}\n </p>\n </div>\n </div>\n </CardContent>\n </Card>\n\n {/* Configuration */}\n <Card>\n <CardHeader>\n <CardTitle>Configuration</CardTitle>\n </CardHeader>\n <CardContent>\n <dl className=\"space-y-4 text-body-sm\">\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Status</dt>\n <dd>\n <ParserStatusBadge status={parser.status} />\n </dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Type</dt>\n <dd>\n <ParserTypeBadge type={parser.type} />\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\">{parser.ttl ? `${parser.ttl}s` : 'No caching'}</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\">{parser.version || 1}</dd>\n </div>\n </dl>\n </CardContent>\n </Card>\n\n {/* Timestamps */}\n <Card>\n <CardHeader>\n <CardTitle>Timestamps</CardTitle>\n </CardHeader>\n <CardContent>\n <dl className=\"space-y-4 text-body-sm\">\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 {parser.createdAt\n ? formatDistanceToNow(new Date(parser.createdAt), { addSuffix: true })\n : 'Unknown'}\n </dd>\n </div>\n <div className=\"flex justify-between items-center\">\n <dt className=\"text-text-secondary\">Updated</dt>\n <dd className=\"text-text-primary font-medium\">\n {parser.updatedAt\n ? formatDistanceToNow(new Date(parser.updatedAt), { addSuffix: true })\n : 'Unknown'}\n </dd>\n </div>\n </dl>\n </CardContent>\n </Card>\n </div>\n </div>\n\n {/* Delete Confirmation Dialog */}\n <Dialog open={showDeleteConfirm} onOpenChange={setShowDeleteConfirm}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Delete Parser</DialogTitle>\n <DialogDescription>\n Are you sure you want to delete <strong>{parser.name}</strong>? This action cannot be undone.\n </DialogDescription>\n </DialogHeader>\n <div className=\"bg-status-warning-bg/10 border border-status-warning-border/20 rounded-md p-4 flex items-start gap-2\">\n <AlertTriangle className=\"w-4 h-4 text-status-warning-text flex-shrink-0 mt-0.5\" />\n <p className=\"text-body-xs text-status-warning-text\">\n Widgets and pipelines using this parser may stop working correctly after deletion.\n </p>\n </div>\n <DialogFooter>\n <Button onClick={() => setShowDeleteConfirm(false)} variant=\"secondary\">\n Cancel\n </Button>\n <Button\n onClick={() => {\n nativeImpact('medium');\n void handleDelete();\n }}\n disabled={isDeleting}\n variant=\"destructive\"\n >\n {isDeleting ? 'Deleting...' : 'Delete Parser'}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n\n {/* Export Parser Dialog */}\n <ExportParserDialog\n isOpen={isExportDialogOpen}\n parserId={parserId || null}\n parserName={parser.name}\n onClose={handleExportClose}\n />\n </div>\n );\n});\n\nexport default ParserViewPage;\n"],"mappings":"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"}
|
|
@@ -242,8 +242,8 @@ var h = ({ className: e }) => /* @__PURE__ */ p("svg", {
|
|
|
242
242
|
className: "flex flex-col items-center justify-center py-16 text-center",
|
|
243
243
|
children: [
|
|
244
244
|
/* @__PURE__ */ p("div", {
|
|
245
|
-
className: "p-3 rounded-full bg-
|
|
246
|
-
children: /* @__PURE__ */ p(b, { className: "w-8 h-8 text-
|
|
245
|
+
className: "p-3 rounded-full bg-status-error-bg/10 mb-4",
|
|
246
|
+
children: /* @__PURE__ */ p(b, { className: "w-8 h-8 text-status-error-text" })
|
|
247
247
|
}),
|
|
248
248
|
/* @__PURE__ */ p("h3", {
|
|
249
249
|
className: "text-lg font-medium text-text-primary mb-2",
|
|
@@ -301,9 +301,9 @@ var h = ({ className: e }) => /* @__PURE__ */ p("svg", {
|
|
|
301
301
|
children: "Build a pipeline by chaining parser stages — each stage reads an input key, runs a parser, and writes a structured output key that the next stage (or a data sink) can use. Name it, add your stages in order, then test it before saving so your data flows end to end."
|
|
302
302
|
}),
|
|
303
303
|
z && /* @__PURE__ */ p("div", {
|
|
304
|
-
className: "mb-6 p-4 bg-
|
|
304
|
+
className: "mb-6 p-4 bg-status-error-bg/10 border border-status-error-border/20 rounded-md",
|
|
305
305
|
children: /* @__PURE__ */ p("p", {
|
|
306
|
-
className: "text-sm text-
|
|
306
|
+
className: "text-sm text-status-error-text",
|
|
307
307
|
children: z
|
|
308
308
|
})
|
|
309
309
|
}),
|
|
@@ -322,7 +322,7 @@ var h = ({ className: e }) => /* @__PURE__ */ p("svg", {
|
|
|
322
322
|
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ m("label", {
|
|
323
323
|
className: "block text-sm font-medium text-text-primary mb-2",
|
|
324
324
|
children: ["Name ", /* @__PURE__ */ p("span", {
|
|
325
|
-
className: "text-
|
|
325
|
+
className: "text-status-error-text",
|
|
326
326
|
children: "*"
|
|
327
327
|
})]
|
|
328
328
|
}), /* @__PURE__ */ p("input", {
|
|
@@ -420,7 +420,7 @@ var h = ({ className: e }) => /* @__PURE__ */ p("svg", {
|
|
|
420
420
|
/* @__PURE__ */ p("button", {
|
|
421
421
|
type: "button",
|
|
422
422
|
onClick: () => X(t),
|
|
423
|
-
className: "p-1 text-text-secondary hover:text-
|
|
423
|
+
className: "p-1 text-text-secondary hover:text-status-error-text hover:bg-status-error-bg/10 rounded",
|
|
424
424
|
children: /* @__PURE__ */ p(_, { className: "w-4 h-4" })
|
|
425
425
|
})
|
|
426
426
|
]
|
|
@@ -433,7 +433,7 @@ var h = ({ className: e }) => /* @__PURE__ */ p("svg", {
|
|
|
433
433
|
children: [/* @__PURE__ */ m("label", {
|
|
434
434
|
className: "block text-xs font-medium text-text-secondary mb-1",
|
|
435
435
|
children: ["Parser ", /* @__PURE__ */ p("span", {
|
|
436
|
-
className: "text-
|
|
436
|
+
className: "text-status-error-text",
|
|
437
437
|
children: "*"
|
|
438
438
|
})]
|
|
439
439
|
}), /* @__PURE__ */ m("select", {
|
|
@@ -457,7 +457,7 @@ var h = ({ className: e }) => /* @__PURE__ */ p("svg", {
|
|
|
457
457
|
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ m("label", {
|
|
458
458
|
className: "block text-xs font-medium text-text-secondary mb-1",
|
|
459
459
|
children: ["Input Key ", /* @__PURE__ */ p("span", {
|
|
460
|
-
className: "text-
|
|
460
|
+
className: "text-status-error-text",
|
|
461
461
|
children: "*"
|
|
462
462
|
})]
|
|
463
463
|
}), /* @__PURE__ */ p("input", {
|
|
@@ -470,7 +470,7 @@ var h = ({ className: e }) => /* @__PURE__ */ p("svg", {
|
|
|
470
470
|
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ m("label", {
|
|
471
471
|
className: "block text-xs font-medium text-text-secondary mb-1",
|
|
472
472
|
children: ["Output Key ", /* @__PURE__ */ p("span", {
|
|
473
|
-
className: "text-
|
|
473
|
+
className: "text-status-error-text",
|
|
474
474
|
children: "*"
|
|
475
475
|
})]
|
|
476
476
|
}), /* @__PURE__ */ p("input", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PipelineBuilderPage.js","names":[],"sources":["../../../src/bigconsole/pages/PipelineBuilderPage.tsx"],"sourcesContent":["/**\n * Pipeline Builder Page\n *\n * Create and edit Pipelines with stage management.\n * Supports adding, removing, and reordering stages.\n */\n\nimport { memo, useState, useCallback, useEffect, useMemo } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { GlassCard, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { useAppNavigate } from '../contexts';\nimport { usePipelineOperations } from '../hooks/usePipelineOperations';\nimport { useParserOperations } from '../hooks/useParserOperations';\nimport { PipelineStatusBadge } from '../components/pipeline/PipelineStatusBadge';\nimport type { PipelineStatus, StageErrorHandling, ParserType } from '../types';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface StageForm {\n id?: string;\n parserId: string;\n parserName: string;\n parserType: ParserType | null;\n inputKey: string;\n outputKey: string;\n enabled: boolean;\n onError: StageErrorHandling;\n fallbackValue: string;\n description: string;\n}\n\n// ============================================================================\n// ICONS\n// ============================================================================\n\nconst BackIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M10 19l-7-7m0 0l7-7m-7 7h18\" />\n </svg>\n);\n\nconst PlusIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 4v16m8-8H4\" />\n </svg>\n);\n\nconst TrashIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n />\n </svg>\n);\n\nconst ArrowUpIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M5 15l7-7 7 7\" />\n </svg>\n);\n\nconst ArrowDownIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n);\n\nconst ErrorIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n);\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst STATUS_OPTIONS: { value: PipelineStatus; label: string }[] = [\n { value: 'draft', label: 'Draft' },\n { value: 'active', label: 'Active' },\n { value: 'inactive', label: 'Inactive' },\n];\n\nconst ERROR_HANDLING_OPTIONS: { value: StageErrorHandling; label: string; description: string }[] = [\n { value: 'fail', label: 'Fail', description: 'Stop pipeline execution on error' },\n { value: 'skip', label: 'Skip', description: 'Skip this stage and continue' },\n { value: 'fallback', label: 'Fallback', description: 'Use fallback value on error' },\n];\n\nconst DEFAULT_STAGE: StageForm = {\n parserId: '',\n parserName: '',\n parserType: null,\n inputKey: 'data',\n outputKey: 'result',\n enabled: true,\n onError: 'fail',\n fallbackValue: '',\n description: '',\n};\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const PipelineBuilderPage = memo(function PipelineBuilderPage() {\n const { pipelineId } = useParams<{ pipelineId: string }>();\n const navigate = useAppNavigate();\n const isEditMode = !!pipelineId && pipelineId !== 'new';\n // Use default consoleId for now (should come from context in production)\n const consoleId = 'default';\n\n // Form state\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [status, setStatus] = useState<PipelineStatus>('draft');\n const [stages, setStages] = useState<StageForm[]>([]);\n const [version, setVersion] = useState(1);\n const [isSaving, setIsSaving] = useState(false);\n const [saveError, setSaveError] = useState<string | null>(null);\n\n // Operations\n const {\n loading: pipelineLoading,\n error: pipelineError,\n fetchPipeline,\n createPipeline,\n updatePipeline,\n } = usePipelineOperations({\n consoleId,\n skipFetch: true,\n });\n\n const { parsers } = useParserOperations({\n consoleId,\n });\n\n // Load existing pipeline in edit mode\n useEffect(() => {\n if (isEditMode && pipelineId) {\n fetchPipeline(pipelineId).then((pipeline) => {\n if (pipeline) {\n setName(pipeline.name);\n setDescription(pipeline.description || '');\n setStatus(pipeline.status);\n setVersion(pipeline.version);\n setStages(\n (pipeline.stages || []).map((s) => ({\n id: s.id,\n parserId: s.parserId,\n parserName: s.parserName || '',\n parserType: s.parserType,\n inputKey: s.inputKey,\n outputKey: s.outputKey,\n enabled: s.enabled,\n onError: s.onError,\n fallbackValue: s.fallbackValue ? JSON.stringify(s.fallbackValue) : '',\n description: s.description || '',\n }))\n );\n }\n });\n }\n }, [isEditMode, pipelineId, fetchPipeline]);\n\n // Validation\n const isValid = useMemo(() => {\n if (!name.trim()) return false;\n if (stages.length === 0) return false;\n return stages.every((s) => s.parserId && s.inputKey && s.outputKey);\n }, [name, stages]);\n\n // Handlers\n const handleBack = useCallback(() => {\n navigate(`/pipelines`);\n }, [navigate]);\n\n const handleAddStage = useCallback(() => {\n setStages((prev) => [...prev, { ...DEFAULT_STAGE }]);\n }, []);\n\n const handleRemoveStage = useCallback((index: number) => {\n setStages((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n const handleMoveStage = useCallback((index: number, direction: 'up' | 'down') => {\n setStages((prev) => {\n const newStages = [...prev];\n const targetIndex = direction === 'up' ? index - 1 : index + 1;\n if (targetIndex < 0 || targetIndex >= newStages.length) return prev;\n [newStages[index], newStages[targetIndex]] = [newStages[targetIndex], newStages[index]];\n return newStages;\n });\n }, []);\n\n const handleUpdateStage = useCallback((index: number, updates: Partial<StageForm>) => {\n setStages((prev) => prev.map((stage, i) => (i === index ? { ...stage, ...updates } : stage)));\n }, []);\n\n const handleParserSelect = useCallback(\n (index: number, parserId: string) => {\n const parser = parsers.find((p) => p.id === parserId);\n if (parser) {\n handleUpdateStage(index, {\n parserId: parser.id,\n parserName: parser.name,\n parserType: parser.type,\n });\n }\n },\n [parsers, handleUpdateStage]\n );\n\n const handleSave = useCallback(async () => {\n if (!isValid || !consoleId) return;\n\n setIsSaving(true);\n setSaveError(null);\n\n try {\n const stageInputs = stages.map((s) => ({\n parserId: s.parserId,\n parserName: s.parserName,\n parserType: s.parserType || undefined,\n inputKey: s.inputKey,\n outputKey: s.outputKey,\n enabled: s.enabled,\n onError: s.onError,\n fallbackValue: s.fallbackValue ? JSON.parse(s.fallbackValue) : undefined,\n description: s.description || undefined,\n }));\n\n if (isEditMode && pipelineId) {\n const result = await updatePipeline(\n pipelineId,\n {\n name,\n description: description || undefined,\n status,\n },\n version\n );\n if (result) {\n navigate(`/pipelines/${pipelineId}`);\n }\n } else {\n const result = await createPipeline({\n consoleId,\n name,\n description: description || undefined,\n status,\n stages: stageInputs,\n });\n if (result) {\n navigate(`/pipelines/${result.id}`);\n }\n }\n } catch (err) {\n setSaveError(err instanceof Error ? err.message : 'Failed to save pipeline');\n } finally {\n setIsSaving(false);\n }\n }, [\n isValid,\n consoleId,\n isEditMode,\n pipelineId,\n name,\n description,\n status,\n stages,\n version,\n createPipeline,\n updatePipeline,\n navigate,\n ]);\n\n // Loading state\n if (pipelineLoading && isEditMode) {\n return (\n <div className=\"p-6\">\n <div className=\"flex flex-col items-center justify-center py-16\">\n <svg className=\"w-8 h-8 text-action-primary-bg animate-spin mb-4\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n <p className=\"text-sm text-text-secondary\">Loading Pipeline...</p>\n </div>\n </div>\n );\n }\n\n // Error state\n if (pipelineError) {\n return (\n <div className=\"p-6\">\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n <div className=\"p-3 rounded-full bg-state-error/10 mb-4\">\n <ErrorIcon className=\"w-8 h-8 text-state-error\" />\n </div>\n <h3 className=\"text-lg font-medium text-text-primary mb-2\">Failed to load Pipeline</h3>\n <p className=\"text-sm text-text-secondary mb-4\">{pipelineError.message}</p>\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"px-4 py-2 text-sm font-medium text-action-primary-fg bg-action-primary-bg hover:bg-action-primary-bgHover rounded-md transition-colors\"\n >\n Back to Pipelines\n </button>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"p-6\">\n {/* Header */}\n <div className=\"flex items-center justify-between mb-6\">\n <div className=\"flex items-center gap-4\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"p-2 text-text-secondary hover:text-text-primary hover:bg-bg-sunken rounded-md transition-colors\"\n >\n <BackIcon className=\"w-5 h-5\" />\n </button>\n <div>\n <h1 className=\"text-2xl font-bold text-text-primary\">{isEditMode ? 'Edit Pipeline' : 'Create Pipeline'}</h1>\n <p className=\"text-sm text-text-secondary mt-1\">\n {isEditMode ? 'Update pipeline settings and stages' : 'Create a new data transformation pipeline'}\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"px-4 py-2 text-sm font-medium text-text-primary bg-bg-sunken hover:bg-border-default rounded-md transition-colors\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleSave}\n disabled={!isValid || isSaving}\n className=\"px-4 py-2 text-sm font-medium text-action-primary-fg bg-action-primary-bg hover:bg-action-primary-bgHover rounded-md transition-colors disabled:opacity-50\"\n >\n {isSaving ? 'Saving...' : isEditMode ? 'Save Changes' : 'Create Pipeline'}\n </button>\n </div>\n </div>\n\n <PagePurpose className=\"mb-6\">\n Build a pipeline by chaining parser stages — each stage reads an input key, runs a parser, and writes a\n structured output key that the next stage (or a data sink) can use. Name it, add your stages in order, then test\n it before saving so your data flows end to end.\n </PagePurpose>\n\n {/* Error Message */}\n {saveError && (\n <div className=\"mb-6 p-4 bg-state-error/10 border border-state-error/20 rounded-md\">\n <p className=\"text-sm text-state-error\">{saveError}</p>\n </div>\n )}\n\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n {/* Main Form */}\n <div className=\"lg:col-span-2 space-y-6\">\n {/* Basic Info */}\n <div className=\"bg-bg-surface border border-border-default rounded-lg p-6\">\n <h2 className=\"text-lg font-semibold text-text-primary mb-4\">Basic Information</h2>\n\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-2\">\n Name <span className=\"text-state-error\">*</span>\n </label>\n <input\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"My Pipeline\"\n className=\"w-full px-3 py-2 text-sm text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-2\">Description</label>\n <textarea\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"What does this pipeline do?\"\n rows={3}\n className=\"w-full px-3 py-2 text-sm text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg resize-none\"\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-2\">Status</label>\n <select\n value={status}\n onChange={(e) => setStatus(e.target.value as PipelineStatus)}\n className=\"w-full px-3 py-2 text-sm text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n {STATUS_OPTIONS.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </div>\n </div>\n </div>\n\n {/* Stages — primary emphasis zone */}\n <GlassCard treatment=\"glass\" glow className=\"p-6\">\n <div className=\"flex items-center justify-between mb-4\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Stages ({stages.length})</h2>\n <button\n type=\"button\"\n onClick={handleAddStage}\n className=\"inline-flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-action-primary-fg bg-action-primary-bg hover:bg-action-primary-bgHover rounded-md transition-colors\"\n >\n <PlusIcon className=\"w-4 h-4\" />\n Add Stage\n </button>\n </div>\n\n {stages.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No stages yet\"\n description=\"Add a stage to start building your pipeline.\"\n action={\n <button\n type=\"button\"\n onClick={handleAddStage}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-fg bg-action-primary-bg hover:bg-action-primary-bgHover rounded-md transition-colors\"\n >\n <PlusIcon className=\"w-4 h-4\" />\n Add First Stage\n </button>\n }\n />\n ) : (\n <div className=\"space-y-4\">\n {stages.map((stage, index) => (\n <div key={index} className=\"p-4 bg-bg-sunken border border-border-default rounded-lg\">\n <div className=\"flex items-center justify-between mb-4\">\n <div className=\"flex items-center gap-2\">\n <span className=\"w-6 h-6 flex items-center justify-center text-xs font-medium bg-action-primary-bg/10 text-action-primary-bg rounded-full\">\n {index + 1}\n </span>\n <span className=\"font-medium text-text-primary\">\n {stage.parserName || `Stage ${index + 1}`}\n </span>\n </div>\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => handleMoveStage(index, 'up')}\n disabled={index === 0}\n className=\"p-1 text-text-secondary hover:text-text-primary hover:bg-bg-surface rounded disabled:opacity-30\"\n >\n <ArrowUpIcon className=\"w-4 h-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => handleMoveStage(index, 'down')}\n disabled={index === stages.length - 1}\n className=\"p-1 text-text-secondary hover:text-text-primary hover:bg-bg-surface rounded disabled:opacity-30\"\n >\n <ArrowDownIcon className=\"w-4 h-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => handleRemoveStage(index)}\n className=\"p-1 text-text-secondary hover:text-state-error hover:bg-state-error/10 rounded\"\n >\n <TrashIcon className=\"w-4 h-4\" />\n </button>\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div className=\"col-span-2\">\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n Parser <span className=\"text-state-error\">*</span>\n </label>\n <select\n value={stage.parserId}\n onChange={(e) => handleParserSelect(index, e.target.value)}\n className=\"w-full px-3 py-2 text-sm text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n <option value=\"\">Select a parser...</option>\n {parsers.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name} ({p.type.toUpperCase()})\n </option>\n ))}\n </select>\n </div>\n\n <div>\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n Input Key <span className=\"text-state-error\">*</span>\n </label>\n <input\n type=\"text\"\n value={stage.inputKey}\n onChange={(e) => handleUpdateStage(index, { inputKey: e.target.value })}\n placeholder=\"data\"\n className=\"w-full px-3 py-2 text-sm font-mono text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n </div>\n\n <div>\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n Output Key <span className=\"text-state-error\">*</span>\n </label>\n <input\n type=\"text\"\n value={stage.outputKey}\n onChange={(e) => handleUpdateStage(index, { outputKey: e.target.value })}\n placeholder=\"result\"\n className=\"w-full px-3 py-2 text-sm font-mono text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n </div>\n\n <div>\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">On Error</label>\n <select\n value={stage.onError}\n onChange={(e) =>\n handleUpdateStage(index, {\n onError: e.target.value as StageErrorHandling,\n })\n }\n className=\"w-full px-3 py-2 text-sm text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n {ERROR_HANDLING_OPTIONS.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </div>\n\n <div className=\"flex items-center\">\n <label className=\"flex items-center gap-2 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={stage.enabled}\n onChange={(e) => handleUpdateStage(index, { enabled: e.target.checked })}\n className=\"w-4 h-4 rounded border-border-default text-action-primary-bg focus:ring-action-primary-bg\"\n />\n <span className=\"text-sm text-text-primary\">Enabled</span>\n </label>\n </div>\n\n {stage.onError === 'fallback' && (\n <div className=\"col-span-2\">\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n Fallback Value (JSON)\n </label>\n <input\n type=\"text\"\n value={stage.fallbackValue}\n onChange={(e) => handleUpdateStage(index, { fallbackValue: e.target.value })}\n placeholder='{\"default\": true}'\n className=\"w-full px-3 py-2 text-sm font-mono text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n </div>\n )}\n </div>\n </div>\n ))}\n </div>\n )}\n </GlassCard>\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-6\">\n {/* Preview */}\n <div className=\"bg-bg-surface border border-border-default rounded-lg p-6\">\n <h2 className=\"text-lg font-semibold text-text-primary mb-4\">Preview</h2>\n\n <div className=\"space-y-3\">\n <div>\n <span className=\"text-xs text-text-secondary\">Name</span>\n <p className=\"text-sm text-text-primary\">{name || 'Untitled'}</p>\n </div>\n\n <div>\n <span className=\"text-xs text-text-secondary\">Status</span>\n <div className=\"mt-1\">\n <PipelineStatusBadge status={status} />\n </div>\n </div>\n\n <div>\n <span className=\"text-xs text-text-secondary\">Stages</span>\n <p className=\"text-sm text-text-primary\">{stages.length}</p>\n </div>\n\n {stages.length > 0 && (\n <div>\n <span className=\"text-xs text-text-secondary\">Data Flow</span>\n <div className=\"mt-1 text-xs font-mono text-text-secondary\">\n {stages.map((s, i) => (\n <span key={i}>\n {s.inputKey}\n {i < stages.length - 1 && ' → '}\n </span>\n ))}\n {stages.length > 0 && ` → ${stages[stages.length - 1].outputKey}`}\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Help */}\n <div className=\"bg-bg-sunken border border-border-default rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary mb-2\">Tips</h3>\n <ul className=\"text-xs text-text-secondary space-y-2\">\n <li>• Each stage processes the output of the previous stage</li>\n <li>• Use consistent input/output keys to chain data</li>\n <li>• Set error handling per stage for robustness</li>\n <li>• Disable stages to skip them during execution</li>\n </ul>\n </div>\n </div>\n </div>\n </div>\n );\n});\n\nexport default PipelineBuilderPage;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PipelineBuilderPage.js","names":[],"sources":["../../../src/bigconsole/pages/PipelineBuilderPage.tsx"],"sourcesContent":["/**\n * Pipeline Builder Page\n *\n * Create and edit Pipelines with stage management.\n * Supports adding, removing, and reordering stages.\n */\n\nimport { memo, useState, useCallback, useEffect, useMemo } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { GlassCard, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { useAppNavigate } from '../contexts';\nimport { usePipelineOperations } from '../hooks/usePipelineOperations';\nimport { useParserOperations } from '../hooks/useParserOperations';\nimport { PipelineStatusBadge } from '../components/pipeline/PipelineStatusBadge';\nimport type { PipelineStatus, StageErrorHandling, ParserType } from '../types';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface StageForm {\n id?: string;\n parserId: string;\n parserName: string;\n parserType: ParserType | null;\n inputKey: string;\n outputKey: string;\n enabled: boolean;\n onError: StageErrorHandling;\n fallbackValue: string;\n description: string;\n}\n\n// ============================================================================\n// ICONS\n// ============================================================================\n\nconst BackIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M10 19l-7-7m0 0l7-7m-7 7h18\" />\n </svg>\n);\n\nconst PlusIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 4v16m8-8H4\" />\n </svg>\n);\n\nconst TrashIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n />\n </svg>\n);\n\nconst ArrowUpIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M5 15l7-7 7 7\" />\n </svg>\n);\n\nconst ArrowDownIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n);\n\nconst ErrorIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n);\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst STATUS_OPTIONS: { value: PipelineStatus; label: string }[] = [\n { value: 'draft', label: 'Draft' },\n { value: 'active', label: 'Active' },\n { value: 'inactive', label: 'Inactive' },\n];\n\nconst ERROR_HANDLING_OPTIONS: { value: StageErrorHandling; label: string; description: string }[] = [\n { value: 'fail', label: 'Fail', description: 'Stop pipeline execution on error' },\n { value: 'skip', label: 'Skip', description: 'Skip this stage and continue' },\n { value: 'fallback', label: 'Fallback', description: 'Use fallback value on error' },\n];\n\nconst DEFAULT_STAGE: StageForm = {\n parserId: '',\n parserName: '',\n parserType: null,\n inputKey: 'data',\n outputKey: 'result',\n enabled: true,\n onError: 'fail',\n fallbackValue: '',\n description: '',\n};\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const PipelineBuilderPage = memo(function PipelineBuilderPage() {\n const { pipelineId } = useParams<{ pipelineId: string }>();\n const navigate = useAppNavigate();\n const isEditMode = !!pipelineId && pipelineId !== 'new';\n // Use default consoleId for now (should come from context in production)\n const consoleId = 'default';\n\n // Form state\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [status, setStatus] = useState<PipelineStatus>('draft');\n const [stages, setStages] = useState<StageForm[]>([]);\n const [version, setVersion] = useState(1);\n const [isSaving, setIsSaving] = useState(false);\n const [saveError, setSaveError] = useState<string | null>(null);\n\n // Operations\n const {\n loading: pipelineLoading,\n error: pipelineError,\n fetchPipeline,\n createPipeline,\n updatePipeline,\n } = usePipelineOperations({\n consoleId,\n skipFetch: true,\n });\n\n const { parsers } = useParserOperations({\n consoleId,\n });\n\n // Load existing pipeline in edit mode\n useEffect(() => {\n if (isEditMode && pipelineId) {\n fetchPipeline(pipelineId).then((pipeline) => {\n if (pipeline) {\n setName(pipeline.name);\n setDescription(pipeline.description || '');\n setStatus(pipeline.status);\n setVersion(pipeline.version);\n setStages(\n (pipeline.stages || []).map((s) => ({\n id: s.id,\n parserId: s.parserId,\n parserName: s.parserName || '',\n parserType: s.parserType,\n inputKey: s.inputKey,\n outputKey: s.outputKey,\n enabled: s.enabled,\n onError: s.onError,\n fallbackValue: s.fallbackValue ? JSON.stringify(s.fallbackValue) : '',\n description: s.description || '',\n }))\n );\n }\n });\n }\n }, [isEditMode, pipelineId, fetchPipeline]);\n\n // Validation\n const isValid = useMemo(() => {\n if (!name.trim()) return false;\n if (stages.length === 0) return false;\n return stages.every((s) => s.parserId && s.inputKey && s.outputKey);\n }, [name, stages]);\n\n // Handlers\n const handleBack = useCallback(() => {\n navigate(`/pipelines`);\n }, [navigate]);\n\n const handleAddStage = useCallback(() => {\n setStages((prev) => [...prev, { ...DEFAULT_STAGE }]);\n }, []);\n\n const handleRemoveStage = useCallback((index: number) => {\n setStages((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n const handleMoveStage = useCallback((index: number, direction: 'up' | 'down') => {\n setStages((prev) => {\n const newStages = [...prev];\n const targetIndex = direction === 'up' ? index - 1 : index + 1;\n if (targetIndex < 0 || targetIndex >= newStages.length) return prev;\n [newStages[index], newStages[targetIndex]] = [newStages[targetIndex], newStages[index]];\n return newStages;\n });\n }, []);\n\n const handleUpdateStage = useCallback((index: number, updates: Partial<StageForm>) => {\n setStages((prev) => prev.map((stage, i) => (i === index ? { ...stage, ...updates } : stage)));\n }, []);\n\n const handleParserSelect = useCallback(\n (index: number, parserId: string) => {\n const parser = parsers.find((p) => p.id === parserId);\n if (parser) {\n handleUpdateStage(index, {\n parserId: parser.id,\n parserName: parser.name,\n parserType: parser.type,\n });\n }\n },\n [parsers, handleUpdateStage]\n );\n\n const handleSave = useCallback(async () => {\n if (!isValid || !consoleId) return;\n\n setIsSaving(true);\n setSaveError(null);\n\n try {\n const stageInputs = stages.map((s) => ({\n parserId: s.parserId,\n parserName: s.parserName,\n parserType: s.parserType || undefined,\n inputKey: s.inputKey,\n outputKey: s.outputKey,\n enabled: s.enabled,\n onError: s.onError,\n fallbackValue: s.fallbackValue ? JSON.parse(s.fallbackValue) : undefined,\n description: s.description || undefined,\n }));\n\n if (isEditMode && pipelineId) {\n const result = await updatePipeline(\n pipelineId,\n {\n name,\n description: description || undefined,\n status,\n },\n version\n );\n if (result) {\n navigate(`/pipelines/${pipelineId}`);\n }\n } else {\n const result = await createPipeline({\n consoleId,\n name,\n description: description || undefined,\n status,\n stages: stageInputs,\n });\n if (result) {\n navigate(`/pipelines/${result.id}`);\n }\n }\n } catch (err) {\n setSaveError(err instanceof Error ? err.message : 'Failed to save pipeline');\n } finally {\n setIsSaving(false);\n }\n }, [\n isValid,\n consoleId,\n isEditMode,\n pipelineId,\n name,\n description,\n status,\n stages,\n version,\n createPipeline,\n updatePipeline,\n navigate,\n ]);\n\n // Loading state\n if (pipelineLoading && isEditMode) {\n return (\n <div className=\"p-6\">\n <div className=\"flex flex-col items-center justify-center py-16\">\n <svg className=\"w-8 h-8 text-action-primary-bg animate-spin mb-4\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n <p className=\"text-sm text-text-secondary\">Loading Pipeline...</p>\n </div>\n </div>\n );\n }\n\n // Error state\n if (pipelineError) {\n return (\n <div className=\"p-6\">\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n <div className=\"p-3 rounded-full bg-status-error-bg/10 mb-4\">\n <ErrorIcon className=\"w-8 h-8 text-status-error-text\" />\n </div>\n <h3 className=\"text-lg font-medium text-text-primary mb-2\">Failed to load Pipeline</h3>\n <p className=\"text-sm text-text-secondary mb-4\">{pipelineError.message}</p>\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"px-4 py-2 text-sm font-medium text-action-primary-fg bg-action-primary-bg hover:bg-action-primary-bgHover rounded-md transition-colors\"\n >\n Back to Pipelines\n </button>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"p-6\">\n {/* Header */}\n <div className=\"flex items-center justify-between mb-6\">\n <div className=\"flex items-center gap-4\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"p-2 text-text-secondary hover:text-text-primary hover:bg-bg-sunken rounded-md transition-colors\"\n >\n <BackIcon className=\"w-5 h-5\" />\n </button>\n <div>\n <h1 className=\"text-2xl font-bold text-text-primary\">{isEditMode ? 'Edit Pipeline' : 'Create Pipeline'}</h1>\n <p className=\"text-sm text-text-secondary mt-1\">\n {isEditMode ? 'Update pipeline settings and stages' : 'Create a new data transformation pipeline'}\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"px-4 py-2 text-sm font-medium text-text-primary bg-bg-sunken hover:bg-border-default rounded-md transition-colors\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleSave}\n disabled={!isValid || isSaving}\n className=\"px-4 py-2 text-sm font-medium text-action-primary-fg bg-action-primary-bg hover:bg-action-primary-bgHover rounded-md transition-colors disabled:opacity-50\"\n >\n {isSaving ? 'Saving...' : isEditMode ? 'Save Changes' : 'Create Pipeline'}\n </button>\n </div>\n </div>\n\n <PagePurpose className=\"mb-6\">\n Build a pipeline by chaining parser stages — each stage reads an input key, runs a parser, and writes a\n structured output key that the next stage (or a data sink) can use. Name it, add your stages in order, then test\n it before saving so your data flows end to end.\n </PagePurpose>\n\n {/* Error Message */}\n {saveError && (\n <div className=\"mb-6 p-4 bg-status-error-bg/10 border border-status-error-border/20 rounded-md\">\n <p className=\"text-sm text-status-error-text\">{saveError}</p>\n </div>\n )}\n\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n {/* Main Form */}\n <div className=\"lg:col-span-2 space-y-6\">\n {/* Basic Info */}\n <div className=\"bg-bg-surface border border-border-default rounded-lg p-6\">\n <h2 className=\"text-lg font-semibold text-text-primary mb-4\">Basic Information</h2>\n\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-2\">\n Name <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"My Pipeline\"\n className=\"w-full px-3 py-2 text-sm text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-2\">Description</label>\n <textarea\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"What does this pipeline do?\"\n rows={3}\n className=\"w-full px-3 py-2 text-sm text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg resize-none\"\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-2\">Status</label>\n <select\n value={status}\n onChange={(e) => setStatus(e.target.value as PipelineStatus)}\n className=\"w-full px-3 py-2 text-sm text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n {STATUS_OPTIONS.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </div>\n </div>\n </div>\n\n {/* Stages — primary emphasis zone */}\n <GlassCard treatment=\"glass\" glow className=\"p-6\">\n <div className=\"flex items-center justify-between mb-4\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Stages ({stages.length})</h2>\n <button\n type=\"button\"\n onClick={handleAddStage}\n className=\"inline-flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-action-primary-fg bg-action-primary-bg hover:bg-action-primary-bgHover rounded-md transition-colors\"\n >\n <PlusIcon className=\"w-4 h-4\" />\n Add Stage\n </button>\n </div>\n\n {stages.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No stages yet\"\n description=\"Add a stage to start building your pipeline.\"\n action={\n <button\n type=\"button\"\n onClick={handleAddStage}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-fg bg-action-primary-bg hover:bg-action-primary-bgHover rounded-md transition-colors\"\n >\n <PlusIcon className=\"w-4 h-4\" />\n Add First Stage\n </button>\n }\n />\n ) : (\n <div className=\"space-y-4\">\n {stages.map((stage, index) => (\n <div key={index} className=\"p-4 bg-bg-sunken border border-border-default rounded-lg\">\n <div className=\"flex items-center justify-between mb-4\">\n <div className=\"flex items-center gap-2\">\n <span className=\"w-6 h-6 flex items-center justify-center text-xs font-medium bg-action-primary-bg/10 text-action-primary-bg rounded-full\">\n {index + 1}\n </span>\n <span className=\"font-medium text-text-primary\">\n {stage.parserName || `Stage ${index + 1}`}\n </span>\n </div>\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => handleMoveStage(index, 'up')}\n disabled={index === 0}\n className=\"p-1 text-text-secondary hover:text-text-primary hover:bg-bg-surface rounded disabled:opacity-30\"\n >\n <ArrowUpIcon className=\"w-4 h-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => handleMoveStage(index, 'down')}\n disabled={index === stages.length - 1}\n className=\"p-1 text-text-secondary hover:text-text-primary hover:bg-bg-surface rounded disabled:opacity-30\"\n >\n <ArrowDownIcon className=\"w-4 h-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => handleRemoveStage(index)}\n className=\"p-1 text-text-secondary hover:text-status-error-text hover:bg-status-error-bg/10 rounded\"\n >\n <TrashIcon className=\"w-4 h-4\" />\n </button>\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div className=\"col-span-2\">\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n Parser <span className=\"text-status-error-text\">*</span>\n </label>\n <select\n value={stage.parserId}\n onChange={(e) => handleParserSelect(index, e.target.value)}\n className=\"w-full px-3 py-2 text-sm text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n <option value=\"\">Select a parser...</option>\n {parsers.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name} ({p.type.toUpperCase()})\n </option>\n ))}\n </select>\n </div>\n\n <div>\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n Input Key <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n type=\"text\"\n value={stage.inputKey}\n onChange={(e) => handleUpdateStage(index, { inputKey: e.target.value })}\n placeholder=\"data\"\n className=\"w-full px-3 py-2 text-sm font-mono text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n </div>\n\n <div>\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n Output Key <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n type=\"text\"\n value={stage.outputKey}\n onChange={(e) => handleUpdateStage(index, { outputKey: e.target.value })}\n placeholder=\"result\"\n className=\"w-full px-3 py-2 text-sm font-mono text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n </div>\n\n <div>\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">On Error</label>\n <select\n value={stage.onError}\n onChange={(e) =>\n handleUpdateStage(index, {\n onError: e.target.value as StageErrorHandling,\n })\n }\n className=\"w-full px-3 py-2 text-sm text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n {ERROR_HANDLING_OPTIONS.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </div>\n\n <div className=\"flex items-center\">\n <label className=\"flex items-center gap-2 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={stage.enabled}\n onChange={(e) => handleUpdateStage(index, { enabled: e.target.checked })}\n className=\"w-4 h-4 rounded border-border-default text-action-primary-bg focus:ring-action-primary-bg\"\n />\n <span className=\"text-sm text-text-primary\">Enabled</span>\n </label>\n </div>\n\n {stage.onError === 'fallback' && (\n <div className=\"col-span-2\">\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n Fallback Value (JSON)\n </label>\n <input\n type=\"text\"\n value={stage.fallbackValue}\n onChange={(e) => handleUpdateStage(index, { fallbackValue: e.target.value })}\n placeholder='{\"default\": true}'\n className=\"w-full px-3 py-2 text-sm font-mono text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n </div>\n )}\n </div>\n </div>\n ))}\n </div>\n )}\n </GlassCard>\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-6\">\n {/* Preview */}\n <div className=\"bg-bg-surface border border-border-default rounded-lg p-6\">\n <h2 className=\"text-lg font-semibold text-text-primary mb-4\">Preview</h2>\n\n <div className=\"space-y-3\">\n <div>\n <span className=\"text-xs text-text-secondary\">Name</span>\n <p className=\"text-sm text-text-primary\">{name || 'Untitled'}</p>\n </div>\n\n <div>\n <span className=\"text-xs text-text-secondary\">Status</span>\n <div className=\"mt-1\">\n <PipelineStatusBadge status={status} />\n </div>\n </div>\n\n <div>\n <span className=\"text-xs text-text-secondary\">Stages</span>\n <p className=\"text-sm text-text-primary\">{stages.length}</p>\n </div>\n\n {stages.length > 0 && (\n <div>\n <span className=\"text-xs text-text-secondary\">Data Flow</span>\n <div className=\"mt-1 text-xs font-mono text-text-secondary\">\n {stages.map((s, i) => (\n <span key={i}>\n {s.inputKey}\n {i < stages.length - 1 && ' → '}\n </span>\n ))}\n {stages.length > 0 && ` → ${stages[stages.length - 1].outputKey}`}\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Help */}\n <div className=\"bg-bg-sunken border border-border-default rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary mb-2\">Tips</h3>\n <ul className=\"text-xs text-text-secondary space-y-2\">\n <li>• Each stage processes the output of the previous stage</li>\n <li>• Use consistent input/output keys to chain data</li>\n <li>• Set error handling per stage for robustness</li>\n <li>• Disable stages to skip them during execution</li>\n </ul>\n </div>\n </div>\n </div>\n </div>\n );\n});\n\nexport default PipelineBuilderPage;\n"],"mappings":"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"}
|
|
@@ -96,11 +96,11 @@ var b = ({ className: e }) => /* @__PURE__ */ v("svg", {
|
|
|
96
96
|
let t = {
|
|
97
97
|
fail: {
|
|
98
98
|
label: "Fail",
|
|
99
|
-
className: "bg-
|
|
99
|
+
className: "bg-status-error-bg/10 text-status-error-text"
|
|
100
100
|
},
|
|
101
101
|
skip: {
|
|
102
102
|
label: "Skip",
|
|
103
|
-
className: "bg-
|
|
103
|
+
className: "bg-status-warning-bg/10 text-status-warning-text"
|
|
104
104
|
},
|
|
105
105
|
fallback: {
|
|
106
106
|
label: "Fallback",
|
|
@@ -180,8 +180,8 @@ var b = ({ className: e }) => /* @__PURE__ */ v("svg", {
|
|
|
180
180
|
className: "flex flex-col items-center justify-center py-16 text-center",
|
|
181
181
|
children: [
|
|
182
182
|
/* @__PURE__ */ v("div", {
|
|
183
|
-
className: "p-3 rounded-full bg-
|
|
184
|
-
children: /* @__PURE__ */ v(w, { className: "w-8 h-8 text-
|
|
183
|
+
className: "p-3 rounded-full bg-status-error-bg/10 mb-4",
|
|
184
|
+
children: /* @__PURE__ */ v(w, { className: "w-8 h-8 text-status-error-text" })
|
|
185
185
|
}),
|
|
186
186
|
/* @__PURE__ */ v("h3", {
|
|
187
187
|
className: "text-lg font-medium text-text-primary mb-2",
|
|
@@ -227,7 +227,7 @@ var b = ({ className: e }) => /* @__PURE__ */ v("svg", {
|
|
|
227
227
|
/* @__PURE__ */ y("button", {
|
|
228
228
|
type: "button",
|
|
229
229
|
onClick: () => R(!L),
|
|
230
|
-
className: "inline-flex items-center gap-2 px-3 py-2 text-sm font-medium text-
|
|
230
|
+
className: "inline-flex items-center gap-2 px-3 py-2 text-sm font-medium text-status-success-text bg-status-success-bg/10 hover:bg-status-success-bg/20 rounded-md transition-colors",
|
|
231
231
|
children: [/* @__PURE__ */ v(C, { className: "w-4 h-4" }), "Test"]
|
|
232
232
|
}),
|
|
233
233
|
/* @__PURE__ */ y("button", {
|
|
@@ -239,7 +239,7 @@ var b = ({ className: e }) => /* @__PURE__ */ v("svg", {
|
|
|
239
239
|
/* @__PURE__ */ y("button", {
|
|
240
240
|
type: "button",
|
|
241
241
|
onClick: Y,
|
|
242
|
-
className: "inline-flex items-center gap-2 px-3 py-2 text-sm font-medium text-
|
|
242
|
+
className: "inline-flex items-center gap-2 px-3 py-2 text-sm font-medium text-status-error-text bg-status-error-bg/10 hover:bg-status-error-bg/20 rounded-md transition-colors",
|
|
243
243
|
children: [/* @__PURE__ */ v(S, { className: "w-4 h-4" }), "Delete"]
|
|
244
244
|
})
|
|
245
245
|
]
|
|
@@ -384,11 +384,11 @@ var b = ({ className: e }) => /* @__PURE__ */ v("svg", {
|
|
|
384
384
|
children: [
|
|
385
385
|
/* @__PURE__ */ y("div", {
|
|
386
386
|
className: "flex items-center gap-2 mb-2",
|
|
387
|
-
children: [F.status === "completed" ? /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ v(T, { className: "w-4 h-4 text-
|
|
388
|
-
className: "text-sm font-medium text-
|
|
387
|
+
children: [F.status === "completed" ? /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ v(T, { className: "w-4 h-4 text-status-success-text" }), /* @__PURE__ */ v("span", {
|
|
388
|
+
className: "text-sm font-medium text-status-success-text",
|
|
389
389
|
children: "Test Passed"
|
|
390
|
-
})] }) : /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ v(w, { className: "w-4 h-4 text-
|
|
391
|
-
className: "text-sm font-medium text-
|
|
390
|
+
})] }) : /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ v(w, { className: "w-4 h-4 text-status-error-text" }), /* @__PURE__ */ v("span", {
|
|
391
|
+
className: "text-sm font-medium text-status-error-text",
|
|
392
392
|
children: "Test Failed"
|
|
393
393
|
})] }), F.totalExecutionTimeMs && /* @__PURE__ */ y("span", {
|
|
394
394
|
className: "text-xs text-text-secondary",
|
|
@@ -409,10 +409,10 @@ var b = ({ className: e }) => /* @__PURE__ */ v("svg", {
|
|
|
409
409
|
F.error && /* @__PURE__ */ y("div", {
|
|
410
410
|
className: "mt-2",
|
|
411
411
|
children: [/* @__PURE__ */ v("label", {
|
|
412
|
-
className: "block text-sm font-medium text-
|
|
412
|
+
className: "block text-sm font-medium text-status-error-text mb-2",
|
|
413
413
|
children: "Error"
|
|
414
414
|
}), /* @__PURE__ */ v("pre", {
|
|
415
|
-
className: "w-full p-3 text-xs font-mono text-
|
|
415
|
+
className: "w-full p-3 text-xs font-mono text-status-error-text bg-status-error-bg/10 border border-status-error-border/20 rounded-md overflow-auto",
|
|
416
416
|
children: F.error
|
|
417
417
|
})]
|
|
418
418
|
})
|