@open-mercato/core 0.4.5-develop-eeccf7adf4 → 0.4.5-develop-5191db4ef3
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/modules/auth/components/AclEditor.js +4 -2
- package/dist/modules/auth/components/AclEditor.js.map +2 -2
- package/dist/modules/auth/frontend/reset.js +3 -3
- package/dist/modules/auth/frontend/reset.js.map +2 -2
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +35 -6
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js +6 -6
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
- package/package.json +2 -2
- package/src/modules/attachments/i18n/de.json +4 -0
- package/src/modules/attachments/i18n/en.json +4 -0
- package/src/modules/attachments/i18n/es.json +4 -0
- package/src/modules/attachments/i18n/pl.json +4 -0
- package/src/modules/auth/components/AclEditor.tsx +4 -2
- package/src/modules/auth/frontend/reset.tsx +3 -3
- package/src/modules/auth/i18n/de.json +5 -0
- package/src/modules/auth/i18n/en.json +5 -0
- package/src/modules/auth/i18n/es.json +5 -0
- package/src/modules/auth/i18n/pl.json +5 -0
- package/src/modules/catalog/i18n/de.json +21 -0
- package/src/modules/catalog/i18n/en.json +21 -0
- package/src/modules/catalog/i18n/es.json +21 -0
- package/src/modules/catalog/i18n/pl.json +21 -0
- package/src/modules/currencies/i18n/de.json +6 -0
- package/src/modules/currencies/i18n/en.json +6 -0
- package/src/modules/currencies/i18n/es.json +6 -0
- package/src/modules/currencies/i18n/pl.json +6 -0
- package/src/modules/customers/i18n/de.json +22 -1
- package/src/modules/customers/i18n/en.json +21 -0
- package/src/modules/customers/i18n/es.json +21 -0
- package/src/modules/customers/i18n/pl.json +21 -0
- package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +41 -5
- package/src/modules/dashboards/i18n/de.json +5 -1
- package/src/modules/dashboards/i18n/en.json +5 -1
- package/src/modules/dashboards/i18n/es.json +5 -1
- package/src/modules/dashboards/i18n/pl.json +5 -1
- package/src/modules/dictionaries/i18n/de.json +14 -1
- package/src/modules/dictionaries/i18n/en.json +14 -1
- package/src/modules/dictionaries/i18n/es.json +14 -1
- package/src/modules/dictionaries/i18n/pl.json +14 -1
- package/src/modules/feature_toggles/i18n/de.json +3 -0
- package/src/modules/feature_toggles/i18n/en.json +3 -0
- package/src/modules/feature_toggles/i18n/es.json +3 -0
- package/src/modules/feature_toggles/i18n/pl.json +3 -0
- package/src/modules/query_index/i18n/es.json +2 -2
- package/src/modules/resources/i18n/de.json +57 -0
- package/src/modules/resources/i18n/en.json +57 -0
- package/src/modules/resources/i18n/es.json +57 -0
- package/src/modules/resources/i18n/pl.json +57 -0
- package/src/modules/sales/i18n/de.json +23 -0
- package/src/modules/sales/i18n/en.json +23 -0
- package/src/modules/sales/i18n/es.json +23 -0
- package/src/modules/sales/i18n/pl.json +23 -0
- package/src/modules/staff/i18n/de.json +14 -0
- package/src/modules/staff/i18n/en.json +14 -0
- package/src/modules/staff/i18n/es.json +14 -0
- package/src/modules/staff/i18n/pl.json +14 -0
- package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +6 -6
- package/src/modules/workflows/i18n/de.json +41 -0
- package/src/modules/workflows/i18n/en.json +41 -0
- package/src/modules/workflows/i18n/es.json +41 -0
- package/src/modules/workflows/i18n/pl.json +41 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/workflows/backend/definitions/visual-editor/page.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport { WorkflowGraph } from '../../../components/WorkflowGraph'\n// Conditional imports based on feature flag\nimport { NodeEditDialog } from '../../../components/NodeEditDialog'\nimport { EdgeEditDialog } from '../../../components/EdgeEditDialog'\nimport { NodeEditDialogCrudForm } from '../../../components/NodeEditDialogCrudForm'\nimport { EdgeEditDialogCrudForm } from '../../../components/EdgeEditDialogCrudForm'\nimport { Node, Edge, addEdge, Connection, applyNodeChanges, applyEdgeChanges, NodeChange, EdgeChange } from '@xyflow/react'\nimport { useState, useCallback, useEffect } from 'react'\nimport { useRouter, useSearchParams } from 'next/navigation'\nimport { graphToDefinition, definitionToGraph, validateWorkflowGraph, generateStepId, generateTransitionId, ValidationError } from '../../../lib/graph-utils'\nimport { workflowDefinitionDataSchema } from '../../../data/validators'\nimport { Page } from '@open-mercato/ui/backend/Page'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Switch } from '@open-mercato/ui/primitives/switch'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { TagsInput } from '@open-mercato/ui/backend/inputs/TagsInput'\nimport { LoadingMessage } from '@open-mercato/ui/backend/detail'\nimport { Alert, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { FormHeader } from '@open-mercato/ui/backend/forms'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { CircleQuestionMark, Info, PanelTopClose, PanelTopOpen, Play, Save, Trash2 } from 'lucide-react'\nimport { NODE_TYPE_ICONS, NODE_TYPE_COLORS, NODE_TYPE_LABELS } from '../../../lib/node-type-icons'\nimport { DefinitionTriggersEditor } from '../../../components/DefinitionTriggersEditor'\nimport { MobileVisualEditor } from '../../../components/mobile/MobileVisualEditor'\nimport { useIsMobile } from '@open-mercato/ui/hooks/useIsMobile'\nimport type { WorkflowDefinitionTrigger } from '../../../data/entities'\nimport type { WorkflowMetadataState, WorkflowMetadataHandlers } from '../../../data/types'\nimport * as React from 'react'\n\n/**\n * VisualEditorPage - Visual workflow definition editor\n *\n * Layout:\n * - Page Header: Title, description, and action buttons (Save, Validate, Test)\n * - Workflow Metadata: Collapsible form for workflow details\n * - Page Body:\n * - Left sidebar: Step palette (click to add)\n * - Main canvas: ReactFlow graph editor\n * - Flash Messages: Top-right positioned validation messages\n * - Edit Dialogs: Modal dialogs for editing steps and transitions\n */\nexport default function VisualEditorPage() {\n const t = useT()\n const router = useRouter()\n const searchParams = useSearchParams()\n const definitionId = searchParams.get('id')\n const isMobile = useIsMobile()\n\n const [isLoading, setIsLoading] = useState(!!definitionId)\n const [isSaving, setIsSaving] = useState(false)\n const [nodes, setNodes] = useState<Node[]>([])\n const [edges, setEdges] = useState<Edge[]>([])\n const [selectedNode, setSelectedNode] = useState<Node | null>(null)\n const [selectedEdge, setSelectedEdge] = useState<Edge | null>(null)\n const [showMetadata, setShowMetadata] = useState(true)\n const [isCompactViewport, setIsCompactViewport] = useState(false)\n\n // Auto-collapse metadata on compact viewports after hydration\n useEffect(() => {\n if (typeof window === 'undefined') return\n const mediaQuery = window.matchMedia('(max-width: 1279px)')\n const applyViewportMode = () => {\n const compact = mediaQuery.matches\n setIsCompactViewport(compact)\n setShowMetadata(!compact)\n }\n\n applyViewportMode()\n mediaQuery.addEventListener('change', applyViewportMode)\n\n return () => {\n mediaQuery.removeEventListener('change', applyViewportMode)\n }\n }, [])\n const [showNodeDialog, setShowNodeDialog] = useState(false)\n const [showEdgeDialog, setShowEdgeDialog] = useState(false)\n const [showClearConfirm, setShowClearConfirm] = useState(false)\n\n // Workflow metadata state\n const [workflowId, setWorkflowId] = useState('')\n const [workflowName, setWorkflowName] = useState('')\n const [description, setDescription] = useState('')\n const [version, setVersion] = useState(1)\n const [enabled, setEnabled] = useState(true)\n const [category, setCategory] = useState('')\n const [tags, setTags] = useState<string[]>([])\n const [icon, setIcon] = useState('')\n const [effectiveFrom, setEffectiveFrom] = useState('')\n const [effectiveTo, setEffectiveTo] = useState('')\n const [triggers, setTriggers] = useState<WorkflowDefinitionTrigger[]>([])\n\n // Load existing definition if ID is provided\n useEffect(() => {\n const loadDefinition = async () => {\n if (!definitionId) {\n setIsLoading(false)\n return\n }\n\n try {\n const result = await apiCall<{ data: any; error?: string }>(`/api/workflows/definitions/${definitionId}`)\n\n if (!result.ok) {\n flash(`Failed to load workflow: ${result.result?.error || 'Unknown error'}`, 'error')\n setIsLoading(false)\n return\n }\n\n const definition = result.result?.data\n\n // Populate metadata\n setWorkflowId(definition.workflowId)\n setWorkflowName(definition.workflowName || definition.definition.workflowName || '')\n setDescription(definition.description || definition.definition.description || '')\n setVersion(definition.version)\n setEnabled(definition.enabled)\n setCategory(definition.metadata?.category || '')\n setTags(definition.metadata?.tags || [])\n setIcon(definition.metadata?.icon || '')\n setEffectiveFrom(definition.effectiveFrom || '')\n setEffectiveTo(definition.effectiveTo || '')\n\n // Convert definition to graph\n const graph = definitionToGraph(definition.definition)\n setNodes(graph.nodes)\n setEdges(graph.edges)\n\n // Load embedded triggers from definition\n setTriggers(definition.definition?.triggers || [])\n\n flash('Workflow loaded successfully', 'success')\n } catch (error) {\n console.error('Error loading workflow definition:', error)\n flash('Failed to load workflow definition', 'error')\n } finally {\n setIsLoading(false)\n }\n }\n\n loadDefinition()\n }, [definitionId])\n\n // Handle node changes from ReactFlow\n const handleNodesChange = useCallback((changes: NodeChange[]) => {\n setNodes((nds) => applyNodeChanges(changes, nds))\n }, [])\n\n // Handle edge changes from ReactFlow\n const handleEdgesChange = useCallback((changes: EdgeChange[]) => {\n setEdges((eds) => applyEdgeChanges(changes, eds))\n }, [])\n\n // Handle adding new node from palette\n const handleAddNode = useCallback((nodeType: string) => {\n const newNode: Node = {\n id: generateStepId(nodeType),\n type: nodeType,\n position: {\n x: 250 + nodes.length * 50,\n y: 100 + nodes.length * 150,\n },\n data: {\n label: getDefaultLabel(nodeType),\n description: '',\n badge: getDefaultBadge(nodeType),\n status: 'pending',\n },\n }\n\n setNodes((nds) => [...nds, newNode])\n }, [nodes.length])\n\n // Handle node selection - open edit dialog\n const handleNodeClick = useCallback((_event: React.MouseEvent, node: Node) => {\n setSelectedNode(node)\n setSelectedEdge(null)\n setShowNodeDialog(true)\n }, [])\n\n // Handle edge selection - open edit dialog\n const handleEdgeClick = useCallback((_event: React.MouseEvent, edge: Edge) => {\n setSelectedEdge(edge)\n setSelectedNode(null)\n setShowEdgeDialog(true)\n }, [])\n\n // Save node updates\n const handleSaveNode = useCallback((nodeId: string, updates: Partial<Node['data']>) => {\n setNodes((nds) =>\n nds.map((node) =>\n node.id === nodeId\n ? { ...node, data: { ...node.data, ...updates } }\n : node\n )\n )\n flash('Node updated successfully', 'success')\n }, [])\n\n // Save edge updates\n const handleSaveEdge = useCallback((edgeId: string, updates: Partial<Edge['data']>) => {\n setEdges((eds) =>\n eds.map((edge) =>\n edge.id === edgeId\n ? { ...edge, data: { ...edge.data, ...updates } }\n : edge\n )\n )\n flash('Transition updated successfully', 'success')\n }, [])\n\n // Delete edge\n const handleDeleteEdge = useCallback((edgeId: string) => {\n setEdges((eds) => eds.filter((edge) => edge.id !== edgeId))\n flash('Transition deleted successfully', 'success')\n }, [])\n\n // Delete node\n const handleDeleteNode = useCallback((nodeId: string) => {\n // Remove the node\n setNodes((nds) => nds.filter((node) => node.id !== nodeId))\n\n // Remove all edges connected to this node\n setEdges((eds) => eds.filter((edge) => edge.source !== nodeId && edge.target !== nodeId))\n\n flash('Step deleted successfully', 'success')\n }, [])\n\n // Handle new connections\n const handleConnect = useCallback((connection: Connection) => {\n const newEdge: Edge = {\n id: generateTransitionId(connection.source!, connection.target!),\n source: connection.source!,\n target: connection.target!,\n type: 'smoothstep',\n data: {\n trigger: 'auto',\n preConditions: [],\n postConditions: [],\n activities: [],\n label: '',\n },\n }\n\n setEdges((eds) => addEdge(newEdge, eds))\n }, [])\n\n // Validate workflow\n const handleValidate = useCallback(() => {\n const graphErrors = validateWorkflowGraph(nodes, edges)\n const allErrors: ValidationError[] = [...graphErrors]\n\n // Run Zod schema validation\n try {\n const definitionData = graphToDefinition(nodes, edges, { includePositions: true })\n const result = workflowDefinitionDataSchema.safeParse(definitionData)\n\n if (!result.success) {\n // Convert Zod errors to validation errors\n result.error.issues.forEach((issue) => {\n allErrors.push({\n type: 'error',\n message: `Schema validation: ${issue.path.join('.')} - ${issue.message}`,\n })\n })\n }\n } catch (error) {\n allErrors.push({\n type: 'error',\n message: `Schema validation failed: ${error instanceof Error ? error.message : 'Unknown error'}`,\n })\n }\n\n if (allErrors.length === 0) {\n flash('Validation passed! Your workflow is valid and ready to save.', 'success')\n } else {\n // Show first error/warning message\n const firstError = allErrors[0]\n const errorCount = allErrors.length\n const message = errorCount > 1\n ? `${firstError.message} (and ${errorCount - 1} more ${errorCount === 2 ? 'issue' : 'issues'})`\n : firstError.message\n flash(message, firstError.type === 'error' ? 'error' : 'warning')\n }\n }, [nodes, edges])\n\n // Save workflow definition\n const handleSave = useCallback(async () => {\n // Validate required fields\n if (!workflowId || !workflowName) {\n flash('Workflow ID and Name are required fields', 'error')\n return\n }\n\n // Validate workflow structure\n const errors = validateWorkflowGraph(nodes, edges)\n const criticalErrors = errors.filter(e => e.type === 'error')\n if (criticalErrors.length > 0) {\n flash(`Cannot save: ${criticalErrors.length} validation error(s) found. Please fix them first.`, 'error')\n return\n }\n\n // Generate definition data and include triggers\n const graphDefinition = graphToDefinition(nodes, edges, { includePositions: true })\n const definitionData = {\n ...graphDefinition,\n triggers: triggers.length > 0 ? triggers : undefined,\n }\n\n // Run Zod schema validation before saving\n const schemaResult = workflowDefinitionDataSchema.safeParse(definitionData)\n if (!schemaResult.success) {\n const firstIssue = schemaResult.error.issues[0]\n flash(`Schema error: ${firstIssue.path.join('.')} - ${firstIssue.message}`, 'error')\n return\n }\n\n setIsSaving(true)\n\n try {\n\n const metadata: any = {}\n if (category) metadata.category = category\n if (tags.length > 0) metadata.tags = tags\n if (icon) metadata.icon = icon\n\n // Determine if creating new or updating existing\n const isUpdate = !!definitionId\n\n let result\n if (isUpdate) {\n // Update existing definition\n result = await apiCall<{ data: any; error?: string }>(`/api/workflows/definitions/${definitionId}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n definition: definitionData,\n enabled,\n }),\n })\n } else {\n // Create new definition\n result = await apiCall<{ data: any; error?: string }>('/api/workflows/definitions', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n workflowId,\n workflowName,\n description: description || null,\n version,\n definition: definitionData,\n metadata: Object.keys(metadata).length > 0 ? metadata : null,\n enabled,\n effectiveFrom: effectiveFrom || null,\n effectiveTo: effectiveTo || null,\n }),\n })\n }\n\n if (!result.ok) {\n flash(`Failed to save: ${result.result?.error || 'Unknown error'}`, 'error')\n return\n }\n\n const savedDefinition = result.result?.data\n\n flash(`Workflow ${isUpdate ? 'updated' : 'created'} successfully!`, 'success')\n\n // Redirect to definition detail page after short delay\n setTimeout(() => {\n router.push(`/backend/definitions/${savedDefinition.id}`)\n }, 1500)\n\n } catch (error) {\n console.error('Error saving workflow definition:', error)\n flash('Failed to save workflow definition. Please try again.', 'error')\n } finally {\n setIsSaving(false)\n }\n }, [nodes, edges, workflowId, workflowName, description, version, enabled, category, tags, icon, effectiveFrom, effectiveTo, triggers, definitionId, router])\n\n // Test workflow\n const handleTest = useCallback(() => {\n // First validate\n const errors = validateWorkflowGraph(nodes, edges)\n const criticalErrors = errors.filter((e) => e.type === 'error')\n if (criticalErrors.length > 0) {\n flash(`Cannot test: ${criticalErrors.length} validation error(s) found. Please fix them first.`, 'error')\n return\n }\n\n // TODO: Implement test logic (create instance, run first step)\n flash('Test functionality will be implemented next', 'info')\n }, [nodes, edges])\n\n // Load example workflow\n const handleLoadExample = useCallback(() => {\n // Set example metadata\n setWorkflowId('approval_workflow')\n setWorkflowName('Simple Approval Workflow')\n setDescription('A basic approval workflow for reviewing and approving requests')\n setVersion(1)\n setEnabled(true)\n setCategory('Approvals')\n setTags(['approval', 'review'])\n\n const exampleNodes: Node[] = [\n {\n id: 'start',\n type: 'start',\n position: { x: 250, y: 50 },\n data: {\n label: 'Start',\n description: 'Workflow begins',\n status: 'pending',\n badge: 'Start',\n },\n },\n {\n id: 'step1',\n type: 'userTask',\n position: { x: 250, y: 250 },\n data: {\n label: 'Review Request',\n description: 'User reviews the incoming request',\n status: 'pending',\n stepNumber: 1,\n badge: 'User Task',\n assignedToRoles: ['Reviewer'],\n },\n },\n {\n id: 'end',\n type: 'end',\n position: { x: 250, y: 450 },\n data: {\n label: 'Complete',\n description: 'Workflow ends',\n status: 'pending',\n badge: 'End',\n },\n },\n ]\n\n const exampleEdges: Edge[] = [\n {\n id: 'e-start-step1',\n source: 'start',\n target: 'step1',\n type: 'smoothstep',\n data: {\n trigger: 'auto',\n preConditions: [],\n postConditions: [],\n activities: [],\n },\n },\n {\n id: 'e-step1-end',\n source: 'step1',\n target: 'end',\n type: 'smoothstep',\n data: {\n trigger: 'auto',\n preConditions: [],\n postConditions: [],\n activities: [],\n },\n },\n ]\n\n setNodes(exampleNodes)\n setEdges(exampleEdges)\n flash('Example workflow loaded', 'success')\n }, [])\n\n // Clear canvas\n const handleClear = useCallback(() => {\n if (nodes.length > 0 || edges.length > 0 || workflowId || workflowName) {\n setShowClearConfirm(true)\n }\n }, [nodes.length, edges.length, workflowId, workflowName])\n\n // Confirm clear action\n const confirmClear = useCallback(() => {\n setNodes([])\n setEdges([])\n setWorkflowId('')\n setWorkflowName('')\n setDescription('')\n setVersion(1)\n setEnabled(true)\n setCategory('')\n setTags([])\n setIcon('')\n setEffectiveFrom('')\n setEffectiveTo('')\n setTriggers([])\n setShowClearConfirm(false)\n flash('Canvas cleared', 'success')\n }, [])\n\n // Show loading spinner while loading definition\n if (isLoading) {\n return (\n <Page className=\"flex items-center justify-center min-h-[50vh]\">\n <LoadingMessage label=\"Loading workflow definition...\" />\n </Page>\n )\n }\n\n const metadata: WorkflowMetadataState = {\n workflowId, workflowName, description, version,\n enabled, category, tags, icon,\n effectiveFrom, effectiveTo, triggers,\n }\n\n const metadataHandlers: WorkflowMetadataHandlers = {\n setWorkflowId, setWorkflowName, setDescription, setVersion,\n setEnabled, setCategory, setTags, setIcon,\n setEffectiveFrom, setEffectiveTo, setTriggers,\n }\n\n const sharedDialogs = (\n <>\n {process.env.NEXT_PUBLIC_WORKFLOW_CRUDFORM_ENABLED === 'true' ? (\n <NodeEditDialogCrudForm node={selectedNode} isOpen={showNodeDialog} onClose={() => setShowNodeDialog(false)} onSave={handleSaveNode} onDelete={handleDeleteNode} />\n ) : (\n <NodeEditDialog node={selectedNode} isOpen={showNodeDialog} onClose={() => setShowNodeDialog(false)} onSave={handleSaveNode} onDelete={handleDeleteNode} />\n )}\n {process.env.NEXT_PUBLIC_WORKFLOW_CRUDFORM_ENABLED === 'true' ? (\n <EdgeEditDialogCrudForm edge={selectedEdge} isOpen={showEdgeDialog} onClose={() => setShowEdgeDialog(false)} onSave={handleSaveEdge} onDelete={handleDeleteEdge} />\n ) : (\n <EdgeEditDialog edge={selectedEdge} isOpen={showEdgeDialog} onClose={() => setShowEdgeDialog(false)} onSave={handleSaveEdge} onDelete={handleDeleteEdge} />\n )}\n <Dialog open={showClearConfirm} onOpenChange={setShowClearConfirm}>\n <DialogContent className=\"sm:max-w-md\">\n <DialogHeader>\n <DialogTitle>{t('workflows.visualEditor.clearTitle')}</DialogTitle>\n <DialogDescription>{t('workflows.visualEditor.clearDescription')}</DialogDescription>\n </DialogHeader>\n <DialogFooter>\n <Button variant=\"outline\" onClick={() => setShowClearConfirm(false)}>{t('common.cancel', 'Cancel')}</Button>\n <Button variant=\"destructive\" onClick={confirmClear}>{t('common.clear', 'Clear')}</Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </>\n )\n\n if (isMobile) {\n return (\n <Page className=\"flex h-[100svh] flex-col space-y-0 overflow-hidden\">\n <MobileVisualEditor\n definitionId={definitionId}\n isSaving={isSaving}\n nodes={nodes}\n edges={edges}\n onNodesChange={handleNodesChange}\n onEdgesChange={handleEdgesChange}\n onNodeClick={handleNodeClick}\n onEdgeClick={handleEdgeClick}\n onConnect={handleConnect}\n onAddNode={handleAddNode}\n onSave={handleSave}\n onValidate={handleValidate}\n onTest={handleTest}\n onLoadExample={handleLoadExample}\n onClear={handleClear}\n metadata={metadata}\n metadataHandlers={metadataHandlers}\n />\n {sharedDialogs}\n </Page>\n )\n }\n\n return (\n <Page className=\"space-y-0 overflow-x-hidden\">\n {/* Page Header */}\n <div className=\"shrink-0 border-b border-border bg-background px-3 py-2 md:px-6 md:py-3\">\n <FormHeader\n mode=\"detail\"\n backHref=\"/backend/definitions\"\n backLabel={t('workflows.definitions.backToList', 'Back to definitions')}\n title={definitionId ? (workflowName || t('workflows.definitions.singular')) : t('workflows.backend.definitions.visual_editor.title')}\n subtitle={definitionId\n ? t('workflows.definitions.detail.summary', 'Editing workflow definition')\n : t('workflows.definitions.create.summary', 'Create and edit workflow definitions visually with a drag-and-drop interface')\n }\n actionsContent={\n <div className=\"flex flex-wrap items-center justify-end gap-1 md:gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setShowMetadata(!showMetadata)}\n disabled={isSaving}\n className=\"h-8 px-2 text-xs\"\n aria-label={showMetadata ? t('workflows.visualEditor.hideMetadata') : t('workflows.visualEditor.showMetadata')}\n >\n {showMetadata ? <PanelTopClose className=\"mr-1.5 h-4 w-4\" /> : <PanelTopOpen className=\"mr-1.5 h-4 w-4\" />}\n {showMetadata ? t('workflows.visualEditor.hideMetadata') : t('workflows.visualEditor.showMetadata')}\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleLoadExample}\n disabled={isSaving}\n className=\"h-8 text-xs\"\n >\n {t('workflows.visualEditor.loadExample')}\n </Button>\n <Button\n variant=\"destructive\"\n size=\"sm\"\n onClick={handleClear}\n disabled={isSaving}\n className=\"h-8 px-2 text-xs\"\n aria-label={t('workflows.visualEditor.clear')}\n >\n <Trash2 className=\"mr-1.5 h-4 w-4\" />\n {t('workflows.visualEditor.clear')}\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleValidate}\n disabled={isSaving}\n className=\"h-8 px-2 text-xs\"\n aria-label={t('workflows.visualEditor.validate')}\n >\n <CircleQuestionMark className=\"mr-1.5 h-4 w-4\" />\n {t('workflows.visualEditor.validate')}\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleTest}\n disabled={isSaving}\n className=\"h-8 text-xs\"\n >\n <Play className=\"mr-1.5 h-4 w-4\" />\n {t('workflows.visualEditor.runTest')}\n </Button>\n <Button\n size=\"sm\"\n onClick={handleSave}\n disabled={isSaving}\n className=\"h-8 px-2 text-xs md:px-3\"\n aria-label={isSaving ? t('workflows.mobile.saving') : definitionId ? t('workflows.common.update') : t('workflows.common.save')}\n >\n <Save className=\"mr-1.5 h-4 w-4\" />\n {isSaving ? t('workflows.mobile.saving') : definitionId ? t('workflows.common.update') : t('workflows.common.save')}\n </Button>\n </div>\n }\n />\n </div>\n\n {/* Workflow Metadata Form */}\n {showMetadata && (\n <div className={isCompactViewport\n ? 'shrink-0 border-b border-border bg-background px-3 py-2 max-h-[60svh] overflow-y-auto overscroll-contain md:px-6 md:py-3'\n : 'shrink-0 border-b border-border bg-background px-3 py-2 md:px-6 md:py-3'\n }>\n <div className=\"rounded-lg border bg-card p-3 md:p-4\">\n <h2 className=\"mb-3 text-xs font-semibold uppercase text-muted-foreground\">{t('workflows.visualEditor.workflowMetadata')}</h2>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3 md:gap-4\">\n {/* Workflow ID */}\n <div className=\"min-w-0 space-y-1\">\n <Label htmlFor=\"workflowId\" className=\"text-xs\">Workflow ID *</Label>\n <Input\n id=\"workflowId\"\n value={workflowId}\n onChange={(e) => setWorkflowId(e.target.value)}\n placeholder=\"checkout_workflow\"\n disabled={!!definitionId}\n className=\"h-8 text-sm\"\n />\n {definitionId && <p className=\"text-[10px] text-muted-foreground\">Read-only</p>}\n </div>\n\n {/* Workflow Name */}\n <div className=\"min-w-0 space-y-1\">\n <Label htmlFor=\"workflowName\" className=\"text-xs\">Name *</Label>\n <Input\n id=\"workflowName\"\n value={workflowName}\n onChange={(e) => setWorkflowName(e.target.value)}\n placeholder=\"Checkout Process\"\n className=\"h-8 text-sm\"\n />\n </div>\n\n {/* Category */}\n <div className=\"min-w-0 space-y-1\">\n <Label htmlFor=\"category\" className=\"text-xs\">Category</Label>\n <Input\n id=\"category\"\n value={category}\n onChange={(e) => setCategory(e.target.value)}\n placeholder=\"E-Commerce\"\n className=\"h-8 text-sm\"\n />\n </div>\n\n {/* Description */}\n <div className=\"min-w-0 space-y-1 sm:col-span-2 lg:col-span-3\">\n <Label htmlFor=\"description\" className=\"text-xs\">Description</Label>\n <Textarea\n id=\"description\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Describe the purpose of this workflow...\"\n rows={2}\n className=\"min-h-[60px] text-sm\"\n />\n </div>\n\n {/* Version */}\n <div className=\"min-w-0 space-y-1\">\n <Label htmlFor=\"version\" className=\"text-xs\">Version *</Label>\n <Input\n id=\"version\"\n type=\"number\"\n value={version}\n onChange={(e) => setVersion(parseInt(e.target.value) || 1)}\n min={1}\n disabled={!!definitionId}\n className=\"h-8 text-sm\"\n />\n </div>\n\n {/* Enabled */}\n <div className=\"min-w-0 space-y-1\">\n <Label className=\"text-xs\">{t('common.enabled', 'Enabled')}</Label>\n <div className=\"flex h-8 items-center gap-2\">\n <Switch\n id=\"enabled\"\n checked={enabled}\n onCheckedChange={setEnabled}\n />\n <Label htmlFor=\"enabled\" className=\"cursor-pointer text-xs font-normal\">\n {enabled ? t('common.on', 'On') : t('common.off', 'Off')}\n </Label>\n </div>\n </div>\n\n {/* Tags */}\n <div className=\"min-w-0 space-y-1\">\n <Label className=\"text-xs\">Tags</Label>\n <TagsInput\n value={tags}\n onChange={setTags}\n placeholder={t('workflows.form.placeholders.tags')}\n />\n </div>\n\n {/* Icon */}\n <div className=\"min-w-0 space-y-1\">\n <Label htmlFor=\"icon\" className=\"text-xs\">Icon</Label>\n <Input\n id=\"icon\"\n value={icon}\n onChange={(e) => setIcon(e.target.value)}\n placeholder=\"ShoppingCart\"\n className=\"h-8 text-sm\"\n />\n </div>\n\n <div className=\"min-w-0 space-y-1\">\n <Label htmlFor=\"effectiveFrom\" className=\"text-xs\">Effective From</Label>\n <Input\n id=\"effectiveFrom\"\n type=\"date\"\n value={effectiveFrom}\n onChange={(e) => setEffectiveFrom(e.target.value)}\n className=\"h-8 text-sm\"\n />\n </div>\n\n <div className=\"min-w-0 space-y-1\">\n <Label htmlFor=\"effectiveTo\" className=\"text-xs\">Effective To</Label>\n <Input\n id=\"effectiveTo\"\n type=\"date\"\n value={effectiveTo}\n onChange={(e) => setEffectiveTo(e.target.value)}\n className=\"h-8 text-sm\"\n />\n </div>\n </div>\n </div>\n\n {/* Event Triggers */}\n <DefinitionTriggersEditor\n value={triggers}\n onChange={setTriggers}\n className=\"mt-3\"\n />\n </div>\n )}\n\n {/* Main Content */}\n {isCompactViewport ? (\n <div className=\"px-3 py-3 md:px-6 md:py-4\">\n <div className=\"relative min-w-0\">\n <div className=\"h-[64svh] min-h-[360px] rounded-lg border bg-card\">\n <WorkflowGraph\n initialNodes={nodes}\n initialEdges={edges}\n onNodesChange={handleNodesChange}\n onEdgesChange={handleEdgesChange}\n onNodeClick={handleNodeClick}\n onEdgeClick={handleEdgeClick}\n onConnect={handleConnect}\n editable={true}\n height=\"100%\"\n />\n </div>\n\n {nodes.length === 0 && (\n <div className=\"pointer-events-none absolute inset-0 flex items-center justify-center px-4\">\n <div className=\"text-center\">\n <h2 className=\"mb-2 text-lg font-semibold text-foreground\">Start Building Your Workflow</h2>\n <p className=\"mb-4 text-sm text-muted-foreground\">Tap a step type below to add it to the canvas</p>\n <button\n onClick={handleLoadExample}\n className=\"pointer-events-auto text-sm text-primary hover:underline\"\n >\n Load an example workflow\n </button>\n </div>\n </div>\n )}\n </div>\n\n <div className=\"mt-3 rounded-lg border bg-card p-3\">\n <h2 className=\"mb-2 text-xs font-semibold uppercase text-muted-foreground\">Step Palette</h2>\n <p className=\"mb-3 text-xs text-muted-foreground\">Tap a step type to add it to the canvas</p>\n\n <div className=\"flex gap-2 overflow-x-auto pb-1\">\n {(['start', 'userTask', 'automated', 'waitForSignal', 'subWorkflow', 'end'] as const).map((nodeType) => {\n const Icon = NODE_TYPE_ICONS[nodeType]\n return (\n <button\n key={nodeType}\n onClick={() => handleAddNode(nodeType)}\n className=\"flex shrink-0 items-center gap-1 rounded-md border bg-background px-2 py-1 text-xs hover:bg-muted active:bg-muted/80\"\n >\n <Icon className=\"h-3.5 w-3.5\" />\n <span>{NODE_TYPE_LABELS[nodeType].title}</span>\n </button>\n )\n })}\n </div>\n </div>\n </div>\n ) : (\n <div className=\"flex min-h-[72svh] min-w-0 flex-1 border-t border-border\">\n {/* Left Sidebar - Step Palette */}\n <div className=\"w-[24rem] shrink-0 overflow-y-auto border-r border-border bg-background p-6\">\n <div className=\"rounded-lg border bg-card p-4\">\n <h2 className=\"mb-2 text-sm font-semibold uppercase text-muted-foreground\">Step Palette</h2>\n <p className=\"mb-4 text-xs text-muted-foreground\">\n Click a step type to add it to the canvas\n </p>\n\n <div className=\"space-y-3\">\n {/* START Step */}\n <button\n onClick={() => handleAddNode('start')}\n className=\"group relative w-full cursor-pointer rounded-xl border-2 border-border bg-background px-4 py-3 text-left transition-all hover:border-muted-foreground/30 hover:shadow-md\"\n >\n <div className={`absolute right-2 top-2 ${NODE_TYPE_COLORS.start} opacity-60 transition-opacity group-hover:opacity-100`}>\n {(() => {\n const Icon = NODE_TYPE_ICONS.start\n return <Icon className=\"h-4 w-4\" />\n })()}\n </div>\n <div className=\"text-sm font-semibold text-foreground\">{NODE_TYPE_LABELS.start.title}</div>\n <div className=\"mt-0.5 text-xs text-muted-foreground\">{NODE_TYPE_LABELS.start.description}</div>\n </button>\n\n {/* USER_TASK Step */}\n <button\n onClick={() => handleAddNode('userTask')}\n className=\"group relative w-full cursor-pointer rounded-xl border-2 border-border bg-background px-4 py-3 text-left transition-all hover:border-muted-foreground/30 hover:shadow-md\"\n >\n <div className={`absolute right-2 top-2 ${NODE_TYPE_COLORS.userTask} opacity-60 transition-opacity group-hover:opacity-100`}>\n {(() => {\n const Icon = NODE_TYPE_ICONS.userTask\n return <Icon className=\"h-4 w-4\" />\n })()}\n </div>\n <div className=\"text-sm font-semibold text-foreground\">{NODE_TYPE_LABELS.userTask.title}</div>\n <div className=\"mt-0.5 text-xs text-muted-foreground\">{NODE_TYPE_LABELS.userTask.description}</div>\n </button>\n\n {/* AUTOMATED Step */}\n <button\n onClick={() => handleAddNode('automated')}\n className=\"group relative w-full cursor-pointer rounded-xl border-2 border-border bg-background px-4 py-3 text-left transition-all hover:border-muted-foreground/30 hover:shadow-md\"\n >\n <div className={`absolute right-2 top-2 ${NODE_TYPE_COLORS.automated} opacity-60 transition-opacity group-hover:opacity-100`}>\n {(() => {\n const Icon = NODE_TYPE_ICONS.automated\n return <Icon className=\"h-4 w-4\" />\n })()}\n </div>\n <div className=\"text-sm font-semibold text-foreground\">{NODE_TYPE_LABELS.automated.title}</div>\n <div className=\"mt-0.5 text-xs text-muted-foreground\">{NODE_TYPE_LABELS.automated.description}</div>\n </button>\n\n {/* WAIT_FOR_SIGNAL Step */}\n <button\n onClick={() => handleAddNode('waitForSignal')}\n className=\"group relative w-full cursor-pointer rounded-xl border-2 border-border bg-background px-4 py-3 text-left transition-all hover:border-muted-foreground/30 hover:shadow-md\"\n >\n <div className={`absolute right-2 top-2 ${NODE_TYPE_COLORS.waitForSignal} opacity-60 transition-opacity group-hover:opacity-100`}>\n {(() => {\n const Icon = NODE_TYPE_ICONS.waitForSignal\n return <Icon className=\"h-4 w-4\" />\n })()}\n </div>\n <div className=\"text-sm font-semibold text-foreground\">{NODE_TYPE_LABELS.waitForSignal.title}</div>\n <div className=\"mt-0.5 text-xs text-muted-foreground\">{NODE_TYPE_LABELS.waitForSignal.description}</div>\n </button>\n\n {/* SUB_WORKFLOW Step */}\n <button\n onClick={() => handleAddNode('subWorkflow')}\n className=\"group relative w-full cursor-pointer rounded-xl border-2 border-border bg-background px-4 py-3 text-left transition-all hover:border-muted-foreground/30 hover:shadow-md\"\n >\n <div className={`absolute right-2 top-2 ${NODE_TYPE_COLORS.subWorkflow} opacity-60 transition-opacity group-hover:opacity-100`}>\n {(() => {\n const Icon = NODE_TYPE_ICONS.subWorkflow\n return <Icon className=\"h-4 w-4\" />\n })()}\n </div>\n <div className=\"text-sm font-semibold text-foreground\">{NODE_TYPE_LABELS.subWorkflow.title}</div>\n <div className=\"mt-0.5 text-xs text-muted-foreground\">{NODE_TYPE_LABELS.subWorkflow.description}</div>\n </button>\n\n {/* END Step */}\n <button\n onClick={() => handleAddNode('end')}\n className=\"group relative w-full cursor-pointer rounded-xl border-2 border-border bg-background px-4 py-3 text-left transition-all hover:border-muted-foreground/30 hover:shadow-md\"\n >\n <div className={`absolute right-2 top-2 ${NODE_TYPE_COLORS.end} opacity-60 transition-opacity group-hover:opacity-100`}>\n {(() => {\n const Icon = NODE_TYPE_ICONS.end\n return <Icon className=\"h-4 w-4\" />\n })()}\n </div>\n <div className=\"text-sm font-semibold text-foreground\">{NODE_TYPE_LABELS.end.title}</div>\n <div className=\"mt-0.5 text-xs text-muted-foreground\">{NODE_TYPE_LABELS.end.description}</div>\n </button>\n </div>\n\n {/* Instructions */}\n <Alert variant=\"info\" className=\"mt-6\">\n <Info className=\"size-4\" />\n <AlertTitle className=\"text-xs\">How to use:</AlertTitle>\n <div className=\"mt-2\">\n <ul className=\"list-inside list-disc space-y-1 text-xs\">\n <li>Click step types to add them</li>\n <li>Drag steps to position them</li>\n <li>Connect steps by dragging from handles</li>\n <li>Click steps and transitions to edit them</li>\n <li>Validate before saving</li>\n </ul>\n </div>\n </Alert>\n </div>\n </div>\n\n {/* Main Canvas */}\n <div className=\"min-w-0 flex-1 p-6\">\n <div className=\"relative h-[72svh] min-h-[640px]\">\n <div className=\"h-full rounded-lg border bg-card\">\n <WorkflowGraph\n initialNodes={nodes}\n initialEdges={edges}\n onNodesChange={handleNodesChange}\n onEdgesChange={handleEdgesChange}\n onNodeClick={handleNodeClick}\n onEdgeClick={handleEdgeClick}\n onConnect={handleConnect}\n editable={true}\n height=\"100%\"\n />\n </div>\n\n {/* Empty State */}\n {nodes.length === 0 && (\n <div className=\"pointer-events-none absolute inset-0 flex items-center justify-center px-4\">\n <div className=\"text-center\">\n <h2 className=\"mb-2 text-xl font-semibold text-foreground\">\n Start Building Your Workflow\n </h2>\n <p className=\"mb-4 text-muted-foreground\">\n Click a step type from the palette to add it to the canvas\n </p>\n <button\n onClick={handleLoadExample}\n className=\"pointer-events-auto text-sm text-primary hover:underline\"\n >\n Load an example workflow\n </button>\n </div>\n </div>\n )}\n </div>\n </div>\n </div>\n )}\n {sharedDialogs}\n </Page>\n )\n}\n\n// Helper functions\nfunction getDefaultLabel(nodeType: string): string {\n const labels: Record<string, string> = {\n start: 'Start',\n end: 'End',\n userTask: 'New User Task',\n automated: 'New Automated Task',\n decision: 'Decision Point',\n waitForSignal: 'Wait for Signal',\n }\n return labels[nodeType] || 'New Step'\n}\n\nfunction getDefaultBadge(nodeType: string): string {\n const badges: Record<string, string> = {\n start: 'Start',\n end: 'End',\n userTask: 'User Task',\n automated: 'Automated',\n decision: 'Decision',\n waitForSignal: 'Wait for Signal',\n }\n return badges[nodeType] || 'Task'\n}\n\n"],
|
|
5
|
-
"mappings": ";AAugBQ,SAkBJ,UAlBI,KA+BE,YA/BF;AArgBR,SAAS,qBAAqB;AAE9B,SAAS,sBAAsB;AAC/B,SAAS,sBAAsB;AAC/B,SAAS,8BAA8B;AACvC,SAAS,8BAA8B;AACvC,SAAqB,SAAqB,kBAAkB,wBAAgD;AAC5G,SAAS,UAAU,aAAa,iBAAiB;AACjD,SAAS,WAAW,uBAAuB;AAC3C,SAAS,mBAAmB,mBAAmB,uBAAuB,gBAAgB,4BAA6C;AACnI,SAAS,oCAAoC;AAC7C,SAAS,YAAY;AACrB,SAAS,cAAc;AACvB,SAAS,aAAa;AACtB,SAAS,gBAAgB;AACzB,SAAS,aAAa;AACtB,SAAS,cAAc;AACvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,iBAAiB;AAC1B,SAAS,sBAAsB;AAC/B,SAAS,OAAO,kBAAkB;AAClC,SAAS,YAAY;AACrB,SAAS,kBAAkB;AAC3B,SAAS,eAAe;AACxB,SAAS,aAAa;AACtB,SAAS,oBAAoB,MAAM,eAAe,cAAc,MAAM,MAAM,cAAc;AAC1F,SAAS,iBAAiB,kBAAkB,wBAAwB;AACpE,SAAS,gCAAgC;AACzC,SAAS,0BAA0B;AACnC,SAAS,mBAAmB;AAiBb,SAAR,mBAAoC;AACzC,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,UAAU;AACzB,QAAM,eAAe,gBAAgB;AACrC,QAAM,eAAe,aAAa,IAAI,IAAI;AAC1C,QAAM,WAAW,YAAY;AAE7B,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,CAAC,CAAC,YAAY;AACzD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAiB,CAAC,CAAC;AAC7C,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAiB,CAAC,CAAC;AAC7C,QAAM,CAAC,cAAc,eAAe,IAAI,SAAsB,IAAI;AAClE,QAAM,CAAC,cAAc,eAAe,IAAI,SAAsB,IAAI;AAClE,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,IAAI;AACrD,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,SAAS,KAAK;AAGhE,YAAU,MAAM;AACd,QAAI,OAAO,WAAW,YAAa;AACnC,UAAM,aAAa,OAAO,WAAW,qBAAqB;AAC1D,UAAM,oBAAoB,MAAM;AAC9B,YAAM,UAAU,WAAW;AAC3B,2BAAqB,OAAO;AAC5B,sBAAgB,CAAC,OAAO;AAAA,IAC1B;AAEA,sBAAkB;AAClB,eAAW,iBAAiB,UAAU,iBAAiB;AAEvD,WAAO,MAAM;AACX,iBAAW,oBAAoB,UAAU,iBAAiB;AAAA,IAC5D;AAAA,EACF,GAAG,CAAC,CAAC;AACL,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAS,KAAK;AAC1D,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAS,KAAK;AAC1D,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,SAAS,KAAK;AAG9D,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,EAAE;AAC/C,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,EAAE;AACnD,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,EAAE;AACjD,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,CAAC;AACxC,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,IAAI;AAC3C,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,EAAE;AAC3C,QAAM,CAAC,MAAM,OAAO,IAAI,SAAmB,CAAC,CAAC;AAC7C,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,EAAE;AACnC,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,EAAE;AACrD,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,EAAE;AACjD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAsC,CAAC,CAAC;AAGxE,YAAU,MAAM;AACd,UAAM,iBAAiB,YAAY;AACjC,UAAI,CAAC,cAAc;AACjB,qBAAa,KAAK;AAClB;AAAA,MACF;AAEA,UAAI;AACF,cAAM,SAAS,MAAM,QAAuC,8BAA8B,YAAY,EAAE;AAExG,YAAI,CAAC,OAAO,IAAI;AACd,gBAAM,4BAA4B,OAAO,QAAQ,SAAS,eAAe,IAAI,OAAO;AACpF,uBAAa,KAAK;AAClB;AAAA,QACF;AAEA,cAAM,aAAa,OAAO,QAAQ;AAGlC,sBAAc,WAAW,UAAU;AACnC,wBAAgB,WAAW,gBAAgB,WAAW,WAAW,gBAAgB,EAAE;AACnF,uBAAe,WAAW,eAAe,WAAW,WAAW,eAAe,EAAE;AAChF,mBAAW,WAAW,OAAO;AAC7B,mBAAW,WAAW,OAAO;AAC7B,oBAAY,WAAW,UAAU,YAAY,EAAE;AAC/C,gBAAQ,WAAW,UAAU,QAAQ,CAAC,CAAC;AACvC,gBAAQ,WAAW,UAAU,QAAQ,EAAE;AACvC,yBAAiB,WAAW,iBAAiB,EAAE;AAC/C,uBAAe,WAAW,eAAe,EAAE;AAG3C,cAAM,QAAQ,kBAAkB,WAAW,UAAU;AACrD,iBAAS,MAAM,KAAK;AACpB,iBAAS,MAAM,KAAK;AAGpB,oBAAY,WAAW,YAAY,YAAY,CAAC,CAAC;AAEjD,cAAM,gCAAgC,SAAS;AAAA,MACjD,SAAS,OAAO;AACd,gBAAQ,MAAM,sCAAsC,KAAK;AACzD,cAAM,sCAAsC,OAAO;AAAA,MACrD,UAAE;AACA,qBAAa,KAAK;AAAA,MACpB;AAAA,IACF;AAEA,mBAAe;AAAA,EACjB,GAAG,CAAC,YAAY,CAAC;AAGjB,QAAM,oBAAoB,YAAY,CAAC,YAA0B;AAC/D,aAAS,CAAC,QAAQ,iBAAiB,SAAS,GAAG,CAAC;AAAA,EAClD,GAAG,CAAC,CAAC;AAGL,QAAM,oBAAoB,YAAY,CAAC,YAA0B;AAC/D,aAAS,CAAC,QAAQ,iBAAiB,SAAS,GAAG,CAAC;AAAA,EAClD,GAAG,CAAC,CAAC;AAGL,QAAM,gBAAgB,YAAY,CAAC,aAAqB;AACtD,UAAM,UAAgB;AAAA,MACpB,IAAI,eAAe,QAAQ;AAAA,MAC3B,MAAM;AAAA,MACN,UAAU;AAAA,QACR,GAAG,MAAM,MAAM,SAAS;AAAA,QACxB,GAAG,MAAM,MAAM,SAAS;AAAA,MAC1B;AAAA,MACA,MAAM;AAAA,QACJ,OAAO,gBAAgB,QAAQ;AAAA,QAC/B,aAAa;AAAA,QACb,OAAO,gBAAgB,QAAQ;AAAA,QAC/B,QAAQ;AAAA,MACV;AAAA,IACF;AAEA,aAAS,CAAC,QAAQ,CAAC,GAAG,KAAK,OAAO,CAAC;AAAA,EACrC,GAAG,CAAC,MAAM,MAAM,CAAC;AAGjB,QAAM,kBAAkB,YAAY,CAAC,QAA0B,SAAe;AAC5E,oBAAgB,IAAI;AACpB,oBAAgB,IAAI;AACpB,sBAAkB,IAAI;AAAA,EACxB,GAAG,CAAC,CAAC;AAGL,QAAM,kBAAkB,YAAY,CAAC,QAA0B,SAAe;AAC5E,oBAAgB,IAAI;AACpB,oBAAgB,IAAI;AACpB,sBAAkB,IAAI;AAAA,EACxB,GAAG,CAAC,CAAC;AAGL,QAAM,iBAAiB,YAAY,CAAC,QAAgB,YAAmC;AACrF;AAAA,MAAS,CAAC,QACR,IAAI;AAAA,QAAI,CAAC,SACP,KAAK,OAAO,SACR,EAAE,GAAG,MAAM,MAAM,EAAE,GAAG,KAAK,MAAM,GAAG,QAAQ,EAAE,IAC9C;AAAA,MACN;AAAA,IACF;AACA,UAAM,6BAA6B,SAAS;AAAA,EAC9C,GAAG,CAAC,CAAC;AAGL,QAAM,iBAAiB,YAAY,CAAC,QAAgB,YAAmC;AACrF;AAAA,MAAS,CAAC,QACR,IAAI;AAAA,QAAI,CAAC,SACP,KAAK,OAAO,SACR,EAAE,GAAG,MAAM,MAAM,EAAE,GAAG,KAAK,MAAM,GAAG,QAAQ,EAAE,IAC9C;AAAA,MACN;AAAA,IACF;AACA,UAAM,mCAAmC,SAAS;AAAA,EACpD,GAAG,CAAC,CAAC;AAGL,QAAM,mBAAmB,YAAY,CAAC,WAAmB;AACvD,aAAS,CAAC,QAAQ,IAAI,OAAO,CAAC,SAAS,KAAK,OAAO,MAAM,CAAC;AAC1D,UAAM,mCAAmC,SAAS;AAAA,EACpD,GAAG,CAAC,CAAC;AAGL,QAAM,mBAAmB,YAAY,CAAC,WAAmB;AAEvD,aAAS,CAAC,QAAQ,IAAI,OAAO,CAAC,SAAS,KAAK,OAAO,MAAM,CAAC;AAG1D,aAAS,CAAC,QAAQ,IAAI,OAAO,CAAC,SAAS,KAAK,WAAW,UAAU,KAAK,WAAW,MAAM,CAAC;AAExF,UAAM,6BAA6B,SAAS;AAAA,EAC9C,GAAG,CAAC,CAAC;AAGL,QAAM,gBAAgB,YAAY,CAAC,eAA2B;AAC5D,UAAM,UAAgB;AAAA,MACpB,IAAI,qBAAqB,WAAW,QAAS,WAAW,MAAO;AAAA,MAC/D,QAAQ,WAAW;AAAA,MACnB,QAAQ,WAAW;AAAA,MACnB,MAAM;AAAA,MACN,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,eAAe,CAAC;AAAA,QAChB,gBAAgB,CAAC;AAAA,QACjB,YAAY,CAAC;AAAA,QACb,OAAO;AAAA,MACT;AAAA,IACF;AAEA,aAAS,CAAC,QAAQ,QAAQ,SAAS,GAAG,CAAC;AAAA,EACzC,GAAG,CAAC,CAAC;AAGL,QAAM,iBAAiB,YAAY,MAAM;AACvC,UAAM,cAAc,sBAAsB,OAAO,KAAK;AACtD,UAAM,YAA+B,CAAC,GAAG,WAAW;AAGpD,QAAI;AACF,YAAM,iBAAiB,kBAAkB,OAAO,OAAO,EAAE,kBAAkB,KAAK,CAAC;AACjF,YAAM,SAAS,6BAA6B,UAAU,cAAc;AAEpE,UAAI,CAAC,OAAO,SAAS;AAEnB,eAAO,MAAM,OAAO,QAAQ,CAAC,UAAU;AACrC,oBAAU,KAAK;AAAA,YACb,MAAM;AAAA,YACN,SAAS,sBAAsB,MAAM,KAAK,KAAK,GAAG,CAAC,MAAM,MAAM,OAAO;AAAA,UACxE,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AAAA,IACF,SAAS,OAAO;AACd,gBAAU,KAAK;AAAA,QACb,MAAM;AAAA,QACN,SAAS,6BAA6B,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MAChG,CAAC;AAAA,IACH;AAEA,QAAI,UAAU,WAAW,GAAG;AAC1B,YAAM,gEAAgE,SAAS;AAAA,IACjF,OAAO;AAEL,YAAM,aAAa,UAAU,CAAC;AAC9B,YAAM,aAAa,UAAU;AAC7B,YAAM,UAAU,aAAa,IACzB,GAAG,WAAW,OAAO,SAAS,aAAa,CAAC,SAAS,eAAe,IAAI,UAAU,QAAQ,MAC1F,WAAW;AACf,YAAM,SAAS,WAAW,SAAS,UAAU,UAAU,SAAS;AAAA,IAClE;AAAA,EACF,GAAG,CAAC,OAAO,KAAK,CAAC;AAGjB,QAAM,aAAa,YAAY,YAAY;AAEzC,QAAI,CAAC,cAAc,CAAC,cAAc;AAChC,YAAM,4CAA4C,OAAO;AACzD;AAAA,IACF;AAGA,UAAM,SAAS,sBAAsB,OAAO,KAAK;AACjD,UAAM,iBAAiB,OAAO,OAAO,OAAK,EAAE,SAAS,OAAO;AAC5D,QAAI,eAAe,SAAS,GAAG;AAC7B,YAAM,gBAAgB,eAAe,MAAM,sDAAsD,OAAO;AACxG;AAAA,IACF;AAGA,UAAM,kBAAkB,kBAAkB,OAAO,OAAO,EAAE,kBAAkB,KAAK,CAAC;AAClF,UAAM,iBAAiB;AAAA,MACrB,GAAG;AAAA,MACH,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,IAC7C;AAGA,UAAM,eAAe,6BAA6B,UAAU,cAAc;AAC1E,QAAI,CAAC,aAAa,SAAS;AACzB,YAAM,aAAa,aAAa,MAAM,OAAO,CAAC;AAC9C,YAAM,iBAAiB,WAAW,KAAK,KAAK,GAAG,CAAC,MAAM,WAAW,OAAO,IAAI,OAAO;AACnF;AAAA,IACF;AAEA,gBAAY,IAAI;AAEhB,QAAI;AAEF,YAAMA,YAAgB,CAAC;AACvB,UAAI,SAAU,CAAAA,UAAS,WAAW;AAClC,UAAI,KAAK,SAAS,EAAG,CAAAA,UAAS,OAAO;AACrC,UAAI,KAAM,CAAAA,UAAS,OAAO;AAG1B,YAAM,WAAW,CAAC,CAAC;AAEnB,UAAI;AACJ,UAAI,UAAU;AAEZ,iBAAS,MAAM,QAAuC,8BAA8B,YAAY,IAAI;AAAA,UAClG,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU;AAAA,YACnB,YAAY;AAAA,YACZ;AAAA,UACF,CAAC;AAAA,QACH,CAAC;AAAA,MACH,OAAO;AAEL,iBAAS,MAAM,QAAuC,8BAA8B;AAAA,UAClF,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU;AAAA,YACnB;AAAA,YACA;AAAA,YACA,aAAa,eAAe;AAAA,YAC5B;AAAA,YACA,YAAY;AAAA,YACZ,UAAU,OAAO,KAAKA,SAAQ,EAAE,SAAS,IAAIA,YAAW;AAAA,YACxD;AAAA,YACA,eAAe,iBAAiB;AAAA,YAChC,aAAa,eAAe;AAAA,UAC9B,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AAEA,UAAI,CAAC,OAAO,IAAI;AACd,cAAM,mBAAmB,OAAO,QAAQ,SAAS,eAAe,IAAI,OAAO;AAC3E;AAAA,MACF;AAEA,YAAM,kBAAkB,OAAO,QAAQ;AAEvC,YAAM,YAAY,WAAW,YAAY,SAAS,kBAAkB,SAAS;AAG7E,iBAAW,MAAM;AACf,eAAO,KAAK,wBAAwB,gBAAgB,EAAE,EAAE;AAAA,MAC1D,GAAG,IAAI;AAAA,IAET,SAAS,OAAO;AACd,cAAQ,MAAM,qCAAqC,KAAK;AACxD,YAAM,yDAAyD,OAAO;AAAA,IACxE,UAAE;AACA,kBAAY,KAAK;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,OAAO,OAAO,YAAY,cAAc,aAAa,SAAS,SAAS,UAAU,MAAM,MAAM,eAAe,aAAa,UAAU,cAAc,MAAM,CAAC;AAG5J,QAAM,aAAa,YAAY,MAAM;AAEnC,UAAM,SAAS,sBAAsB,OAAO,KAAK;AACjD,UAAM,iBAAiB,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,OAAO;AAC9D,QAAI,eAAe,SAAS,GAAG;AAC7B,YAAM,gBAAgB,eAAe,MAAM,sDAAsD,OAAO;AACxG;AAAA,IACF;AAGA,UAAM,+CAA+C,MAAM;AAAA,EAC7D,GAAG,CAAC,OAAO,KAAK,CAAC;AAGjB,QAAM,oBAAoB,YAAY,MAAM;AAE1C,kBAAc,mBAAmB;AACjC,oBAAgB,0BAA0B;AAC1C,mBAAe,gEAAgE;AAC/E,eAAW,CAAC;AACZ,eAAW,IAAI;AACf,gBAAY,WAAW;AACvB,YAAQ,CAAC,YAAY,QAAQ,CAAC;AAE9B,UAAM,eAAuB;AAAA,MAC3B;AAAA,QACE,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,UAAU,EAAE,GAAG,KAAK,GAAG,GAAG;AAAA,QAC1B,MAAM;AAAA,UACJ,OAAO;AAAA,UACP,aAAa;AAAA,UACb,QAAQ;AAAA,UACR,OAAO;AAAA,QACT;AAAA,MACF;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,UAAU,EAAE,GAAG,KAAK,GAAG,IAAI;AAAA,QAC3B,MAAM;AAAA,UACJ,OAAO;AAAA,UACP,aAAa;AAAA,UACb,QAAQ;AAAA,UACR,YAAY;AAAA,UACZ,OAAO;AAAA,UACP,iBAAiB,CAAC,UAAU;AAAA,QAC9B;AAAA,MACF;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,UAAU,EAAE,GAAG,KAAK,GAAG,IAAI;AAAA,QAC3B,MAAM;AAAA,UACJ,OAAO;AAAA,UACP,aAAa;AAAA,UACb,QAAQ;AAAA,UACR,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAEA,UAAM,eAAuB;AAAA,MAC3B;AAAA,QACE,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,MAAM;AAAA,UACJ,SAAS;AAAA,UACT,eAAe,CAAC;AAAA,UAChB,gBAAgB,CAAC;AAAA,UACjB,YAAY,CAAC;AAAA,QACf;AAAA,MACF;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,MAAM;AAAA,UACJ,SAAS;AAAA,UACT,eAAe,CAAC;AAAA,UAChB,gBAAgB,CAAC;AAAA,UACjB,YAAY,CAAC;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAEA,aAAS,YAAY;AACrB,aAAS,YAAY;AACrB,UAAM,2BAA2B,SAAS;AAAA,EAC5C,GAAG,CAAC,CAAC;AAGL,QAAM,cAAc,YAAY,MAAM;AACpC,QAAI,MAAM,SAAS,KAAK,MAAM,SAAS,KAAK,cAAc,cAAc;AACtE,0BAAoB,IAAI;AAAA,IAC1B;AAAA,EACF,GAAG,CAAC,MAAM,QAAQ,MAAM,QAAQ,YAAY,YAAY,CAAC;AAGzD,QAAM,eAAe,YAAY,MAAM;AACrC,aAAS,CAAC,CAAC;AACX,aAAS,CAAC,CAAC;AACX,kBAAc,EAAE;AAChB,oBAAgB,EAAE;AAClB,mBAAe,EAAE;AACjB,eAAW,CAAC;AACZ,eAAW,IAAI;AACf,gBAAY,EAAE;AACd,YAAQ,CAAC,CAAC;AACV,YAAQ,EAAE;AACV,qBAAiB,EAAE;AACnB,mBAAe,EAAE;AACjB,gBAAY,CAAC,CAAC;AACd,wBAAoB,KAAK;AACzB,UAAM,kBAAkB,SAAS;AAAA,EACnC,GAAG,CAAC,CAAC;AAGL,MAAI,WAAW;AACb,WACE,oBAAC,QAAK,WAAU,iDACd,8BAAC,kBAAe,OAAM,kCAAiC,GACzD;AAAA,EAEJ;AAEA,QAAM,WAAkC;AAAA,IACtC;AAAA,IAAY;AAAA,IAAc;AAAA,IAAa;AAAA,IACvC;AAAA,IAAS;AAAA,IAAU;AAAA,IAAM;AAAA,IACzB;AAAA,IAAe;AAAA,IAAa;AAAA,EAC9B;AAEA,QAAM,mBAA6C;AAAA,IACjD;AAAA,IAAe;AAAA,IAAiB;AAAA,IAAgB;AAAA,IAChD;AAAA,IAAY;AAAA,IAAa;AAAA,IAAS;AAAA,IAClC;AAAA,IAAkB;AAAA,IAAgB;AAAA,EACpC;AAEA,QAAM,gBACJ,iCACG;AAAA,YAAQ,IAAI,0CAA0C,SACrD,oBAAC,0BAAuB,MAAM,cAAc,QAAQ,gBAAgB,SAAS,MAAM,kBAAkB,KAAK,GAAG,QAAQ,gBAAgB,UAAU,kBAAkB,IAEjK,oBAAC,kBAAe,MAAM,cAAc,QAAQ,gBAAgB,SAAS,MAAM,kBAAkB,KAAK,GAAG,QAAQ,gBAAgB,UAAU,kBAAkB;AAAA,IAE1J,QAAQ,IAAI,0CAA0C,SACrD,oBAAC,0BAAuB,MAAM,cAAc,QAAQ,gBAAgB,SAAS,MAAM,kBAAkB,KAAK,GAAG,QAAQ,gBAAgB,UAAU,kBAAkB,IAEjK,oBAAC,kBAAe,MAAM,cAAc,QAAQ,gBAAgB,SAAS,MAAM,kBAAkB,KAAK,GAAG,QAAQ,gBAAgB,UAAU,kBAAkB;AAAA,IAE3J,oBAAC,UAAO,MAAM,kBAAkB,cAAc,qBAC5C,+BAAC,iBAAc,WAAU,eACvB;AAAA,2BAAC,gBACC;AAAA,4BAAC,eAAa,YAAE,mCAAmC,GAAE;AAAA,QACrD,oBAAC,qBAAmB,YAAE,yCAAyC,GAAE;AAAA,SACnE;AAAA,MACA,qBAAC,gBACC;AAAA,4BAAC,UAAO,SAAQ,WAAU,SAAS,MAAM,oBAAoB,KAAK,GAAI,YAAE,iBAAiB,QAAQ,GAAE;AAAA,QACnG,oBAAC,UAAO,SAAQ,eAAc,SAAS,cAAe,YAAE,gBAAgB,OAAO,GAAE;AAAA,SACnF;AAAA,OACF,GACF;AAAA,KACF;AAGF,MAAI,UAAU;AACZ,WACE,qBAAC,QAAK,WAAU,sDACd;AAAA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,eAAe;AAAA,UACf,eAAe;AAAA,UACf,aAAa;AAAA,UACb,aAAa;AAAA,UACb,WAAW;AAAA,UACX,WAAW;AAAA,UACX,QAAQ;AAAA,UACR,YAAY;AAAA,UACZ,QAAQ;AAAA,UACR,eAAe;AAAA,UACf,SAAS;AAAA,UACT;AAAA,UACA;AAAA;AAAA,MACF;AAAA,MACC;AAAA,OACH;AAAA,EAEJ;AAEA,SACE,qBAAC,QAAK,WAAU,+BAEd;AAAA,wBAAC,SAAI,WAAU,2EACb;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,UAAS;AAAA,QACT,WAAW,EAAE,oCAAoC,qBAAqB;AAAA,QACtE,OAAO,eAAgB,gBAAgB,EAAE,gCAAgC,IAAK,EAAE,mDAAmD;AAAA,QACnI,UAAU,eACN,EAAE,wCAAwC,6BAA6B,IACvE,EAAE,wCAAwC,8EAA8E;AAAA,QAE5H,gBACE,qBAAC,SAAI,WAAU,0DACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MAAM,gBAAgB,CAAC,YAAY;AAAA,cAC5C,UAAU;AAAA,cACV,WAAU;AAAA,cACV,cAAY,eAAe,EAAE,qCAAqC,IAAI,EAAE,qCAAqC;AAAA,cAE5G;AAAA,+BAAe,oBAAC,iBAAc,WAAU,kBAAiB,IAAK,oBAAC,gBAAa,WAAU,kBAAiB;AAAA,gBACvG,eAAe,EAAE,qCAAqC,IAAI,EAAE,qCAAqC;AAAA;AAAA;AAAA,UACpG;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS;AAAA,cACT,UAAU;AAAA,cACV,WAAU;AAAA,cAET,YAAE,oCAAoC;AAAA;AAAA,UACzC;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS;AAAA,cACT,UAAU;AAAA,cACV,WAAU;AAAA,cACV,cAAY,EAAE,8BAA8B;AAAA,cAE5C;AAAA,oCAAC,UAAO,WAAU,kBAAiB;AAAA,gBAClC,EAAE,8BAA8B;AAAA;AAAA;AAAA,UACnC;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS;AAAA,cACT,UAAU;AAAA,cACV,WAAU;AAAA,cACV,cAAY,EAAE,iCAAiC;AAAA,cAE/C;AAAA,oCAAC,sBAAmB,WAAU,kBAAiB;AAAA,gBAC9C,EAAE,iCAAiC;AAAA;AAAA;AAAA,UACtC;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS;AAAA,cACT,UAAU;AAAA,cACV,WAAU;AAAA,cAEV;AAAA,oCAAC,QAAK,WAAU,kBAAiB;AAAA,gBAChC,EAAE,gCAAgC;AAAA;AAAA;AAAA,UACrC;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS;AAAA,cACT,UAAU;AAAA,cACV,WAAU;AAAA,cACV,cAAY,WAAW,EAAE,yBAAyB,IAAI,eAAe,EAAE,yBAAyB,IAAI,EAAE,uBAAuB;AAAA,cAE7H;AAAA,oCAAC,QAAK,WAAU,kBAAiB;AAAA,gBAChC,WAAW,EAAE,yBAAyB,IAAI,eAAe,EAAE,yBAAyB,IAAI,EAAE,uBAAuB;AAAA;AAAA;AAAA,UACpH;AAAA,WACF;AAAA;AAAA,IAEJ,GACF;AAAA,IAGC,gBACC,qBAAC,SAAI,WAAW,oBACZ,6HACA,2EAEF;AAAA,2BAAC,SAAI,WAAU,wCACb;AAAA,4BAAC,QAAG,WAAU,8DAA8D,YAAE,yCAAyC,GAAE;AAAA,QACzH,qBAAC,SAAI,WAAU,iEAEb;AAAA,+BAAC,SAAI,WAAU,qBACb;AAAA,gCAAC,SAAM,SAAQ,cAAa,WAAU,WAAU,2BAAa;AAAA,YAC7D;AAAA,cAAC;AAAA;AAAA,gBACC,IAAG;AAAA,gBACH,OAAO;AAAA,gBACP,UAAU,CAAC,MAAM,cAAc,EAAE,OAAO,KAAK;AAAA,gBAC7C,aAAY;AAAA,gBACZ,UAAU,CAAC,CAAC;AAAA,gBACZ,WAAU;AAAA;AAAA,YACZ;AAAA,YACC,gBAAgB,oBAAC,OAAE,WAAU,qCAAoC,uBAAS;AAAA,aAC7E;AAAA,UAGA,qBAAC,SAAI,WAAU,qBACb;AAAA,gCAAC,SAAM,SAAQ,gBAAe,WAAU,WAAU,oBAAM;AAAA,YACxD;AAAA,cAAC;AAAA;AAAA,gBACC,IAAG;AAAA,gBACH,OAAO;AAAA,gBACP,UAAU,CAAC,MAAM,gBAAgB,EAAE,OAAO,KAAK;AAAA,gBAC/C,aAAY;AAAA,gBACZ,WAAU;AAAA;AAAA,YACZ;AAAA,aACF;AAAA,UAGA,qBAAC,SAAI,WAAU,qBACb;AAAA,gCAAC,SAAM,SAAQ,YAAW,WAAU,WAAU,sBAAQ;AAAA,YACtD;AAAA,cAAC;AAAA;AAAA,gBACC,IAAG;AAAA,gBACH,OAAO;AAAA,gBACP,UAAU,CAAC,MAAM,YAAY,EAAE,OAAO,KAAK;AAAA,gBAC3C,aAAY;AAAA,gBACZ,WAAU;AAAA;AAAA,YACZ;AAAA,aACF;AAAA,UAGA,qBAAC,SAAI,WAAU,iDACb;AAAA,gCAAC,SAAM,SAAQ,eAAc,WAAU,WAAU,yBAAW;AAAA,YAC5D;AAAA,cAAC;AAAA;AAAA,gBACC,IAAG;AAAA,gBACH,OAAO;AAAA,gBACP,UAAU,CAAC,MAAM,eAAe,EAAE,OAAO,KAAK;AAAA,gBAC9C,aAAY;AAAA,gBACZ,MAAM;AAAA,gBACN,WAAU;AAAA;AAAA,YACZ;AAAA,aACF;AAAA,UAGA,qBAAC,SAAI,WAAU,qBACb;AAAA,gCAAC,SAAM,SAAQ,WAAU,WAAU,WAAU,uBAAS;AAAA,YACtD;AAAA,cAAC;AAAA;AAAA,gBACC,IAAG;AAAA,gBACH,MAAK;AAAA,gBACL,OAAO;AAAA,gBACP,UAAU,CAAC,MAAM,WAAW,SAAS,EAAE,OAAO,KAAK,KAAK,CAAC;AAAA,gBACzD,KAAK;AAAA,gBACL,UAAU,CAAC,CAAC;AAAA,gBACZ,WAAU;AAAA;AAAA,YACZ;AAAA,aACF;AAAA,UAGA,qBAAC,SAAI,WAAU,qBACb;AAAA,gCAAC,SAAM,WAAU,WAAW,YAAE,kBAAkB,SAAS,GAAE;AAAA,YAC3D,qBAAC,SAAI,WAAU,+BACb;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,IAAG;AAAA,kBACH,SAAS;AAAA,kBACT,iBAAiB;AAAA;AAAA,cACnB;AAAA,cACA,oBAAC,SAAM,SAAQ,WAAU,WAAU,sCAChC,oBAAU,EAAE,aAAa,IAAI,IAAI,EAAE,cAAc,KAAK,GACzD;AAAA,eACF;AAAA,aACF;AAAA,UAGA,qBAAC,SAAI,WAAU,qBACb;AAAA,gCAAC,SAAM,WAAU,WAAU,kBAAI;AAAA,YAC/B;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO;AAAA,gBACP,UAAU;AAAA,gBACV,aAAa,EAAE,kCAAkC;AAAA;AAAA,YACnD;AAAA,aACF;AAAA,UAGA,qBAAC,SAAI,WAAU,qBACb;AAAA,gCAAC,SAAM,SAAQ,QAAO,WAAU,WAAU,kBAAI;AAAA,YAC9C;AAAA,cAAC;AAAA;AAAA,gBACC,IAAG;AAAA,gBACH,OAAO;AAAA,gBACP,UAAU,CAAC,MAAM,QAAQ,EAAE,OAAO,KAAK;AAAA,gBACvC,aAAY;AAAA,gBACZ,WAAU;AAAA;AAAA,YACZ;AAAA,aACF;AAAA,UAEA,qBAAC,SAAI,WAAU,qBACb;AAAA,gCAAC,SAAM,SAAQ,iBAAgB,WAAU,WAAU,4BAAc;AAAA,YACjE;AAAA,cAAC;AAAA;AAAA,gBACC,IAAG;AAAA,gBACH,MAAK;AAAA,gBACL,OAAO;AAAA,gBACP,UAAU,CAAC,MAAM,iBAAiB,EAAE,OAAO,KAAK;AAAA,gBAChD,WAAU;AAAA;AAAA,YACZ;AAAA,aACF;AAAA,UAEA,qBAAC,SAAI,WAAU,qBACb;AAAA,gCAAC,SAAM,SAAQ,eAAc,WAAU,WAAU,0BAAY;AAAA,YAC7D;AAAA,cAAC;AAAA;AAAA,gBACC,IAAG;AAAA,gBACH,MAAK;AAAA,gBACL,OAAO;AAAA,gBACP,UAAU,CAAC,MAAM,eAAe,EAAE,OAAO,KAAK;AAAA,gBAC9C,WAAU;AAAA;AAAA,YACZ;AAAA,aACF;AAAA,WACF;AAAA,SACF;AAAA,MAGA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,UACP,UAAU;AAAA,UACV,WAAU;AAAA;AAAA,MACZ;AAAA,OACF;AAAA,IAID,oBACC,qBAAC,SAAI,WAAU,6BACb;AAAA,2BAAC,SAAI,WAAU,oBACb;AAAA,4BAAC,SAAI,WAAU,qDACb;AAAA,UAAC;AAAA;AAAA,YACC,cAAc;AAAA,YACd,cAAc;AAAA,YACd,eAAe;AAAA,YACf,eAAe;AAAA,YACf,aAAa;AAAA,YACb,aAAa;AAAA,YACb,WAAW;AAAA,YACX,UAAU;AAAA,YACV,QAAO;AAAA;AAAA,QACT,GACF;AAAA,QAEC,MAAM,WAAW,KAChB,oBAAC,SAAI,WAAU,8EACb,+BAAC,SAAI,WAAU,eACb;AAAA,8BAAC,QAAG,WAAU,8CAA6C,0CAA4B;AAAA,UACvF,oBAAC,OAAE,WAAU,sCAAqC,2DAA6C;AAAA,UAC/F;AAAA,YAAC;AAAA;AAAA,cACC,SAAS;AAAA,cACT,WAAU;AAAA,cACX;AAAA;AAAA,UAED;AAAA,WACF,GACF;AAAA,SAEJ;AAAA,MAEA,qBAAC,SAAI,WAAU,sCACb;AAAA,4BAAC,QAAG,WAAU,8DAA6D,0BAAY;AAAA,QACvF,oBAAC,OAAE,WAAU,sCAAqC,qDAAuC;AAAA,QAEzF,oBAAC,SAAI,WAAU,mCACX,WAAC,SAAS,YAAY,aAAa,iBAAiB,eAAe,KAAK,EAAY,IAAI,CAAC,aAAa;AACtG,gBAAM,OAAO,gBAAgB,QAAQ;AACrC,iBACE;AAAA,YAAC;AAAA;AAAA,cAEC,SAAS,MAAM,cAAc,QAAQ;AAAA,cACrC,WAAU;AAAA,cAEV;AAAA,oCAAC,QAAK,WAAU,eAAc;AAAA,gBAC9B,oBAAC,UAAM,2BAAiB,QAAQ,EAAE,OAAM;AAAA;AAAA;AAAA,YALnC;AAAA,UAMP;AAAA,QAEJ,CAAC,GACH;AAAA,SACF;AAAA,OACF,IAEA,qBAAC,SAAI,WAAU,4DAEb;AAAA,0BAAC,SAAI,WAAU,+EACb,+BAAC,SAAI,WAAU,iCACb;AAAA,4BAAC,QAAG,WAAU,8DAA6D,0BAAY;AAAA,QACvF,oBAAC,OAAE,WAAU,sCAAqC,uDAElD;AAAA,QAEA,qBAAC,SAAI,WAAU,aAEb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAS,MAAM,cAAc,OAAO;AAAA,cACpC,WAAU;AAAA,cAEV;AAAA,oCAAC,SAAI,WAAW,0BAA0B,iBAAiB,KAAK,0DAC5D,iBAAM;AACN,wBAAM,OAAO,gBAAgB;AAC7B,yBAAO,oBAAC,QAAK,WAAU,WAAU;AAAA,gBACnC,GAAG,GACL;AAAA,gBACA,oBAAC,SAAI,WAAU,yCAAyC,2BAAiB,MAAM,OAAM;AAAA,gBACrF,oBAAC,SAAI,WAAU,wCAAwC,2BAAiB,MAAM,aAAY;AAAA;AAAA;AAAA,UAC5F;AAAA,UAGA;AAAA,YAAC;AAAA;AAAA,cACC,SAAS,MAAM,cAAc,UAAU;AAAA,cACvC,WAAU;AAAA,cAEV;AAAA,oCAAC,SAAI,WAAW,0BAA0B,iBAAiB,QAAQ,0DAC/D,iBAAM;AACN,wBAAM,OAAO,gBAAgB;AAC7B,yBAAO,oBAAC,QAAK,WAAU,WAAU;AAAA,gBACnC,GAAG,GACL;AAAA,gBACA,oBAAC,SAAI,WAAU,yCAAyC,2BAAiB,SAAS,OAAM;AAAA,gBACxF,oBAAC,SAAI,WAAU,wCAAwC,2BAAiB,SAAS,aAAY;AAAA;AAAA;AAAA,UAC/F;AAAA,UAGA;AAAA,YAAC;AAAA;AAAA,cACC,SAAS,MAAM,cAAc,WAAW;AAAA,cACxC,WAAU;AAAA,cAEV;AAAA,oCAAC,SAAI,WAAW,0BAA0B,iBAAiB,SAAS,0DAChE,iBAAM;AACN,wBAAM,OAAO,gBAAgB;AAC7B,yBAAO,oBAAC,QAAK,WAAU,WAAU;AAAA,gBACnC,GAAG,GACL;AAAA,gBACA,oBAAC,SAAI,WAAU,yCAAyC,2BAAiB,UAAU,OAAM;AAAA,gBACzF,oBAAC,SAAI,WAAU,wCAAwC,2BAAiB,UAAU,aAAY;AAAA;AAAA;AAAA,UAChG;AAAA,UAGA;AAAA,YAAC;AAAA;AAAA,cACC,SAAS,MAAM,cAAc,eAAe;AAAA,cAC5C,WAAU;AAAA,cAEV;AAAA,oCAAC,SAAI,WAAW,0BAA0B,iBAAiB,aAAa,0DACpE,iBAAM;AACN,wBAAM,OAAO,gBAAgB;AAC7B,yBAAO,oBAAC,QAAK,WAAU,WAAU;AAAA,gBACnC,GAAG,GACL;AAAA,gBACA,oBAAC,SAAI,WAAU,yCAAyC,2BAAiB,cAAc,OAAM;AAAA,gBAC7F,oBAAC,SAAI,WAAU,wCAAwC,2BAAiB,cAAc,aAAY;AAAA;AAAA;AAAA,UACpG;AAAA,UAGA;AAAA,YAAC;AAAA;AAAA,cACC,SAAS,MAAM,cAAc,aAAa;AAAA,cAC1C,WAAU;AAAA,cAEV;AAAA,oCAAC,SAAI,WAAW,0BAA0B,iBAAiB,WAAW,0DAClE,iBAAM;AACN,wBAAM,OAAO,gBAAgB;AAC7B,yBAAO,oBAAC,QAAK,WAAU,WAAU;AAAA,gBACnC,GAAG,GACL;AAAA,gBACA,oBAAC,SAAI,WAAU,yCAAyC,2BAAiB,YAAY,OAAM;AAAA,gBAC3F,oBAAC,SAAI,WAAU,wCAAwC,2BAAiB,YAAY,aAAY;AAAA;AAAA;AAAA,UAClG;AAAA,UAGA;AAAA,YAAC;AAAA;AAAA,cACC,SAAS,MAAM,cAAc,KAAK;AAAA,cAClC,WAAU;AAAA,cAEV;AAAA,oCAAC,SAAI,WAAW,0BAA0B,iBAAiB,GAAG,0DAC1D,iBAAM;AACN,wBAAM,OAAO,gBAAgB;AAC7B,yBAAO,oBAAC,QAAK,WAAU,WAAU;AAAA,gBACnC,GAAG,GACL;AAAA,gBACA,oBAAC,SAAI,WAAU,yCAAyC,2BAAiB,IAAI,OAAM;AAAA,gBACnF,oBAAC,SAAI,WAAU,wCAAwC,2BAAiB,IAAI,aAAY;AAAA;AAAA;AAAA,UAC1F;AAAA,WACF;AAAA,QAGA,qBAAC,SAAM,SAAQ,QAAO,WAAU,QAC9B;AAAA,8BAAC,QAAK,WAAU,UAAS;AAAA,UACzB,oBAAC,cAAW,WAAU,WAAU,yBAAW;AAAA,UAC3C,oBAAC,SAAI,WAAU,QACb,+BAAC,QAAG,WAAU,2CACZ;AAAA,gCAAC,QAAG,0CAA4B;AAAA,YAChC,oBAAC,QAAG,yCAA2B;AAAA,YAC/B,oBAAC,QAAG,oDAAsC;AAAA,YAC1C,oBAAC,QAAG,sDAAwC;AAAA,YAC5C,oBAAC,QAAG,oCAAsB;AAAA,aAC5B,GACF;AAAA,WACF;AAAA,SACF,GACF;AAAA,MAGA,oBAAC,SAAI,WAAU,sBACb,+BAAC,SAAI,WAAU,oCACb;AAAA,4BAAC,SAAI,WAAU,oCACb;AAAA,UAAC;AAAA;AAAA,YACC,cAAc;AAAA,YACd,cAAc;AAAA,YACd,eAAe;AAAA,YACf,eAAe;AAAA,YACf,aAAa;AAAA,YACb,aAAa;AAAA,YACb,WAAW;AAAA,YACX,UAAU;AAAA,YACV,QAAO;AAAA;AAAA,QACT,GACF;AAAA,QAGC,MAAM,WAAW,KAChB,oBAAC,SAAI,WAAU,8EACb,+BAAC,SAAI,WAAU,eACb;AAAA,8BAAC,QAAG,WAAU,8CAA6C,0CAE3D;AAAA,UACA,oBAAC,OAAE,WAAU,8BAA6B,wEAE1C;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAS;AAAA,cACT,WAAU;AAAA,cACX;AAAA;AAAA,UAED;AAAA,WACF,GACF;AAAA,SAEJ,GACF;AAAA,OACF;AAAA,IAED;AAAA,KACH;AAEJ;AAGA,SAAS,gBAAgB,UAA0B;AACjD,QAAM,SAAiC;AAAA,IACrC,OAAO;AAAA,IACP,KAAK;AAAA,IACL,UAAU;AAAA,IACV,WAAW;AAAA,IACX,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AACA,SAAO,OAAO,QAAQ,KAAK;AAC7B;AAEA,SAAS,gBAAgB,UAA0B;AACjD,QAAM,SAAiC;AAAA,IACrC,OAAO;AAAA,IACP,KAAK;AAAA,IACL,UAAU;AAAA,IACV,WAAW;AAAA,IACX,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AACA,SAAO,OAAO,QAAQ,KAAK;AAC7B;",
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport { WorkflowGraph } from '../../../components/WorkflowGraph'\n// Conditional imports based on feature flag\nimport { NodeEditDialog } from '../../../components/NodeEditDialog'\nimport { EdgeEditDialog } from '../../../components/EdgeEditDialog'\nimport { NodeEditDialogCrudForm } from '../../../components/NodeEditDialogCrudForm'\nimport { EdgeEditDialogCrudForm } from '../../../components/EdgeEditDialogCrudForm'\nimport { Node, Edge, addEdge, Connection, applyNodeChanges, applyEdgeChanges, NodeChange, EdgeChange } from '@xyflow/react'\nimport { useState, useCallback, useEffect } from 'react'\nimport { useRouter, useSearchParams } from 'next/navigation'\nimport { graphToDefinition, definitionToGraph, validateWorkflowGraph, generateStepId, generateTransitionId, ValidationError } from '../../../lib/graph-utils'\nimport { workflowDefinitionDataSchema } from '../../../data/validators'\nimport { Page } from '@open-mercato/ui/backend/Page'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Switch } from '@open-mercato/ui/primitives/switch'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { TagsInput } from '@open-mercato/ui/backend/inputs/TagsInput'\nimport { LoadingMessage } from '@open-mercato/ui/backend/detail'\nimport { Alert, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { FormHeader } from '@open-mercato/ui/backend/forms'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { CircleQuestionMark, Info, PanelTopClose, PanelTopOpen, Play, Save, Trash2 } from 'lucide-react'\nimport { NODE_TYPE_ICONS, NODE_TYPE_COLORS, NODE_TYPE_LABELS } from '../../../lib/node-type-icons'\nimport { DefinitionTriggersEditor } from '../../../components/DefinitionTriggersEditor'\nimport { MobileVisualEditor } from '../../../components/mobile/MobileVisualEditor'\nimport { useIsMobile } from '@open-mercato/ui/hooks/useIsMobile'\nimport type { WorkflowDefinitionTrigger } from '../../../data/entities'\nimport type { WorkflowMetadataState, WorkflowMetadataHandlers } from '../../../data/types'\nimport * as React from 'react'\n\n/**\n * VisualEditorPage - Visual workflow definition editor\n *\n * Layout:\n * - Page Header: Title, description, and action buttons (Save, Validate, Test)\n * - Workflow Metadata: Collapsible form for workflow details\n * - Page Body:\n * - Left sidebar: Step palette (click to add)\n * - Main canvas: ReactFlow graph editor\n * - Flash Messages: Top-right positioned validation messages\n * - Edit Dialogs: Modal dialogs for editing steps and transitions\n */\nexport default function VisualEditorPage() {\n const t = useT()\n const router = useRouter()\n const searchParams = useSearchParams()\n const definitionId = searchParams.get('id')\n const isMobile = useIsMobile()\n\n const [isLoading, setIsLoading] = useState(!!definitionId)\n const [isSaving, setIsSaving] = useState(false)\n const [nodes, setNodes] = useState<Node[]>([])\n const [edges, setEdges] = useState<Edge[]>([])\n const [selectedNode, setSelectedNode] = useState<Node | null>(null)\n const [selectedEdge, setSelectedEdge] = useState<Edge | null>(null)\n const [showMetadata, setShowMetadata] = useState(true)\n const [isCompactViewport, setIsCompactViewport] = useState(false)\n\n // Auto-collapse metadata on compact viewports after hydration\n useEffect(() => {\n if (typeof window === 'undefined') return\n const mediaQuery = window.matchMedia('(max-width: 1279px)')\n const applyViewportMode = () => {\n const compact = mediaQuery.matches\n setIsCompactViewport(compact)\n setShowMetadata(!compact)\n }\n\n applyViewportMode()\n mediaQuery.addEventListener('change', applyViewportMode)\n\n return () => {\n mediaQuery.removeEventListener('change', applyViewportMode)\n }\n }, [])\n const [showNodeDialog, setShowNodeDialog] = useState(false)\n const [showEdgeDialog, setShowEdgeDialog] = useState(false)\n const [showClearConfirm, setShowClearConfirm] = useState(false)\n\n // Workflow metadata state\n const [workflowId, setWorkflowId] = useState('')\n const [workflowName, setWorkflowName] = useState('')\n const [description, setDescription] = useState('')\n const [version, setVersion] = useState(1)\n const [enabled, setEnabled] = useState(true)\n const [category, setCategory] = useState('')\n const [tags, setTags] = useState<string[]>([])\n const [icon, setIcon] = useState('')\n const [effectiveFrom, setEffectiveFrom] = useState('')\n const [effectiveTo, setEffectiveTo] = useState('')\n const [triggers, setTriggers] = useState<WorkflowDefinitionTrigger[]>([])\n\n // Load existing definition if ID is provided\n useEffect(() => {\n const loadDefinition = async () => {\n if (!definitionId) {\n setIsLoading(false)\n return\n }\n\n try {\n const result = await apiCall<{ data: any; error?: string }>(`/api/workflows/definitions/${definitionId}`)\n\n if (!result.ok) {\n flash(`Failed to load workflow: ${result.result?.error || 'Unknown error'}`, 'error')\n setIsLoading(false)\n return\n }\n\n const definition = result.result?.data\n\n // Populate metadata\n setWorkflowId(definition.workflowId)\n setWorkflowName(definition.workflowName || definition.definition.workflowName || '')\n setDescription(definition.description || definition.definition.description || '')\n setVersion(definition.version)\n setEnabled(definition.enabled)\n setCategory(definition.metadata?.category || '')\n setTags(definition.metadata?.tags || [])\n setIcon(definition.metadata?.icon || '')\n setEffectiveFrom(definition.effectiveFrom || '')\n setEffectiveTo(definition.effectiveTo || '')\n\n // Convert definition to graph\n const graph = definitionToGraph(definition.definition)\n setNodes(graph.nodes)\n setEdges(graph.edges)\n\n // Load embedded triggers from definition\n setTriggers(definition.definition?.triggers || [])\n\n flash('Workflow loaded successfully', 'success')\n } catch (error) {\n console.error('Error loading workflow definition:', error)\n flash('Failed to load workflow definition', 'error')\n } finally {\n setIsLoading(false)\n }\n }\n\n loadDefinition()\n }, [definitionId])\n\n // Handle node changes from ReactFlow\n const handleNodesChange = useCallback((changes: NodeChange[]) => {\n setNodes((nds) => applyNodeChanges(changes, nds))\n }, [])\n\n // Handle edge changes from ReactFlow\n const handleEdgesChange = useCallback((changes: EdgeChange[]) => {\n setEdges((eds) => applyEdgeChanges(changes, eds))\n }, [])\n\n // Handle adding new node from palette\n const handleAddNode = useCallback((nodeType: string) => {\n const newNode: Node = {\n id: generateStepId(nodeType),\n type: nodeType,\n position: {\n x: 250 + nodes.length * 50,\n y: 100 + nodes.length * 150,\n },\n data: {\n label: getDefaultLabel(nodeType),\n description: '',\n badge: getDefaultBadge(nodeType),\n status: 'pending',\n },\n }\n\n setNodes((nds) => [...nds, newNode])\n }, [nodes.length])\n\n // Handle node selection - open edit dialog\n const handleNodeClick = useCallback((_event: React.MouseEvent, node: Node) => {\n setSelectedNode(node)\n setSelectedEdge(null)\n setShowNodeDialog(true)\n }, [])\n\n // Handle edge selection - open edit dialog\n const handleEdgeClick = useCallback((_event: React.MouseEvent, edge: Edge) => {\n setSelectedEdge(edge)\n setSelectedNode(null)\n setShowEdgeDialog(true)\n }, [])\n\n // Save node updates\n const handleSaveNode = useCallback((nodeId: string, updates: Partial<Node['data']>) => {\n setNodes((nds) =>\n nds.map((node) =>\n node.id === nodeId\n ? { ...node, data: { ...node.data, ...updates } }\n : node\n )\n )\n flash('Node updated successfully', 'success')\n }, [])\n\n // Save edge updates\n const handleSaveEdge = useCallback((edgeId: string, updates: Partial<Edge['data']>) => {\n setEdges((eds) =>\n eds.map((edge) =>\n edge.id === edgeId\n ? { ...edge, data: { ...edge.data, ...updates } }\n : edge\n )\n )\n flash('Transition updated successfully', 'success')\n }, [])\n\n // Delete edge\n const handleDeleteEdge = useCallback((edgeId: string) => {\n setEdges((eds) => eds.filter((edge) => edge.id !== edgeId))\n flash('Transition deleted successfully', 'success')\n }, [])\n\n // Delete node\n const handleDeleteNode = useCallback((nodeId: string) => {\n // Remove the node\n setNodes((nds) => nds.filter((node) => node.id !== nodeId))\n\n // Remove all edges connected to this node\n setEdges((eds) => eds.filter((edge) => edge.source !== nodeId && edge.target !== nodeId))\n\n flash('Step deleted successfully', 'success')\n }, [])\n\n // Handle new connections\n const handleConnect = useCallback((connection: Connection) => {\n const newEdge: Edge = {\n id: generateTransitionId(connection.source!, connection.target!),\n source: connection.source!,\n target: connection.target!,\n type: 'smoothstep',\n data: {\n trigger: 'auto',\n preConditions: [],\n postConditions: [],\n activities: [],\n label: '',\n },\n }\n\n setEdges((eds) => addEdge(newEdge, eds))\n }, [])\n\n // Validate workflow\n const handleValidate = useCallback(() => {\n const graphErrors = validateWorkflowGraph(nodes, edges)\n const allErrors: ValidationError[] = [...graphErrors]\n\n // Run Zod schema validation\n try {\n const definitionData = graphToDefinition(nodes, edges, { includePositions: true })\n const result = workflowDefinitionDataSchema.safeParse(definitionData)\n\n if (!result.success) {\n // Convert Zod errors to validation errors\n result.error.issues.forEach((issue) => {\n allErrors.push({\n type: 'error',\n message: `Schema validation: ${issue.path.join('.')} - ${issue.message}`,\n })\n })\n }\n } catch (error) {\n allErrors.push({\n type: 'error',\n message: `Schema validation failed: ${error instanceof Error ? error.message : 'Unknown error'}`,\n })\n }\n\n if (allErrors.length === 0) {\n flash('Validation passed! Your workflow is valid and ready to save.', 'success')\n } else {\n // Show first error/warning message\n const firstError = allErrors[0]\n const errorCount = allErrors.length\n const message = errorCount > 1\n ? `${firstError.message} (and ${errorCount - 1} more ${errorCount === 2 ? 'issue' : 'issues'})`\n : firstError.message\n flash(message, firstError.type === 'error' ? 'error' : 'warning')\n }\n }, [nodes, edges])\n\n // Save workflow definition\n const handleSave = useCallback(async () => {\n // Validate required fields\n if (!workflowId || !workflowName) {\n flash('Workflow ID and Name are required fields', 'error')\n return\n }\n\n // Validate workflow structure\n const errors = validateWorkflowGraph(nodes, edges)\n const criticalErrors = errors.filter(e => e.type === 'error')\n if (criticalErrors.length > 0) {\n flash(`Cannot save: ${criticalErrors.length} validation error(s) found. Please fix them first.`, 'error')\n return\n }\n\n // Generate definition data and include triggers\n const graphDefinition = graphToDefinition(nodes, edges, { includePositions: true })\n const definitionData = {\n ...graphDefinition,\n triggers: triggers.length > 0 ? triggers : undefined,\n }\n\n // Run Zod schema validation before saving\n const schemaResult = workflowDefinitionDataSchema.safeParse(definitionData)\n if (!schemaResult.success) {\n const firstIssue = schemaResult.error.issues[0]\n flash(`Schema error: ${firstIssue.path.join('.')} - ${firstIssue.message}`, 'error')\n return\n }\n\n setIsSaving(true)\n\n try {\n\n const metadata: any = {}\n if (category) metadata.category = category\n if (tags.length > 0) metadata.tags = tags\n if (icon) metadata.icon = icon\n\n // Determine if creating new or updating existing\n const isUpdate = !!definitionId\n\n let result\n if (isUpdate) {\n // Update existing definition\n result = await apiCall<{ data: any; error?: string }>(`/api/workflows/definitions/${definitionId}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n definition: definitionData,\n enabled,\n }),\n })\n } else {\n // Create new definition\n result = await apiCall<{ data: any; error?: string }>('/api/workflows/definitions', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n workflowId,\n workflowName,\n description: description || null,\n version,\n definition: definitionData,\n metadata: Object.keys(metadata).length > 0 ? metadata : null,\n enabled,\n effectiveFrom: effectiveFrom || null,\n effectiveTo: effectiveTo || null,\n }),\n })\n }\n\n if (!result.ok) {\n flash(`Failed to save: ${result.result?.error || 'Unknown error'}`, 'error')\n return\n }\n\n const savedDefinition = result.result?.data\n\n flash(`Workflow ${isUpdate ? 'updated' : 'created'} successfully!`, 'success')\n\n // Redirect to definition detail page after short delay\n setTimeout(() => {\n router.push(`/backend/definitions/${savedDefinition.id}`)\n }, 1500)\n\n } catch (error) {\n console.error('Error saving workflow definition:', error)\n flash('Failed to save workflow definition. Please try again.', 'error')\n } finally {\n setIsSaving(false)\n }\n }, [nodes, edges, workflowId, workflowName, description, version, enabled, category, tags, icon, effectiveFrom, effectiveTo, triggers, definitionId, router])\n\n // Test workflow\n const handleTest = useCallback(() => {\n // First validate\n const errors = validateWorkflowGraph(nodes, edges)\n const criticalErrors = errors.filter((e) => e.type === 'error')\n if (criticalErrors.length > 0) {\n flash(`Cannot test: ${criticalErrors.length} validation error(s) found. Please fix them first.`, 'error')\n return\n }\n\n // TODO: Implement test logic (create instance, run first step)\n flash('Test functionality will be implemented next', 'info')\n }, [nodes, edges])\n\n // Load example workflow\n const handleLoadExample = useCallback(() => {\n // Set example metadata\n setWorkflowId('approval_workflow')\n setWorkflowName('Simple Approval Workflow')\n setDescription('A basic approval workflow for reviewing and approving requests')\n setVersion(1)\n setEnabled(true)\n setCategory('Approvals')\n setTags(['approval', 'review'])\n\n const exampleNodes: Node[] = [\n {\n id: 'start',\n type: 'start',\n position: { x: 250, y: 50 },\n data: {\n label: 'Start',\n description: 'Workflow begins',\n status: 'pending',\n badge: 'Start',\n },\n },\n {\n id: 'step1',\n type: 'userTask',\n position: { x: 250, y: 250 },\n data: {\n label: 'Review Request',\n description: 'User reviews the incoming request',\n status: 'pending',\n stepNumber: 1,\n badge: 'User Task',\n assignedToRoles: ['Reviewer'],\n },\n },\n {\n id: 'end',\n type: 'end',\n position: { x: 250, y: 450 },\n data: {\n label: 'Complete',\n description: 'Workflow ends',\n status: 'pending',\n badge: 'End',\n },\n },\n ]\n\n const exampleEdges: Edge[] = [\n {\n id: 'e-start-step1',\n source: 'start',\n target: 'step1',\n type: 'smoothstep',\n data: {\n trigger: 'auto',\n preConditions: [],\n postConditions: [],\n activities: [],\n },\n },\n {\n id: 'e-step1-end',\n source: 'step1',\n target: 'end',\n type: 'smoothstep',\n data: {\n trigger: 'auto',\n preConditions: [],\n postConditions: [],\n activities: [],\n },\n },\n ]\n\n setNodes(exampleNodes)\n setEdges(exampleEdges)\n flash('Example workflow loaded', 'success')\n }, [])\n\n // Clear canvas\n const handleClear = useCallback(() => {\n if (nodes.length > 0 || edges.length > 0 || workflowId || workflowName) {\n setShowClearConfirm(true)\n }\n }, [nodes.length, edges.length, workflowId, workflowName])\n\n // Confirm clear action\n const confirmClear = useCallback(() => {\n setNodes([])\n setEdges([])\n setWorkflowId('')\n setWorkflowName('')\n setDescription('')\n setVersion(1)\n setEnabled(true)\n setCategory('')\n setTags([])\n setIcon('')\n setEffectiveFrom('')\n setEffectiveTo('')\n setTriggers([])\n setShowClearConfirm(false)\n flash('Canvas cleared', 'success')\n }, [])\n\n // Show loading spinner while loading definition\n if (isLoading) {\n return (\n <Page className=\"flex items-center justify-center min-h-[50vh]\">\n <LoadingMessage label=\"Loading workflow definition...\" />\n </Page>\n )\n }\n\n const metadata: WorkflowMetadataState = {\n workflowId, workflowName, description, version,\n enabled, category, tags, icon,\n effectiveFrom, effectiveTo, triggers,\n }\n\n const metadataHandlers: WorkflowMetadataHandlers = {\n setWorkflowId, setWorkflowName, setDescription, setVersion,\n setEnabled, setCategory, setTags, setIcon,\n setEffectiveFrom, setEffectiveTo, setTriggers,\n }\n\n const sharedDialogs = (\n <>\n {process.env.NEXT_PUBLIC_WORKFLOW_CRUDFORM_ENABLED === 'true' ? (\n <NodeEditDialogCrudForm node={selectedNode} isOpen={showNodeDialog} onClose={() => setShowNodeDialog(false)} onSave={handleSaveNode} onDelete={handleDeleteNode} />\n ) : (\n <NodeEditDialog node={selectedNode} isOpen={showNodeDialog} onClose={() => setShowNodeDialog(false)} onSave={handleSaveNode} onDelete={handleDeleteNode} />\n )}\n {process.env.NEXT_PUBLIC_WORKFLOW_CRUDFORM_ENABLED === 'true' ? (\n <EdgeEditDialogCrudForm edge={selectedEdge} isOpen={showEdgeDialog} onClose={() => setShowEdgeDialog(false)} onSave={handleSaveEdge} onDelete={handleDeleteEdge} />\n ) : (\n <EdgeEditDialog edge={selectedEdge} isOpen={showEdgeDialog} onClose={() => setShowEdgeDialog(false)} onSave={handleSaveEdge} onDelete={handleDeleteEdge} />\n )}\n <Dialog open={showClearConfirm} onOpenChange={setShowClearConfirm}>\n <DialogContent className=\"sm:max-w-md\">\n <DialogHeader>\n <DialogTitle>{t('workflows.visualEditor.clearTitle')}</DialogTitle>\n <DialogDescription>{t('workflows.visualEditor.clearDescription')}</DialogDescription>\n </DialogHeader>\n <DialogFooter>\n <Button variant=\"outline\" onClick={() => setShowClearConfirm(false)}>{t('common.cancel', 'Cancel')}</Button>\n <Button variant=\"destructive\" onClick={confirmClear}>{t('common.clear', 'Clear')}</Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </>\n )\n\n if (isMobile) {\n return (\n <Page className=\"flex h-[100svh] flex-col space-y-0 overflow-hidden\">\n <MobileVisualEditor\n definitionId={definitionId}\n isSaving={isSaving}\n nodes={nodes}\n edges={edges}\n onNodesChange={handleNodesChange}\n onEdgesChange={handleEdgesChange}\n onNodeClick={handleNodeClick}\n onEdgeClick={handleEdgeClick}\n onConnect={handleConnect}\n onAddNode={handleAddNode}\n onSave={handleSave}\n onValidate={handleValidate}\n onTest={handleTest}\n onLoadExample={handleLoadExample}\n onClear={handleClear}\n metadata={metadata}\n metadataHandlers={metadataHandlers}\n />\n {sharedDialogs}\n </Page>\n )\n }\n\n return (\n <Page className=\"space-y-0 overflow-x-hidden\">\n {/* Page Header */}\n <div className=\"shrink-0 border-b border-border bg-background px-3 py-2 md:px-6 md:py-3\">\n <FormHeader\n mode=\"detail\"\n backHref=\"/backend/definitions\"\n backLabel={t('workflows.definitions.backToList', 'Back to definitions')}\n title={definitionId ? (workflowName || t('workflows.definitions.singular')) : t('workflows.backend.definitions.visual_editor.title')}\n subtitle={definitionId\n ? t('workflows.definitions.detail.summary', 'Editing workflow definition')\n : t('workflows.definitions.create.summary', 'Create and edit workflow definitions visually with a drag-and-drop interface')\n }\n actionsContent={\n <div className=\"flex flex-wrap items-center justify-end gap-1 md:gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setShowMetadata(!showMetadata)}\n disabled={isSaving}\n className=\"h-8 px-2 text-xs\"\n aria-label={showMetadata ? t('workflows.visualEditor.hideMetadata') : t('workflows.visualEditor.showMetadata')}\n >\n {showMetadata ? <PanelTopClose className=\"mr-1.5 h-4 w-4\" /> : <PanelTopOpen className=\"mr-1.5 h-4 w-4\" />}\n {showMetadata ? t('workflows.visualEditor.hideMetadata') : t('workflows.visualEditor.showMetadata')}\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleLoadExample}\n disabled={isSaving}\n className=\"h-8 text-xs\"\n >\n {t('workflows.visualEditor.loadExample')}\n </Button>\n <Button\n variant=\"destructive\"\n size=\"sm\"\n onClick={handleClear}\n disabled={isSaving}\n className=\"h-8 px-2 text-xs\"\n aria-label={t('workflows.visualEditor.clear')}\n >\n <Trash2 className=\"mr-1.5 h-4 w-4\" />\n {t('workflows.visualEditor.clear')}\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleValidate}\n disabled={isSaving}\n className=\"h-8 px-2 text-xs\"\n aria-label={t('workflows.visualEditor.validate')}\n >\n <CircleQuestionMark className=\"mr-1.5 h-4 w-4\" />\n {t('workflows.visualEditor.validate')}\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleTest}\n disabled={isSaving}\n className=\"h-8 text-xs\"\n >\n <Play className=\"mr-1.5 h-4 w-4\" />\n {t('workflows.visualEditor.runTest')}\n </Button>\n <Button\n size=\"sm\"\n onClick={handleSave}\n disabled={isSaving}\n className=\"h-8 px-2 text-xs md:px-3\"\n aria-label={isSaving ? t('workflows.mobile.saving') : definitionId ? t('workflows.common.update') : t('workflows.common.save')}\n >\n <Save className=\"mr-1.5 h-4 w-4\" />\n {isSaving ? t('workflows.mobile.saving') : definitionId ? t('workflows.common.update') : t('workflows.common.save')}\n </Button>\n </div>\n }\n />\n </div>\n\n {/* Workflow Metadata Form */}\n {showMetadata && (\n <div className={isCompactViewport\n ? 'shrink-0 border-b border-border bg-background px-3 py-2 max-h-[60svh] overflow-y-auto overscroll-contain md:px-6 md:py-3'\n : 'shrink-0 border-b border-border bg-background px-3 py-2 md:px-6 md:py-3'\n }>\n <div className=\"rounded-lg border bg-card p-3 md:p-4\">\n <h2 className=\"mb-3 text-xs font-semibold uppercase text-muted-foreground\">{t('workflows.visualEditor.workflowMetadata')}</h2>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3 md:gap-4\">\n {/* Workflow ID */}\n <div className=\"min-w-0 space-y-1\">\n <Label htmlFor=\"workflowId\" className=\"text-xs\">Workflow ID *</Label>\n <Input\n id=\"workflowId\"\n value={workflowId}\n onChange={(e) => setWorkflowId(e.target.value)}\n placeholder=\"checkout_workflow\"\n disabled={!!definitionId}\n className=\"h-8 text-sm\"\n />\n {definitionId && <p className=\"text-[10px] text-muted-foreground\">Read-only</p>}\n </div>\n\n {/* Workflow Name */}\n <div className=\"min-w-0 space-y-1\">\n <Label htmlFor=\"workflowName\" className=\"text-xs\">Name *</Label>\n <Input\n id=\"workflowName\"\n value={workflowName}\n onChange={(e) => setWorkflowName(e.target.value)}\n placeholder=\"Checkout Process\"\n className=\"h-8 text-sm\"\n />\n </div>\n\n {/* Category */}\n <div className=\"min-w-0 space-y-1\">\n <Label htmlFor=\"category\" className=\"text-xs\">Category</Label>\n <Input\n id=\"category\"\n value={category}\n onChange={(e) => setCategory(e.target.value)}\n placeholder=\"E-Commerce\"\n className=\"h-8 text-sm\"\n />\n </div>\n\n {/* Description */}\n <div className=\"min-w-0 space-y-1 sm:col-span-2 lg:col-span-3\">\n <Label htmlFor=\"description\" className=\"text-xs\">Description</Label>\n <Textarea\n id=\"description\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Describe the purpose of this workflow...\"\n rows={2}\n className=\"min-h-[60px] text-sm\"\n />\n </div>\n\n {/* Version */}\n <div className=\"min-w-0 space-y-1\">\n <Label htmlFor=\"version\" className=\"text-xs\">Version *</Label>\n <Input\n id=\"version\"\n type=\"number\"\n value={version}\n onChange={(e) => setVersion(parseInt(e.target.value) || 1)}\n min={1}\n disabled={!!definitionId}\n className=\"h-8 text-sm\"\n />\n </div>\n\n {/* Enabled */}\n <div className=\"min-w-0 space-y-1\">\n <Label className=\"text-xs\">{t('common.enabled', 'Enabled')}</Label>\n <div className=\"flex h-8 items-center gap-2\">\n <Switch\n id=\"enabled\"\n checked={enabled}\n onCheckedChange={setEnabled}\n />\n <Label htmlFor=\"enabled\" className=\"cursor-pointer text-xs font-normal\">\n {enabled ? t('common.on', 'On') : t('common.off', 'Off')}\n </Label>\n </div>\n </div>\n\n {/* Tags */}\n <div className=\"min-w-0 space-y-1\">\n <Label className=\"text-xs\">Tags</Label>\n <TagsInput\n value={tags}\n onChange={setTags}\n placeholder={t('workflows.form.placeholders.tags')}\n />\n </div>\n\n {/* Icon */}\n <div className=\"min-w-0 space-y-1\">\n <Label htmlFor=\"icon\" className=\"text-xs\">Icon</Label>\n <Input\n id=\"icon\"\n value={icon}\n onChange={(e) => setIcon(e.target.value)}\n placeholder=\"ShoppingCart\"\n className=\"h-8 text-sm\"\n />\n </div>\n\n <div className=\"min-w-0 space-y-1\">\n <Label htmlFor=\"effectiveFrom\" className=\"text-xs\">Effective From</Label>\n <Input\n id=\"effectiveFrom\"\n type=\"date\"\n value={effectiveFrom}\n onChange={(e) => setEffectiveFrom(e.target.value)}\n className=\"h-8 text-sm\"\n />\n </div>\n\n <div className=\"min-w-0 space-y-1\">\n <Label htmlFor=\"effectiveTo\" className=\"text-xs\">Effective To</Label>\n <Input\n id=\"effectiveTo\"\n type=\"date\"\n value={effectiveTo}\n onChange={(e) => setEffectiveTo(e.target.value)}\n className=\"h-8 text-sm\"\n />\n </div>\n </div>\n </div>\n\n {/* Event Triggers */}\n <DefinitionTriggersEditor\n value={triggers}\n onChange={setTriggers}\n className=\"mt-3\"\n />\n </div>\n )}\n\n {/* Main Content */}\n {isCompactViewport ? (\n <div className=\"px-3 py-3 md:px-6 md:py-4\">\n <div className=\"relative min-w-0\">\n <div className=\"h-[64svh] min-h-[360px] rounded-lg border bg-card\">\n <WorkflowGraph\n initialNodes={nodes}\n initialEdges={edges}\n onNodesChange={handleNodesChange}\n onEdgesChange={handleEdgesChange}\n onNodeClick={handleNodeClick}\n onEdgeClick={handleEdgeClick}\n onConnect={handleConnect}\n editable={true}\n height=\"100%\"\n />\n </div>\n\n {nodes.length === 0 && (\n <div className=\"pointer-events-none absolute inset-0 flex items-center justify-center px-4\">\n <div className=\"text-center\">\n <h2 className=\"mb-2 text-lg font-semibold text-foreground\">Start Building Your Workflow</h2>\n <p className=\"mb-4 text-sm text-muted-foreground\">Tap a step type below to add it to the canvas</p>\n <button\n onClick={handleLoadExample}\n className=\"pointer-events-auto text-sm text-primary hover:underline\"\n >\n Load an example workflow\n </button>\n </div>\n </div>\n )}\n </div>\n\n <div className=\"mt-3 rounded-lg border bg-card p-3\">\n <h2 className=\"mb-2 text-xs font-semibold uppercase text-muted-foreground\">Step Palette</h2>\n <p className=\"mb-3 text-xs text-muted-foreground\">Tap a step type to add it to the canvas</p>\n\n <div className=\"flex gap-2 overflow-x-auto pb-1\">\n {(['start', 'userTask', 'automated', 'waitForSignal', 'subWorkflow', 'end'] as const).map((nodeType) => {\n const Icon = NODE_TYPE_ICONS[nodeType]\n return (\n <button\n key={nodeType}\n onClick={() => handleAddNode(nodeType)}\n className=\"flex shrink-0 items-center gap-1 rounded-md border bg-background px-2 py-1 text-xs hover:bg-muted active:bg-muted/80\"\n >\n <Icon className=\"h-3.5 w-3.5\" />\n <span>{NODE_TYPE_LABELS[nodeType].title}</span>\n </button>\n )\n })}\n </div>\n </div>\n </div>\n ) : (\n <div className=\"flex min-h-[72svh] min-w-0 flex-1 border-t border-border\">\n {/* Left Sidebar - Step Palette */}\n <div className=\"w-[24rem] shrink-0 overflow-y-auto border-r border-border bg-background p-6\">\n <div className=\"rounded-lg border bg-card p-4\">\n <h2 className=\"mb-2 text-sm font-semibold uppercase text-muted-foreground\">Step Palette</h2>\n <p className=\"mb-4 text-xs text-muted-foreground\">\n Click a step type to add it to the canvas\n </p>\n\n <div className=\"space-y-3\">\n {/* START Step */}\n <button\n onClick={() => handleAddNode('start')}\n className=\"group relative w-full cursor-pointer rounded-xl border-2 border-border bg-background px-4 py-3 text-left transition-all hover:border-muted-foreground/30 hover:shadow-md\"\n >\n <div className={`absolute right-2 top-2 ${NODE_TYPE_COLORS.start} opacity-60 transition-opacity group-hover:opacity-100`}>\n {(() => {\n const Icon = NODE_TYPE_ICONS.start\n return <Icon className=\"h-4 w-4\" />\n })()}\n </div>\n <div className=\"text-sm font-semibold text-foreground\">{NODE_TYPE_LABELS.start.title}</div>\n <div className=\"mt-0.5 text-xs text-muted-foreground\">{NODE_TYPE_LABELS.start.description}</div>\n </button>\n\n {/* USER_TASK Step */}\n <button\n onClick={() => handleAddNode('userTask')}\n className=\"group relative w-full cursor-pointer rounded-xl border-2 border-border bg-background px-4 py-3 text-left transition-all hover:border-muted-foreground/30 hover:shadow-md\"\n >\n <div className={`absolute right-2 top-2 ${NODE_TYPE_COLORS.userTask} opacity-60 transition-opacity group-hover:opacity-100`}>\n {(() => {\n const Icon = NODE_TYPE_ICONS.userTask\n return <Icon className=\"h-4 w-4\" />\n })()}\n </div>\n <div className=\"text-sm font-semibold text-foreground\">{NODE_TYPE_LABELS.userTask.title}</div>\n <div className=\"mt-0.5 text-xs text-muted-foreground\">{NODE_TYPE_LABELS.userTask.description}</div>\n </button>\n\n {/* AUTOMATED Step */}\n <button\n onClick={() => handleAddNode('automated')}\n className=\"group relative w-full cursor-pointer rounded-xl border-2 border-border bg-background px-4 py-3 text-left transition-all hover:border-muted-foreground/30 hover:shadow-md\"\n >\n <div className={`absolute right-2 top-2 ${NODE_TYPE_COLORS.automated} opacity-60 transition-opacity group-hover:opacity-100`}>\n {(() => {\n const Icon = NODE_TYPE_ICONS.automated\n return <Icon className=\"h-4 w-4\" />\n })()}\n </div>\n <div className=\"text-sm font-semibold text-foreground\">{NODE_TYPE_LABELS.automated.title}</div>\n <div className=\"mt-0.5 text-xs text-muted-foreground\">{NODE_TYPE_LABELS.automated.description}</div>\n </button>\n\n {/* WAIT_FOR_SIGNAL Step */}\n <button\n onClick={() => handleAddNode('waitForSignal')}\n className=\"group relative w-full cursor-pointer rounded-xl border-2 border-border bg-background px-4 py-3 text-left transition-all hover:border-muted-foreground/30 hover:shadow-md\"\n >\n <div className={`absolute right-2 top-2 ${NODE_TYPE_COLORS.waitForSignal} opacity-60 transition-opacity group-hover:opacity-100`}>\n {(() => {\n const Icon = NODE_TYPE_ICONS.waitForSignal\n return <Icon className=\"h-4 w-4\" />\n })()}\n </div>\n <div className=\"text-sm font-semibold text-foreground\">{NODE_TYPE_LABELS.waitForSignal.title}</div>\n <div className=\"mt-0.5 text-xs text-muted-foreground\">{NODE_TYPE_LABELS.waitForSignal.description}</div>\n </button>\n\n {/* SUB_WORKFLOW Step */}\n <button\n onClick={() => handleAddNode('subWorkflow')}\n className=\"group relative w-full cursor-pointer rounded-xl border-2 border-border bg-background px-4 py-3 text-left transition-all hover:border-muted-foreground/30 hover:shadow-md\"\n >\n <div className={`absolute right-2 top-2 ${NODE_TYPE_COLORS.subWorkflow} opacity-60 transition-opacity group-hover:opacity-100`}>\n {(() => {\n const Icon = NODE_TYPE_ICONS.subWorkflow\n return <Icon className=\"h-4 w-4\" />\n })()}\n </div>\n <div className=\"text-sm font-semibold text-foreground\">{NODE_TYPE_LABELS.subWorkflow.title}</div>\n <div className=\"mt-0.5 text-xs text-muted-foreground\">{NODE_TYPE_LABELS.subWorkflow.description}</div>\n </button>\n\n {/* END Step */}\n <button\n onClick={() => handleAddNode('end')}\n className=\"group relative w-full cursor-pointer rounded-xl border-2 border-border bg-background px-4 py-3 text-left transition-all hover:border-muted-foreground/30 hover:shadow-md\"\n >\n <div className={`absolute right-2 top-2 ${NODE_TYPE_COLORS.end} opacity-60 transition-opacity group-hover:opacity-100`}>\n {(() => {\n const Icon = NODE_TYPE_ICONS.end\n return <Icon className=\"h-4 w-4\" />\n })()}\n </div>\n <div className=\"text-sm font-semibold text-foreground\">{NODE_TYPE_LABELS.end.title}</div>\n <div className=\"mt-0.5 text-xs text-muted-foreground\">{NODE_TYPE_LABELS.end.description}</div>\n </button>\n </div>\n\n {/* Instructions */}\n <Alert variant=\"info\" className=\"mt-6\">\n <Info className=\"size-4\" />\n <AlertTitle className=\"text-xs\">{t('workflows.visualEditor.howToUse', 'How to use:')}</AlertTitle>\n <div className=\"mt-2\">\n <ul className=\"list-inside list-disc space-y-1 text-xs\">\n <li>{t('workflows.visualEditor.hint.addSteps', 'Click step types to add them')}</li>\n <li>{t('workflows.visualEditor.hint.dragSteps', 'Drag steps to position them')}</li>\n <li>{t('workflows.visualEditor.hint.connectSteps', 'Connect steps by dragging from handles')}</li>\n <li>{t('workflows.visualEditor.hint.editSteps', 'Click steps and transitions to edit them')}</li>\n <li>{t('workflows.visualEditor.hint.validate', 'Validate before saving')}</li>\n </ul>\n </div>\n </Alert>\n </div>\n </div>\n\n {/* Main Canvas */}\n <div className=\"min-w-0 flex-1 p-6\">\n <div className=\"relative h-[72svh] min-h-[640px]\">\n <div className=\"h-full rounded-lg border bg-card\">\n <WorkflowGraph\n initialNodes={nodes}\n initialEdges={edges}\n onNodesChange={handleNodesChange}\n onEdgesChange={handleEdgesChange}\n onNodeClick={handleNodeClick}\n onEdgeClick={handleEdgeClick}\n onConnect={handleConnect}\n editable={true}\n height=\"100%\"\n />\n </div>\n\n {/* Empty State */}\n {nodes.length === 0 && (\n <div className=\"pointer-events-none absolute inset-0 flex items-center justify-center px-4\">\n <div className=\"text-center\">\n <h2 className=\"mb-2 text-xl font-semibold text-foreground\">\n Start Building Your Workflow\n </h2>\n <p className=\"mb-4 text-muted-foreground\">\n Click a step type from the palette to add it to the canvas\n </p>\n <button\n onClick={handleLoadExample}\n className=\"pointer-events-auto text-sm text-primary hover:underline\"\n >\n Load an example workflow\n </button>\n </div>\n </div>\n )}\n </div>\n </div>\n </div>\n )}\n {sharedDialogs}\n </Page>\n )\n}\n\n// Helper functions\nfunction getDefaultLabel(nodeType: string): string {\n const labels: Record<string, string> = {\n start: 'Start',\n end: 'End',\n userTask: 'New User Task',\n automated: 'New Automated Task',\n decision: 'Decision Point',\n waitForSignal: 'Wait for Signal',\n }\n return labels[nodeType] || 'New Step'\n}\n\nfunction getDefaultBadge(nodeType: string): string {\n const badges: Record<string, string> = {\n start: 'Start',\n end: 'End',\n userTask: 'User Task',\n automated: 'Automated',\n decision: 'Decision',\n waitForSignal: 'Wait for Signal',\n }\n return badges[nodeType] || 'Task'\n}\n\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["metadata"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.4.5-develop-
|
|
3
|
+
"version": "0.4.5-develop-5191db4ef3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -207,7 +207,7 @@
|
|
|
207
207
|
}
|
|
208
208
|
},
|
|
209
209
|
"dependencies": {
|
|
210
|
-
"@open-mercato/shared": "0.4.5-develop-
|
|
210
|
+
"@open-mercato/shared": "0.4.5-develop-5191db4ef3",
|
|
211
211
|
"@types/semver": "^7.5.8",
|
|
212
212
|
"@xyflow/react": "^12.6.0",
|
|
213
213
|
"ai": "^6.0.0",
|
|
@@ -26,12 +26,16 @@
|
|
|
26
26
|
"attachments.library.metadata.assignments.title": "Zuordnungen",
|
|
27
27
|
"attachments.library.metadata.assignments.type": "Typ",
|
|
28
28
|
"attachments.library.metadata.cancel": "Abbrechen",
|
|
29
|
+
"attachments.library.metadata.details": "Details",
|
|
29
30
|
"attachments.library.metadata.download": "Herunterladen",
|
|
30
31
|
"attachments.library.metadata.error": "Metadaten konnten nicht aktualisiert werden.",
|
|
31
32
|
"attachments.library.metadata.extractedTitle": "Extrahierter Text",
|
|
33
|
+
"attachments.library.metadata.loadError": "Anhangsmetadaten konnten nicht geladen werden.",
|
|
34
|
+
"attachments.library.metadata.loading": "Metadaten werden geladen…",
|
|
32
35
|
"attachments.library.metadata.noContent": "Kein Text extrahiert",
|
|
33
36
|
"attachments.library.metadata.noSelection": "Wählen Sie einen Anhang zum Bearbeiten aus.",
|
|
34
37
|
"attachments.library.metadata.preview": "Vorschau",
|
|
38
|
+
"attachments.library.metadata.previewUnavailable": "Vorschau ist für diesen Dateityp nicht verfügbar.",
|
|
35
39
|
"attachments.library.metadata.resizeTool.copied": "Bild-URL kopiert.",
|
|
36
40
|
"attachments.library.metadata.resizeTool.copy": "URL kopieren",
|
|
37
41
|
"attachments.library.metadata.resizeTool.copyError": "URL konnte nicht kopiert werden.",
|
|
@@ -26,12 +26,16 @@
|
|
|
26
26
|
"attachments.library.metadata.assignments.title": "Assignments",
|
|
27
27
|
"attachments.library.metadata.assignments.type": "Type",
|
|
28
28
|
"attachments.library.metadata.cancel": "Cancel",
|
|
29
|
+
"attachments.library.metadata.details": "Details",
|
|
29
30
|
"attachments.library.metadata.download": "Download",
|
|
30
31
|
"attachments.library.metadata.error": "Failed to update metadata.",
|
|
31
32
|
"attachments.library.metadata.extractedTitle": "Extracted text",
|
|
33
|
+
"attachments.library.metadata.loadError": "Failed to load attachment metadata.",
|
|
34
|
+
"attachments.library.metadata.loading": "Loading metadata…",
|
|
32
35
|
"attachments.library.metadata.noContent": "No text extracted",
|
|
33
36
|
"attachments.library.metadata.noSelection": "Select an attachment to edit.",
|
|
34
37
|
"attachments.library.metadata.preview": "Preview",
|
|
38
|
+
"attachments.library.metadata.previewUnavailable": "Preview is not available for this file type.",
|
|
35
39
|
"attachments.library.metadata.resizeTool.copied": "Image URL copied.",
|
|
36
40
|
"attachments.library.metadata.resizeTool.copy": "Copy URL",
|
|
37
41
|
"attachments.library.metadata.resizeTool.copyError": "Unable to copy URL.",
|
|
@@ -26,12 +26,16 @@
|
|
|
26
26
|
"attachments.library.metadata.assignments.title": "Asignaciones",
|
|
27
27
|
"attachments.library.metadata.assignments.type": "Tipo",
|
|
28
28
|
"attachments.library.metadata.cancel": "Cancelar",
|
|
29
|
+
"attachments.library.metadata.details": "Detalles",
|
|
29
30
|
"attachments.library.metadata.download": "Descargar",
|
|
30
31
|
"attachments.library.metadata.error": "No se pudieron actualizar los metadatos.",
|
|
31
32
|
"attachments.library.metadata.extractedTitle": "Texto extraído",
|
|
33
|
+
"attachments.library.metadata.loadError": "Error al cargar los metadatos del adjunto.",
|
|
34
|
+
"attachments.library.metadata.loading": "Cargando metadatos…",
|
|
32
35
|
"attachments.library.metadata.noContent": "No se extrajo texto",
|
|
33
36
|
"attachments.library.metadata.noSelection": "Seleccione un archivo adjunto para editar.",
|
|
34
37
|
"attachments.library.metadata.preview": "Vista previa",
|
|
38
|
+
"attachments.library.metadata.previewUnavailable": "La vista previa no está disponible para este tipo de archivo.",
|
|
35
39
|
"attachments.library.metadata.resizeTool.copied": "URL de imagen copiada.",
|
|
36
40
|
"attachments.library.metadata.resizeTool.copy": "Copiar URL",
|
|
37
41
|
"attachments.library.metadata.resizeTool.copyError": "No se pudo copiar la URL.",
|
|
@@ -26,12 +26,16 @@
|
|
|
26
26
|
"attachments.library.metadata.assignments.title": "Przypisania",
|
|
27
27
|
"attachments.library.metadata.assignments.type": "Typ",
|
|
28
28
|
"attachments.library.metadata.cancel": "Anuluj",
|
|
29
|
+
"attachments.library.metadata.details": "Szczegóły",
|
|
29
30
|
"attachments.library.metadata.download": "Pobierz",
|
|
30
31
|
"attachments.library.metadata.error": "Nie udało się zaktualizować metadanych.",
|
|
31
32
|
"attachments.library.metadata.extractedTitle": "Wyodrębniony tekst",
|
|
33
|
+
"attachments.library.metadata.loadError": "Nie udało się załadować metadanych załącznika.",
|
|
34
|
+
"attachments.library.metadata.loading": "Ładowanie metadanych…",
|
|
32
35
|
"attachments.library.metadata.noContent": "Brak wyodrębnionego tekstu",
|
|
33
36
|
"attachments.library.metadata.noSelection": "Wybierz załącznik do edycji.",
|
|
34
37
|
"attachments.library.metadata.preview": "Podgląd",
|
|
38
|
+
"attachments.library.metadata.previewUnavailable": "Podgląd nie jest dostępny dla tego typu pliku.",
|
|
35
39
|
"attachments.library.metadata.resizeTool.copied": "URL obrazu skopiowany.",
|
|
36
40
|
"attachments.library.metadata.resizeTool.copy": "Kopiuj URL",
|
|
37
41
|
"attachments.library.metadata.resizeTool.copyError": "Nie można skopiować URL.",
|
|
@@ -4,6 +4,7 @@ import { Button } from '@open-mercato/ui/primitives/button'
|
|
|
4
4
|
import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
|
|
5
5
|
import Link from 'next/link'
|
|
6
6
|
import { hasFeature, matchFeature } from '@open-mercato/shared/security/features'
|
|
7
|
+
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
7
8
|
|
|
8
9
|
function toTitleCase(value: string): string {
|
|
9
10
|
return value.replace(/[-_.]/g, ' ').replace(/\b\w/g, (char) => char.toUpperCase())
|
|
@@ -112,6 +113,7 @@ export function AclEditor({
|
|
|
112
113
|
const actorIsSuperAdmin = !!currentUserIsSuperAdmin
|
|
113
114
|
const [loading, setLoading] = React.useState(true)
|
|
114
115
|
const [features, setFeatures] = React.useState<Feature[]>([])
|
|
116
|
+
const t = useT()
|
|
115
117
|
const [modules, setModules] = React.useState<ModuleInfo[]>([])
|
|
116
118
|
const [granted, setGranted] = React.useState<string[]>(() => {
|
|
117
119
|
const normalized = normalizeFeatureArray(value?.features)
|
|
@@ -497,11 +499,11 @@ export function AclEditor({
|
|
|
497
499
|
})}
|
|
498
500
|
</div>
|
|
499
501
|
<div className="mt-2">
|
|
500
|
-
<Button variant="outline" onClick={() => setOrganizations(null)}>Allow all organizations</Button>
|
|
502
|
+
<Button variant="outline" onClick={() => setOrganizations(null)}>{t('auth.acl.allowAllOrganizations', 'Allow all organizations')}</Button>
|
|
501
503
|
</div>
|
|
502
504
|
{showOrganizationWarning && (
|
|
503
505
|
<div className="mt-3 rounded border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-900">
|
|
504
|
-
Organization restrictions are saved only when at least one feature override is selected. Add a feature or enable a module wildcard before saving.
|
|
506
|
+
{t('auth.acl.organizationWarning', 'Organization restrictions are saved only when at least one feature override is selected. Add a feature or enable a module wildcard before saving.')}
|
|
505
507
|
</div>
|
|
506
508
|
)}
|
|
507
509
|
</div>
|
|
@@ -21,7 +21,7 @@ export default function ResetPage() {
|
|
|
21
21
|
const res = await fetch('/api/auth/reset', { method: 'POST', body: form })
|
|
22
22
|
if (!res.ok) {
|
|
23
23
|
const data = await res.json().catch(() => null)
|
|
24
|
-
setError(data?.error || 'Something went wrong')
|
|
24
|
+
setError(data?.error || t('auth.reset.error', 'Something went wrong'))
|
|
25
25
|
return
|
|
26
26
|
}
|
|
27
27
|
setSent(true)
|
|
@@ -35,12 +35,12 @@ export default function ResetPage() {
|
|
|
35
35
|
<Card className="w-full max-w-sm">
|
|
36
36
|
<CardHeader>
|
|
37
37
|
<CardTitle>{t('auth.resetPassword')}</CardTitle>
|
|
38
|
-
<CardDescription>Enter your email to receive reset link</CardDescription>
|
|
38
|
+
<CardDescription>{t('auth.reset.description', 'Enter your email to receive reset link')}</CardDescription>
|
|
39
39
|
</CardHeader>
|
|
40
40
|
<CardContent>
|
|
41
41
|
{sent ? (
|
|
42
42
|
<div className="text-sm text-muted-foreground">
|
|
43
|
-
If an account with that email exists, we sent a reset link. Please check your inbox.
|
|
43
|
+
{t('auth.reset.sent', 'If an account with that email exists, we sent a reset link. Please check your inbox.')}
|
|
44
44
|
</div>
|
|
45
45
|
) : (
|
|
46
46
|
<form className="grid gap-3" onSubmit={onSubmit} noValidate>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
+
"auth.acl.allowAllOrganizations": "Alle Organisationen zulassen",
|
|
3
|
+
"auth.acl.organizationWarning": "Organisationseinschränkungen werden nur gespeichert, wenn mindestens eine Berechtigungsüberschreibung ausgewählt ist. Füge eine Berechtigung hinzu oder aktiviere einen Modul-Wildcard vor dem Speichern.",
|
|
2
4
|
"auth.actions.contactSupport": "Support kontaktieren",
|
|
3
5
|
"auth.actions.viewPermissions": "Berechtigungen anzeigen",
|
|
4
6
|
"auth.actions.viewSessions": "Sitzungen anzeigen",
|
|
@@ -73,7 +75,10 @@
|
|
|
73
75
|
"auth.profile.form.success": "Profil aktualisiert.",
|
|
74
76
|
"auth.profile.subtitle": "Passwort ändern",
|
|
75
77
|
"auth.profile.title": "Profil",
|
|
78
|
+
"auth.reset.description": "Gib deine E-Mail-Adresse ein, um einen Zurücksetzungslink zu erhalten",
|
|
79
|
+
"auth.reset.error": "Etwas ist schiefgelaufen",
|
|
76
80
|
"auth.reset.errors.failed": "Passwort konnte nicht zurückgesetzt werden",
|
|
81
|
+
"auth.reset.sent": "Falls ein Konto mit dieser E-Mail-Adresse existiert, haben wir einen Zurücksetzungslink gesendet. Überprüfe deinen Posteingang.",
|
|
77
82
|
"auth.reset.form.loading": "...",
|
|
78
83
|
"auth.reset.form.password": "Neues Passwort",
|
|
79
84
|
"auth.reset.form.submit": "Passwort aktualisieren",
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
+
"auth.acl.allowAllOrganizations": "Allow all organizations",
|
|
3
|
+
"auth.acl.organizationWarning": "Organization restrictions are saved only when at least one feature override is selected. Add a feature or enable a module wildcard before saving.",
|
|
2
4
|
"auth.actions.contactSupport": "Contact Support",
|
|
3
5
|
"auth.actions.viewPermissions": "View Permissions",
|
|
4
6
|
"auth.actions.viewSessions": "View Sessions",
|
|
@@ -73,7 +75,10 @@
|
|
|
73
75
|
"auth.profile.form.success": "Profile updated.",
|
|
74
76
|
"auth.profile.subtitle": "Change password",
|
|
75
77
|
"auth.profile.title": "Profile",
|
|
78
|
+
"auth.reset.description": "Enter your email to receive reset link",
|
|
79
|
+
"auth.reset.error": "Something went wrong",
|
|
76
80
|
"auth.reset.errors.failed": "Unable to reset password",
|
|
81
|
+
"auth.reset.sent": "If an account with that email exists, we sent a reset link. Please check your inbox.",
|
|
77
82
|
"auth.reset.form.loading": "...",
|
|
78
83
|
"auth.reset.form.password": "New password",
|
|
79
84
|
"auth.reset.form.submit": "Update password",
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
+
"auth.acl.allowAllOrganizations": "Permitir todas las organizaciones",
|
|
3
|
+
"auth.acl.organizationWarning": "Las restricciones de organización se guardan solo cuando se selecciona al menos una anulación de función. Agrega una función o habilita un comodín de módulo antes de guardar.",
|
|
2
4
|
"auth.actions.contactSupport": "Contactar soporte",
|
|
3
5
|
"auth.actions.viewPermissions": "Ver permisos",
|
|
4
6
|
"auth.actions.viewSessions": "Ver sesiones",
|
|
@@ -73,7 +75,10 @@
|
|
|
73
75
|
"auth.profile.form.success": "Perfil actualizado.",
|
|
74
76
|
"auth.profile.subtitle": "Cambiar contraseña",
|
|
75
77
|
"auth.profile.title": "Perfil",
|
|
78
|
+
"auth.reset.description": "Ingresa tu correo para recibir un enlace de restablecimiento",
|
|
79
|
+
"auth.reset.error": "Algo salió mal",
|
|
76
80
|
"auth.reset.errors.failed": "No se pudo restablecer la contraseña",
|
|
81
|
+
"auth.reset.sent": "Si existe una cuenta con ese correo, enviamos un enlace de restablecimiento. Revisa tu bandeja de entrada.",
|
|
77
82
|
"auth.reset.form.loading": "...",
|
|
78
83
|
"auth.reset.form.password": "Nueva contraseña",
|
|
79
84
|
"auth.reset.form.submit": "Actualizar contraseña",
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
+
"auth.acl.allowAllOrganizations": "Zezwól na wszystkie organizacje",
|
|
3
|
+
"auth.acl.organizationWarning": "Ograniczenia organizacyjne są zapisywane tylko wtedy, gdy wybrano co najmniej jedno nadpisanie uprawnień. Dodaj uprawnienie lub włącz wildcard modułu przed zapisaniem.",
|
|
2
4
|
"auth.actions.contactSupport": "Skontaktuj się z pomocą",
|
|
3
5
|
"auth.actions.viewPermissions": "Zobacz uprawnienia",
|
|
4
6
|
"auth.actions.viewSessions": "Zobacz sesje",
|
|
@@ -73,7 +75,10 @@
|
|
|
73
75
|
"auth.profile.form.success": "Profil zaktualizowany.",
|
|
74
76
|
"auth.profile.subtitle": "Zmiana hasła",
|
|
75
77
|
"auth.profile.title": "Profil",
|
|
78
|
+
"auth.reset.description": "Podaj swój adres e-mail, aby otrzymać link do resetowania",
|
|
79
|
+
"auth.reset.error": "Coś poszło nie tak",
|
|
76
80
|
"auth.reset.errors.failed": "Nie udało się zresetować hasła",
|
|
81
|
+
"auth.reset.sent": "Jeśli konto z tym adresem e-mail istnieje, wysłaliśmy link do resetowania. Sprawdź swoją skrzynkę odbiorczą.",
|
|
77
82
|
"auth.reset.form.loading": "...",
|
|
78
83
|
"auth.reset.form.password": "Nowe hasło",
|
|
79
84
|
"auth.reset.form.submit": "Zaktualizuj hasło",
|
|
@@ -1,6 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"audit_logs.resource_kind.catalog.price": "Preis",
|
|
3
3
|
"audit_logs.resource_kind.catalog.variant": "Variante",
|
|
4
|
+
"catalog.audit.categories.create": "Kategorie erstellen",
|
|
5
|
+
"catalog.audit.categories.delete": "Kategorie löschen",
|
|
6
|
+
"catalog.audit.categories.update": "Kategorie aktualisieren",
|
|
7
|
+
"catalog.audit.offers.create": "Angebot erstellen",
|
|
8
|
+
"catalog.audit.offers.delete": "Angebot löschen",
|
|
9
|
+
"catalog.audit.offers.update": "Angebot aktualisieren",
|
|
10
|
+
"catalog.audit.optionSchemas.create": "Optionsschema erstellen",
|
|
11
|
+
"catalog.audit.optionSchemas.delete": "Optionsschema löschen",
|
|
12
|
+
"catalog.audit.optionSchemas.update": "Optionsschema aktualisieren",
|
|
13
|
+
"catalog.audit.priceKinds.create": "Preisart erstellen",
|
|
14
|
+
"catalog.audit.priceKinds.delete": "Preisart löschen",
|
|
15
|
+
"catalog.audit.priceKinds.update": "Preisart aktualisieren",
|
|
16
|
+
"catalog.audit.prices.create": "Preis erstellen",
|
|
17
|
+
"catalog.audit.prices.delete": "Preis löschen",
|
|
18
|
+
"catalog.audit.prices.update": "Preis aktualisieren",
|
|
19
|
+
"catalog.audit.products.create": "Produkt erstellen",
|
|
20
|
+
"catalog.audit.products.delete": "Produkt löschen",
|
|
21
|
+
"catalog.audit.products.update": "Produkt aktualisieren",
|
|
22
|
+
"catalog.audit.variants.create": "Variante erstellen",
|
|
23
|
+
"catalog.audit.variants.delete": "Variante löschen",
|
|
24
|
+
"catalog.audit.variants.update": "Variante aktualisieren",
|
|
4
25
|
"catalog.categories.flash.created": "Kategorie erstellt",
|
|
5
26
|
"catalog.categories.flash.deleted": "Kategorie archiviert",
|
|
6
27
|
"catalog.categories.flash.updated": "Kategorie aktualisiert",
|