UNPKG

@bernierllc/generic-workflow-ui

Version:

Generic, reusable workflow UI components with linear and graph visualization

161 lines (159 loc) 8.74 kB
"use strict"; /* Copyright (c) 2025 Bernier LLC This file is licensed to the client under a limited-use license. The client may use and modify this code *only within the scope of the project it was delivered for*. Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC. */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.GenericWorkflowBuilderV2 = GenericWorkflowBuilderV2; const react_1 = __importStar(require("react")); const tamagui_1 = require("tamagui"); const react_2 = require("@xyflow/react"); const workflow_converter_1 = require("../json/workflow-converter"); const GenericWorkflowCanvas_1 = require("../canvas/GenericWorkflowCanvas"); const GenericWorkflowStepper_1 = require("../components/GenericWorkflowStepper"); // ============================================================================ // COMPONENT // ============================================================================ /** * Enhanced workflow builder with linear and graph visualization modes */ function GenericWorkflowBuilderV2({ initialWorkflow, initialMode = 'linear', config = {}, onSave, onWorkflowChange, readOnly = false, }) { const { allowJSONImport = true, allowJSONExport = true, showJSONView = true, allowModeToggle = true, canvasConfig = {}, } = config; // Initialize workflow const [workflow, setWorkflow] = (0, react_1.useState)(() => { if (!initialWorkflow) { return { id: `workflow-${Date.now()}`, name: 'New Workflow', stages: [], transitions: [], }; } return initialWorkflow; }); // Mode state const [mode, setMode] = (0, react_1.useState)(initialMode); // JSON view state const [showJSON, setShowJSON] = (0, react_1.useState)(false); // Current stage for visualization const [currentStageId, setCurrentStageId] = (0, react_1.useState)(workflow.stages[0]?.id); // Handle workflow change const handleWorkflowChange = (0, react_1.useCallback)((updatedWorkflow) => { setWorkflow(updatedWorkflow); if (onWorkflowChange) { onWorkflowChange(updatedWorkflow); } }, [onWorkflowChange]); // Handle save const handleSave = (0, react_1.useCallback)(() => { const json = (0, workflow_converter_1.workflowToJSON)(workflow); if (onSave) { onSave({ generic: workflow, json }); } }, [workflow, onSave]); // Handle export const handleExport = (0, react_1.useCallback)(() => { const json = (0, workflow_converter_1.workflowToJSON)(workflow); const blob = new Blob([JSON.stringify(json, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `${workflow.name}.json`; a.click(); URL.revokeObjectURL(url); }, [workflow]); // Handle import const handleImport = (0, react_1.useCallback)(() => { const input = document.createElement('input'); input.type = 'file'; input.accept = 'application/json'; input.onchange = (e) => { const file = e.target.files?.[0]; if (!file) return; const reader = new FileReader(); reader.onload = (event) => { try { const json = JSON.parse(event.target?.result); const importedWorkflow = (0, workflow_converter_1.jsonToWorkflow)(json); setWorkflow(importedWorkflow); if (onWorkflowChange) { onWorkflowChange(importedWorkflow); } } catch (error) { // Handle import error silently or show user feedback if (error instanceof Error) { // Could show toast notification here } } }; reader.readAsText(file); }; input.click(); }, [onWorkflowChange]); return (react_1.default.createElement(tamagui_1.Card, { padding: "$4", elevate: true }, react_1.default.createElement(tamagui_1.YStack, { gap: "$4" }, react_1.default.createElement(tamagui_1.XStack, { justifyContent: "space-between", alignItems: "center" }, react_1.default.createElement(tamagui_1.Text, { fontSize: "$6", fontWeight: "bold" }, "Workflow Builder"), react_1.default.createElement(tamagui_1.XStack, { gap: "$2" }, allowModeToggle && (react_1.default.createElement(tamagui_1.XStack, { gap: "$2", borderWidth: 1, borderColor: "$borderColor", borderRadius: "$2", padding: "$1" }, react_1.default.createElement(tamagui_1.Button, { size: "$3", variant: mode === 'linear' ? 'outlined' : 'ghost', onPress: () => setMode('linear'), disabled: readOnly }, "Linear"), react_1.default.createElement(tamagui_1.Button, { size: "$3", variant: mode === 'graph' ? 'outlined' : 'ghost', onPress: () => setMode('graph'), disabled: readOnly }, "Graph"))), showJSONView && (react_1.default.createElement(tamagui_1.Button, { size: "$3", variant: "outlined", onPress: () => setShowJSON(!showJSON) }, showJSON ? 'Hide' : 'Show', " JSON")), allowJSONImport && (react_1.default.createElement(tamagui_1.Button, { size: "$3", variant: "outlined", onPress: handleImport, disabled: readOnly }, "Import")), allowJSONExport && (react_1.default.createElement(tamagui_1.Button, { size: "$3", variant: "outlined", onPress: handleExport }, "Export")), onSave && (react_1.default.createElement(tamagui_1.Button, { size: "$3", onPress: handleSave, disabled: readOnly }, "Save")))), mode === 'linear' ? (react_1.default.createElement(GenericWorkflowStepper_1.GenericWorkflowStepper, { workflow: workflow, currentStageId: currentStageId || '', config: { enabled: true, orientation: 'horizontal', showDescriptions: true, showIcons: false, showTimestamps: false, showUsers: false, clickableStages: !readOnly, }, onStageChange: (stageId) => setCurrentStageId(stageId) })) : (react_1.default.createElement(react_2.ReactFlowProvider, null, react_1.default.createElement(GenericWorkflowCanvas_1.GenericWorkflowCanvas, { workflow: workflow, currentStageId: currentStageId, config: canvasConfig, onWorkflowChange: handleWorkflowChange, onNodeClick: (stageId) => setCurrentStageId(stageId), readOnly: readOnly }))), showJSON && (react_1.default.createElement(tamagui_1.Card, { padding: "$4", backgroundColor: "$gray2" }, react_1.default.createElement(tamagui_1.Text, { fontFamily: "monospace", fontSize: "$2" }, react_1.default.createElement("pre", null, JSON.stringify((0, workflow_converter_1.workflowToJSON)(workflow), null, 2)))))))); } GenericWorkflowBuilderV2.displayName = 'GenericWorkflowBuilderV2'; exports.default = GenericWorkflowBuilderV2;