diff --git a/ui/package-lock.json b/ui/package-lock.json index 2f5392d09..46fccd086 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,25 +1,25 @@ { - "name": "ui", + "name": "@certimate/webui", "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "ui", - "version": "0.0.0", + "name": "@certimate/webui", "dependencies": { "@ant-design/pro-components": "^2.8.10", "@codemirror/lang-json": "^6.0.2", "@codemirror/lang-yaml": "^6.1.2", "@codemirror/language": "^6.11.2", "@codemirror/legacy-modes": "^6.5.1", - "@flowgram.ai/fixed-layout-editor": "^0.2.28", + "@flowgram.ai/document": "^0.3.2", + "@flowgram.ai/fixed-layout-editor": "^0.3.2", "@tabler/icons-react": "^3.34.1", - "@uiw/codemirror-extensions-basic-setup": "^4.24.1", - "@uiw/codemirror-theme-vscode": "^4.24.1", - "@uiw/react-codemirror": "^4.24.1", + "@uiw/codemirror-extensions-basic-setup": "^4.24.2", + "@uiw/codemirror-theme-vscode": "^4.24.2", + "@uiw/react-codemirror": "^4.24.2", "ahooks": "^3.9.0", - "antd": "^5.26.6", + "antd": "^5.26.7", "antd-zod": "^7.0.0", "clsx": "^2.1.1", "cron-parser": "^5.3.0", @@ -36,8 +36,8 @@ "react-i18next": "^15.6.1", "react-router-dom": "^7.7.1", "tailwind-merge": "^3.3.1", - "zod": "^4.0.10", - "zustand": "^5.0.6" + "zod": "^4.0.14", + "zustand": "^5.0.7" }, "devDependencies": { "@eslint/js": "^9.32.0", @@ -54,7 +54,7 @@ "eslint": "^9.32.0", "eslint-config-prettier": "^10.1.8", "eslint-import-resolver-typescript": "^4.4.4", - "eslint-plugin-better-tailwindcss": "^3.7.2", + "eslint-plugin-better-tailwindcss": "^3.7.3", "eslint-plugin-import": "^2.32.0", "eslint-plugin-prettier": "^5.5.3", "eslint-plugin-react-hooks": "^5.2.0", @@ -2784,12 +2784,12 @@ } }, "node_modules/@flowgram.ai/background-plugin": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/background-plugin/-/background-plugin-0.2.28.tgz", - "integrity": "sha512-GEH0e1TioFQuKTZli7UO0yz171xs2T2XAnoWdxGhuWTcZ3PVyJSwJSF6BPDxfWGgN3kL9JeghbCPgElhwEOKGg==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/background-plugin/-/background-plugin-0.3.2.tgz", + "integrity": "sha512-3BeVeZ3bvhqIfsSVuUpxMBdOON1eY9E+7SlAvs1iWbEgzn8LVg7i6lXdl0BIVlUEIthl7aLH7uxrbb/MAj9Fxg==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/utils": "0.3.2", "inversify": "^6.0.1", "reflect-metadata": "~0.2.2" }, @@ -2799,11 +2799,11 @@ } }, "node_modules/@flowgram.ai/command": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/command/-/command-0.2.28.tgz", - "integrity": "sha512-/OMswJnXKm6aHIjwOQfWzCeYCr19x6gA8YNY8z9BpWJa3mPpPMUKjigldvOZVq/LZ3UPLj4EtbW7u4yyfsNCgA==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/command/-/command-0.3.2.tgz", + "integrity": "sha512-P6tuALZrSzjGBAB3BttJWumtmN0NcBJ88dHGsWStMMDW81LYCFKCsybB2wU0YoGVV7viRjCe/szSoQAbp8B2NQ==", "dependencies": { - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/utils": "0.3.2", "inversify": "^6.0.1", "reflect-metadata": "~0.2.2" }, @@ -2813,12 +2813,12 @@ } }, "node_modules/@flowgram.ai/core": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/core/-/core-0.2.28.tgz", - "integrity": "sha512-iVHIGHZTjoI0OJCf2m2ch70jkopWu6P+G1wy4cYMWqWI89lz2grtAEd7Qg8vRHQameLAdoQnAHuSkAXpIIKcaA==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/core/-/core-0.3.2.tgz", + "integrity": "sha512-pb+YP2DKIrTP2woQEbt7cKWnqwXObsMtGhS0DuRgbCIN1+6fLXFjvN2M2QhMRsOPiqY60dWnZWLKtagwPVUDqA==", "dependencies": { - "@flowgram.ai/command": "0.2.28", - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/command": "0.3.2", + "@flowgram.ai/utils": "0.3.2", "@phosphor/messaging": "^1.3.0", "@tweenjs/tween.js": "^18", "clsx": "^1.1.1", @@ -2858,12 +2858,12 @@ } }, "node_modules/@flowgram.ai/document": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/document/-/document-0.2.28.tgz", - "integrity": "sha512-HzEG5EZNdtooAaGjCCd4k9cjxoUaMs0j2dowVA2/z8CO42ylqLnk+GJqr8jE+gPxS4muwjxdzEa/OXcgsrlqhw==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/document/-/document-0.3.2.tgz", + "integrity": "sha512-N+VAQzZcNt8PUfB/32cGzMFtUUiKGTzCFMFMElB9ffSWG2stHgueRO3kBWCD8yweArfUofhCTk3eERJ345dj3A==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/utils": "0.3.2", "inversify": "^6.0.1", "lodash": "^4.17.21", "nanoid": "^4.0.2", @@ -2888,29 +2888,29 @@ } }, "node_modules/@flowgram.ai/editor": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/editor/-/editor-0.2.28.tgz", - "integrity": "sha512-QMSuOfFXZHHtnjuuX/pDqoGn/iCKjD6I05wcKUn0LqqbFgyYKp49Ju77IS9rGBs6R1Cj0jqFPl3OLW50sFqLEg==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/editor/-/editor-0.3.2.tgz", + "integrity": "sha512-Vdq53nKUoHQKWtVOmMRcI3DgS8U8pW2jFQRklYfAVhmLxyw4636ZplF8F3/AiAbt5tJ7P9OOs5xI456U1U2dqQ==", "dependencies": { - "@flowgram.ai/background-plugin": "0.2.28", - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/document": "0.2.28", - "@flowgram.ai/form": "0.2.28", - "@flowgram.ai/form-core": "0.2.28", - "@flowgram.ai/group-plugin": "0.2.28", - "@flowgram.ai/history": "0.2.28", - "@flowgram.ai/history-node-plugin": "0.2.28", - "@flowgram.ai/i18n-plugin": "0.2.28", - "@flowgram.ai/materials-plugin": "0.2.28", - "@flowgram.ai/node": "0.2.28", - "@flowgram.ai/node-core-plugin": "0.2.28", - "@flowgram.ai/node-variable-plugin": "0.2.28", - "@flowgram.ai/playground-react": "0.2.28", - "@flowgram.ai/redux-devtool-plugin": "0.2.28", - "@flowgram.ai/renderer": "0.2.28", - "@flowgram.ai/shortcuts-plugin": "0.2.28", - "@flowgram.ai/utils": "0.2.28", - "@flowgram.ai/variable-plugin": "0.2.28", + "@flowgram.ai/background-plugin": "0.3.2", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/document": "0.3.2", + "@flowgram.ai/form": "0.3.2", + "@flowgram.ai/form-core": "0.3.2", + "@flowgram.ai/group-plugin": "0.3.2", + "@flowgram.ai/history": "0.3.2", + "@flowgram.ai/history-node-plugin": "0.3.2", + "@flowgram.ai/i18n-plugin": "0.3.2", + "@flowgram.ai/materials-plugin": "0.3.2", + "@flowgram.ai/node": "0.3.2", + "@flowgram.ai/node-core-plugin": "0.3.2", + "@flowgram.ai/node-variable-plugin": "0.3.2", + "@flowgram.ai/playground-react": "0.3.2", + "@flowgram.ai/redux-devtool-plugin": "0.3.2", + "@flowgram.ai/renderer": "0.3.2", + "@flowgram.ai/shortcuts-plugin": "0.3.2", + "@flowgram.ai/utils": "0.3.2", + "@flowgram.ai/variable-plugin": "0.3.2", "inversify": "^6.0.1", "reflect-metadata": "~0.2.2" }, @@ -2920,13 +2920,13 @@ } }, "node_modules/@flowgram.ai/fixed-drag-plugin": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/fixed-drag-plugin/-/fixed-drag-plugin-0.2.28.tgz", - "integrity": "sha512-dNrFBd6G1uFgkhf0LpAC9/7vV8kIQCBuBAmbeUi6EQZkmWsp9rVd4SAdKGqhNLrs6klt8n5oMltv6WJsMCRS6Q==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/fixed-drag-plugin/-/fixed-drag-plugin-0.3.2.tgz", + "integrity": "sha512-XK09rklrkU1EzhmqFBsm/zZGcnnb4LXhNMkol2fDviiq2Aq0UumXL2jRjRaWcFQJVjBawlOd3YciTamSY6xNgg==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/document": "0.2.28", - "@flowgram.ai/renderer": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/document": "0.3.2", + "@flowgram.ai/renderer": "0.3.2", "inversify": "^6.0.1", "reflect-metadata": "~0.2.2" }, @@ -2936,29 +2936,29 @@ } }, "node_modules/@flowgram.ai/fixed-history-plugin": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/fixed-history-plugin/-/fixed-history-plugin-0.2.28.tgz", - "integrity": "sha512-s9ckjS6NS3ds+FfmvTIvO/02N8rSh+EcSDyKwLaGcrYk6X6Fs1T5h/PyBgGTryJ7EzseqlLTFVBqYXzgbymDtg==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/fixed-history-plugin/-/fixed-history-plugin-0.3.2.tgz", + "integrity": "sha512-27+z5s+9LeRBG+sk5e6mPuqu2dw4nBFV49ouNe/l11r+A+w5j6haZdX2kLR0wrWdJWDu7Dn0y9MQyxwPSyVEmg==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/document": "0.2.28", - "@flowgram.ai/form-core": "0.2.28", - "@flowgram.ai/history": "0.2.28", - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/document": "0.3.2", + "@flowgram.ai/form-core": "0.3.2", + "@flowgram.ai/history": "0.3.2", + "@flowgram.ai/utils": "0.3.2", "inversify": "^6.0.1", "lodash": "^4.17.21", "reflect-metadata": "~0.2.2" } }, "node_modules/@flowgram.ai/fixed-layout-core": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/fixed-layout-core/-/fixed-layout-core-0.2.28.tgz", - "integrity": "sha512-pIa7vaksAmBZm3aaDMkpxB8RsS+fHGntDjGBWuP5tKJkjMKSXyPDzA7vGOwcVLyX3OrYiMD8ypuCDOGPruAr2A==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/fixed-layout-core/-/fixed-layout-core-0.3.2.tgz", + "integrity": "sha512-e+J/oxFs4HD8FOdMHh79bXLEp+7gzoCk+42fMTAJ4Or4HEIkep8gRTpFxB0fINnWxpw3CpZZFnhMLIuyR5R46g==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/document": "0.2.28", - "@flowgram.ai/renderer": "0.2.28", - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/document": "0.3.2", + "@flowgram.ai/renderer": "0.3.2", + "@flowgram.ai/utils": "0.3.2", "inversify": "^6.0.1", "lodash": "^4.17.21", "reflect-metadata": "~0.2.2" @@ -2969,19 +2969,19 @@ } }, "node_modules/@flowgram.ai/fixed-layout-editor": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/fixed-layout-editor/-/fixed-layout-editor-0.2.28.tgz", - "integrity": "sha512-PpLQXWjC2L7eqVzNdt7Z4DxEh6GcIJyTrOQE0FjUB3XuS2IW7ciHogs3gEfAVpoFbZGj8tzIcs6IMUu1GxjeqQ==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/fixed-layout-editor/-/fixed-layout-editor-0.3.2.tgz", + "integrity": "sha512-wZxyYOt4f9CFX+iUiq5J4tyn4K9YmfcprYs26i7CB2D542vvpREVWXzl/FdTiylcW6qTTGcFAsQkdVdmd33xEg==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/editor": "0.2.28", - "@flowgram.ai/fixed-drag-plugin": "0.2.28", - "@flowgram.ai/fixed-history-plugin": "0.2.28", - "@flowgram.ai/fixed-layout-core": "0.2.28", - "@flowgram.ai/history": "0.2.28", - "@flowgram.ai/reactive": "0.2.28", - "@flowgram.ai/select-box-plugin": "0.2.28", - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/editor": "0.3.2", + "@flowgram.ai/fixed-drag-plugin": "0.3.2", + "@flowgram.ai/fixed-history-plugin": "0.3.2", + "@flowgram.ai/fixed-layout-core": "0.3.2", + "@flowgram.ai/history": "0.3.2", + "@flowgram.ai/reactive": "0.3.2", + "@flowgram.ai/select-box-plugin": "0.3.2", + "@flowgram.ai/utils": "0.3.2", "inversify": "^6.0.1", "reflect-metadata": "~0.2.2" }, @@ -2991,12 +2991,12 @@ } }, "node_modules/@flowgram.ai/form": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/form/-/form-0.2.28.tgz", - "integrity": "sha512-OgMDayBmHDUEjb6xWZeDmyn8BKZZazEsas3WJKlm2r6zaobygxE5K5NzJ/oy3OyLTgMtpYq3JOWZPgGu16ZRHg==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/form/-/form-0.3.2.tgz", + "integrity": "sha512-OHp6IhOQUcW3Hw/BWrxi4Kn/UTB96BkQgjl2mQ0o+HyqTwzGa9wNtLkNWqIK/CogD/l31kRp39L6rFH71S2AgQ==", "dependencies": { - "@flowgram.ai/reactive": "0.2.28", - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/reactive": "0.3.2", + "@flowgram.ai/utils": "0.3.2", "fast-equals": "^2.0.0", "lodash": "^4.17.21", "nanoid": "^4.0.2" @@ -3007,13 +3007,13 @@ } }, "node_modules/@flowgram.ai/form-core": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/form-core/-/form-core-0.2.28.tgz", - "integrity": "sha512-JpapezHkKEl4hgNnhBo/5mBUcgAv7aUQpp3ypZ0g/0L9qLd9vB3PjBw7mL+K4t+954ckJMLW0AHJyqeWKXpO4g==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/form-core/-/form-core-0.3.2.tgz", + "integrity": "sha512-RjipVRN/pKqDF27vL4GhtRpRtlcDlZZgv2chEehd1tnedJRmgH30REN3ET9ya+cF2Lte9z9ALdAD6KMfCqdySw==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/document": "0.2.28", - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/document": "0.3.2", + "@flowgram.ai/utils": "0.3.2", "inversify": "^6.0.1", "lodash": "^4.17.21", "reflect-metadata": "~0.2.2" @@ -3041,16 +3041,16 @@ } }, "node_modules/@flowgram.ai/free-layout-core": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/free-layout-core/-/free-layout-core-0.2.28.tgz", - "integrity": "sha512-oGLr4dTggl1e7h/usm0Hs4uYjiAKOU8ZY6W9xpEgvXJkRngiGDgh1+S3Sh7WfxvDQeHkaQhGRgcKNqECGqL1LQ==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/free-layout-core/-/free-layout-core-0.3.2.tgz", + "integrity": "sha512-xvoneqfmNqsfzLotqdikBOfMDXC173G0Gqs5XxDZv3fpCuUMyy3eI0KrnoJZMIp6BD5buDmBrm6vk9D8vE1WnQ==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/document": "0.2.28", - "@flowgram.ai/form-core": "0.2.28", - "@flowgram.ai/node": "0.2.28", - "@flowgram.ai/reactive": "0.2.28", - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/document": "0.3.2", + "@flowgram.ai/form-core": "0.3.2", + "@flowgram.ai/node": "0.3.2", + "@flowgram.ai/reactive": "0.3.2", + "@flowgram.ai/utils": "0.3.2", "inversify": "^6.0.1", "lodash-es": "^4.17.21", "nanoid": "^4.0.2", @@ -3079,14 +3079,14 @@ } }, "node_modules/@flowgram.ai/group-plugin": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/group-plugin/-/group-plugin-0.2.28.tgz", - "integrity": "sha512-Gk4A5oCOxF45Htf68OIR2yZyQR2416HMDsDISWCuAZiV/LafGDSNwRWiUv/6tpyUpwT1uHSipkTFSRwAWApO8g==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/group-plugin/-/group-plugin-0.3.2.tgz", + "integrity": "sha512-9fn4Sdu6uDqUPz00VBJu8F4CEdkQECg2ZIDETZLU8iG49eeX1qCGPOai7MRMGY83LcEDIR0Sk5w0Z7i4wM5mXQ==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/document": "0.2.28", - "@flowgram.ai/renderer": "0.2.28", - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/document": "0.3.2", + "@flowgram.ai/renderer": "0.3.2", + "@flowgram.ai/utils": "0.3.2", "inversify": "^6.0.1", "reflect-metadata": "~0.2.2" }, @@ -3096,12 +3096,12 @@ } }, "node_modules/@flowgram.ai/history": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/history/-/history-0.2.28.tgz", - "integrity": "sha512-Em5yq2ZmP5lRglrdIfHe54zt3PSMM3BUj95jge5rC1uxNes7vhu5jaKhVIK6aehu9m4pOY8ZJ7/Dudr3w04aJQ==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/history/-/history-0.3.2.tgz", + "integrity": "sha512-dL4v3tbUkZ4q4ph3LsCHQV5gV+kyYoPfjcR+ok4SyMoLzOg46YsAri7KVhNDR2El77EzGDPiCZ+9ZSQJqOX/eQ==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/utils": "0.3.2", "inversify": "^6.0.1", "lodash": "^4.17.21", "nanoid": "^4.0.2", @@ -3109,17 +3109,17 @@ } }, "node_modules/@flowgram.ai/history-node-plugin": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/history-node-plugin/-/history-node-plugin-0.2.28.tgz", - "integrity": "sha512-NnFt6ocTvGwWjgluUuvJL+Xivj75LrPEFPqhC+GcmciiNmD0HkhW/ojO0aBKv8/Ppemfjo840dhSyxAxyInPsw==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/history-node-plugin/-/history-node-plugin-0.3.2.tgz", + "integrity": "sha512-Q4kMsq11Z7tpHD9mIwPN3jQMrFter7xzbMznr36G4TLRlPV9bfsWNBhLbBto1WEhbiphQ/TTEiBjWQrxlpAkXQ==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/document": "0.2.28", - "@flowgram.ai/form": "0.2.28", - "@flowgram.ai/form-core": "0.2.28", - "@flowgram.ai/history": "0.2.28", - "@flowgram.ai/node": "0.2.28", - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/document": "0.3.2", + "@flowgram.ai/form": "0.3.2", + "@flowgram.ai/form-core": "0.3.2", + "@flowgram.ai/history": "0.3.2", + "@flowgram.ai/node": "0.3.2", + "@flowgram.ai/utils": "0.3.2", "inversify": "^6.0.1", "lodash": "^4.17.21", "reflect-metadata": "~0.2.2" @@ -3148,32 +3148,32 @@ } }, "node_modules/@flowgram.ai/i18n": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/i18n/-/i18n-0.2.28.tgz", - "integrity": "sha512-FsFPlLa834zTBhLKgw6PWm+SoLvsPp2xL9XiphXdjD3kDgLvAsotiO/mdGGuwC+nNMByo2MsUgf7gS7BIVMuTw==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/i18n/-/i18n-0.3.2.tgz", + "integrity": "sha512-k+9f6gwDh4YTL91BfliRL8IEgzGZ4ALBAuFmGVucpx+01NEYAoqwF1+g4u9udlXX9Ncny5DDMNNka1C3B5m46Q==", "dependencies": { - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/utils": "0.3.2", "i18n-js": "^4.5.1" } }, "node_modules/@flowgram.ai/i18n-plugin": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/i18n-plugin/-/i18n-plugin-0.2.28.tgz", - "integrity": "sha512-U0AjDZekzx7Z8ttxSI5JZWE6A2rzQncILYQ4ALTPpaS6nFqna7ju2qEedcUAIf/xo4gZiYugcQc511lvqtnhLg==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/i18n-plugin/-/i18n-plugin-0.3.2.tgz", + "integrity": "sha512-1Zyk6Sh+W62FAF7oP/p+fJ1JxF7iqpoKpOCC65VEHKVQ1TAbHg6fyOoSxNTE7wjnATvt6c3fDw7AYcevIlcRSA==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/i18n": "0.2.28" + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/i18n": "0.3.2" } }, "node_modules/@flowgram.ai/materials-plugin": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/materials-plugin/-/materials-plugin-0.2.28.tgz", - "integrity": "sha512-2s50E0MZwHnE4QVS564d2abd29iMv70r7cnRWeLtc6w91Y+mKHQWM5noeoi/diggIWUmj6w4pFYDnSOcN4DeGA==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/materials-plugin/-/materials-plugin-0.3.2.tgz", + "integrity": "sha512-svG1M1uMIeavXYj8UV5Mv2glcumQ7AYg4/U6xVGhMJFJmnAWNlNVQCqz5PFRkjyIH6FwW/xJVh03TSqpR2Svkw==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/form-core": "0.2.28", - "@flowgram.ai/renderer": "0.2.28", - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/form-core": "0.3.2", + "@flowgram.ai/renderer": "0.3.2", + "@flowgram.ai/utils": "0.3.2", "inversify": "^6.0.1", "reflect-metadata": "~0.2.2" }, @@ -3184,15 +3184,15 @@ } }, "node_modules/@flowgram.ai/node": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/node/-/node-0.2.28.tgz", - "integrity": "sha512-XZ+kKjZdOFYdC8XL2L+BCYAa/wVLnb2dD/lfedMd9Fnf0QaJaQupwhwPnLtmL4HcdB8ro8uBICSIgVGXED66Uw==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/node/-/node-0.3.2.tgz", + "integrity": "sha512-jVr5zlL/vab7g1JSv69fIivKZAb+kPDQJugeNm9Ux9vjaF3nfssFRPeeRCj8JWMw4hqdRUnTms9Mx1udrCLXTg==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/document": "0.2.28", - "@flowgram.ai/form": "0.2.28", - "@flowgram.ai/form-core": "0.2.28", - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/document": "0.3.2", + "@flowgram.ai/form": "0.3.2", + "@flowgram.ai/form-core": "0.3.2", + "@flowgram.ai/utils": "0.3.2", "inversify": "^6.0.1", "lodash": "^4.17.21", "nanoid": "^4.0.2", @@ -3204,16 +3204,16 @@ } }, "node_modules/@flowgram.ai/node-core-plugin": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/node-core-plugin/-/node-core-plugin-0.2.28.tgz", - "integrity": "sha512-72R6APzlW2Yy1od2QibIhSW3TW+xz44s0+k4rzJ+EZW0gHEwtmo+OCQLo19WM0CrBFjAomTyK/2J5L6a1mp9OA==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/node-core-plugin/-/node-core-plugin-0.3.2.tgz", + "integrity": "sha512-pSOKiVXSSL4u+7REMfK57n29Kpx7iuH///FAU9/1VdpjtnwLH25F/RBF8fyR+VLqdtwTfhqz2A7OjGMqIardmg==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/document": "0.2.28", - "@flowgram.ai/form-core": "0.2.28", - "@flowgram.ai/node": "0.2.28", - "@flowgram.ai/renderer": "0.2.28", - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/document": "0.3.2", + "@flowgram.ai/form-core": "0.3.2", + "@flowgram.ai/node": "0.3.2", + "@flowgram.ai/renderer": "0.3.2", + "@flowgram.ai/utils": "0.3.2", "inversify": "^6.0.1", "reflect-metadata": "~0.2.2" }, @@ -3224,16 +3224,16 @@ } }, "node_modules/@flowgram.ai/node-variable-plugin": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/node-variable-plugin/-/node-variable-plugin-0.2.28.tgz", - "integrity": "sha512-3GpLS6LG1w6Y24TJrXnxSa8BnMhs5sgjqv9VgBdx5DFQRynNtRV52bd3X+eNarNFMMcpEqTGiybrvRqmf84K/w==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/node-variable-plugin/-/node-variable-plugin-0.3.2.tgz", + "integrity": "sha512-GjSqMXv3IqZs6mbiSbHTk/anLQFHl6ozdqM1iCZoOn4V15HW7gJMvXHe3VGwsGxAunsgrbCkkciiZmayWSN9Xg==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/document": "0.2.28", - "@flowgram.ai/form-core": "0.2.28", - "@flowgram.ai/node": "0.2.28", - "@flowgram.ai/utils": "0.2.28", - "@flowgram.ai/variable-plugin": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/document": "0.3.2", + "@flowgram.ai/form-core": "0.3.2", + "@flowgram.ai/node": "0.3.2", + "@flowgram.ai/utils": "0.3.2", + "@flowgram.ai/variable-plugin": "0.3.2", "inversify": "^6.0.1", "lodash": "^4.17.21", "reflect-metadata": "~0.2.2" @@ -3262,14 +3262,14 @@ } }, "node_modules/@flowgram.ai/playground-react": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/playground-react/-/playground-react-0.2.28.tgz", - "integrity": "sha512-VvUewy+Av1XHeUa5CBPumkSZR3J/M0m4ME9na6hTfzs7bigKjU8rk+X7397JOWswUBBxGod3Lrw+ujttxxvNag==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/playground-react/-/playground-react-0.3.2.tgz", + "integrity": "sha512-dbuuLF+UKCaIgvlVLd1TbM9t13bePKc+BrFRcYvriXZTAbKI6XvWUD7kQ1hIydU5GgTrhpZEWR6WnrxAvEBlrA==", "dependencies": { - "@flowgram.ai/background-plugin": "0.2.28", - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/shortcuts-plugin": "0.2.28", - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/background-plugin": "0.3.2", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/shortcuts-plugin": "0.3.2", + "@flowgram.ai/utils": "0.3.2", "inversify": "^6.0.1", "reflect-metadata": "~0.2.2" }, @@ -3279,11 +3279,11 @@ } }, "node_modules/@flowgram.ai/reactive": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/reactive/-/reactive-0.2.28.tgz", - "integrity": "sha512-WC8FWI4iBhrrip8If1ghFUhqBxGcHExE4rc6Erx1QQqN7YNFII5/cKF1wAaEgQ99rSVGFxIxjkwrUOjNXnnS6g==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/reactive/-/reactive-0.3.2.tgz", + "integrity": "sha512-U39SOidMenXvcKRgWZ01L7NGCefDwE90S7nil1/1yJ2bqAT9YLpmIY07Sw474sepeZgx2R9HDStuVpLpZOgq0Q==", "dependencies": { - "@flowgram.ai/utils": "0.2.28" + "@flowgram.ai/utils": "0.3.2" }, "peerDependencies": { "react": ">=16.8", @@ -3291,12 +3291,12 @@ } }, "node_modules/@flowgram.ai/redux-devtool-plugin": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/redux-devtool-plugin/-/redux-devtool-plugin-0.2.28.tgz", - "integrity": "sha512-D8C0sWzGAFpFElacEHwONRr2vezcLa3jT6SRtYEbQ0poSA6HLPPYSigRjug8A19jd9NayCVulPm1M59GpuZF3Q==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/redux-devtool-plugin/-/redux-devtool-plugin-0.3.2.tgz", + "integrity": "sha512-yPeQYWK3juW+TeSWYDxjcpjSH1MlbXGpumKaoX4dFfoeNatVVzH77z3R345jLeJv2SwB0bHC7djfp6Dlb2vIsQ==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/variable-core": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/variable-core": "0.3.2", "inversify": "^6.0.1", "reflect-metadata": "~0.2.2", "styled-components": "^5" @@ -3351,14 +3351,14 @@ } }, "node_modules/@flowgram.ai/renderer": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/renderer/-/renderer-0.2.28.tgz", - "integrity": "sha512-7AVVZqsUFeNvq339UfUSohk0ByVDq9ocllODScbeIAVWGZyNjG0tyJyaIEoCYrSqh2l+78C+AsaaBJvOPZG5bg==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/renderer/-/renderer-0.3.2.tgz", + "integrity": "sha512-Pzc43vzAxwpXjJrUkuMopgMMxkplarSlWPw3KdBd9wSIroAslBI6i7z7x3WljfGTJPHGt50EI24tLKTZzGECeQ==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/document": "0.2.28", - "@flowgram.ai/i18n": "0.2.28", - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/document": "0.3.2", + "@flowgram.ai/i18n": "0.3.2", + "@flowgram.ai/utils": "0.3.2", "inversify": "^6.0.1", "lodash": "^4.17.21", "reflect-metadata": "~0.2.2" @@ -3369,12 +3369,12 @@ } }, "node_modules/@flowgram.ai/select-box-plugin": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/select-box-plugin/-/select-box-plugin-0.2.28.tgz", - "integrity": "sha512-xIPLKpT3hUtlHzvSOqeu8yqhVJDL7En8cRawKWwJjBs0nrFXEGryPnMCrsmbF1JwTFZrvKrznJacocqmiLwI3A==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/select-box-plugin/-/select-box-plugin-0.3.2.tgz", + "integrity": "sha512-mM58wToixwB/lfGtojwYPgip/sh6Go3+caEH4Eo447dlf88R6bSjWxThZG689QFsY6ZSQEfchg4GO1eYERvOwQ==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/renderer": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/renderer": "0.3.2", "inversify": "^6.0.1", "reflect-metadata": "~0.2.2" }, @@ -3384,13 +3384,13 @@ } }, "node_modules/@flowgram.ai/shortcuts-plugin": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/shortcuts-plugin/-/shortcuts-plugin-0.2.28.tgz", - "integrity": "sha512-S3XkBmZnQ4FZ+A7sD56v6L2UFOhMSwqTmA4S1G8XqMvmbfHjUjR/OxojfQw/MSd5QNygD4ikBesPoj6FMP45FQ==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/shortcuts-plugin/-/shortcuts-plugin-0.3.2.tgz", + "integrity": "sha512-D5Z3CAd61c2e0bQ9n8ULFAK1yFqV9q7UpMQ89IAu+armcT6w0XORC0CP/c7ojoBvGKYaWMH1gZf0NlQHiT6CZQ==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/document": "0.2.28", - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/document": "0.3.2", + "@flowgram.ai/utils": "0.3.2", "inversify": "^6.0.1", "reflect-metadata": "~0.2.2", "styled-components": "^5" @@ -3445,9 +3445,9 @@ } }, "node_modules/@flowgram.ai/utils": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/utils/-/utils-0.2.28.tgz", - "integrity": "sha512-HG4LpVo3gUcTp/tJCe72vZ9nByRXgkvp2wYyFFD3ZnGvEL8V3PIRwHGvBMP0UqgYBPHOZyqOZhOenP73msvkwg==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/utils/-/utils-0.3.2.tgz", + "integrity": "sha512-XVmiYft8JfrZsV5M2M8i2AMjhz6Fe4Euv0gOuLiSsZL1ZnR95IHzEHuvSd98of4srcUL+b/RcwB2BMXH+/EJ9w==", "dependencies": { "clsx": "^1.1.1", "inversify": "^6.0.1", @@ -3485,18 +3485,18 @@ } }, "node_modules/@flowgram.ai/variable-core": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/variable-core/-/variable-core-0.2.28.tgz", - "integrity": "sha512-Au6UCupM1d044w++GMv2HC4YGc2nsDNBdem71gjxcDLowGo9FDgKF1Fxh2E+UfCv9QfAcShJzCg0R4EtCpEsuQ==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/variable-core/-/variable-core-0.3.2.tgz", + "integrity": "sha512-95E7akQXzPItx7H/tKT4g5CZ0gg6OCsBou13OfotivZS1Yn5GxtqOeWGz7EHUZwurzB9w6o30VR6Y8vuk049Bg==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/utils": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/utils": "0.3.2", "fast-equals": "^2.0.0", "inversify": "^6.0.1", "lodash": "^4.17.21", "nanoid": "^4.0.2", "reflect-metadata": "~0.2.2", - "rxjs": "^7.8.1" + "rxjs": "^7.8.2" }, "peerDependencies": { "react": ">=16.8", @@ -3521,15 +3521,15 @@ } }, "node_modules/@flowgram.ai/variable-layout": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/variable-layout/-/variable-layout-0.2.28.tgz", - "integrity": "sha512-31mxxnLJFanmdMkMvl6WzGV+CO15gPT0jnMsf0Mqp+s7qadtwuHcwzsDEUU9RKR+d/oXuGBpNGrdtQJzBh2JMQ==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/variable-layout/-/variable-layout-0.3.2.tgz", + "integrity": "sha512-vX9lGLl5yY0VAYv5Bua3jqkh2M80+YB/4Qea0crkPAWzg1eVQcG4zbnR+Wc6c3wNz9cTpT+vq+2kiTsP5+95eQ==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/document": "0.2.28", - "@flowgram.ai/free-layout-core": "0.2.28", - "@flowgram.ai/utils": "0.2.28", - "@flowgram.ai/variable-core": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/document": "0.3.2", + "@flowgram.ai/free-layout-core": "0.3.2", + "@flowgram.ai/utils": "0.3.2", + "@flowgram.ai/variable-core": "0.3.2", "inversify": "^6.0.1", "reflect-metadata": "~0.2.2", "styled-components": "^5" @@ -3584,16 +3584,16 @@ } }, "node_modules/@flowgram.ai/variable-plugin": { - "version": "0.2.28", - "resolved": "https://registry.npmmirror.com/@flowgram.ai/variable-plugin/-/variable-plugin-0.2.28.tgz", - "integrity": "sha512-lPxcLNClR865dQMGAGy+NSbC+80mWbVXRolbN1ScIj7on9ypTtDs86VTdFGlKMzP8BSWIXM1Rjb6oSEShCxuJA==", + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/@flowgram.ai/variable-plugin/-/variable-plugin-0.3.2.tgz", + "integrity": "sha512-Fm4DS/DrfcyKtvwUyoB4y5dBr8D/JWaSZjhu6kWee3HIV46uJLruufynMBQprWEgSMj9RyYFoFVQWH4hYisNWg==", "dependencies": { - "@flowgram.ai/core": "0.2.28", - "@flowgram.ai/document": "0.2.28", - "@flowgram.ai/free-layout-core": "0.2.28", - "@flowgram.ai/utils": "0.2.28", - "@flowgram.ai/variable-core": "0.2.28", - "@flowgram.ai/variable-layout": "0.2.28", + "@flowgram.ai/core": "0.3.2", + "@flowgram.ai/document": "0.3.2", + "@flowgram.ai/free-layout-core": "0.3.2", + "@flowgram.ai/utils": "0.3.2", + "@flowgram.ai/variable-core": "0.3.2", + "@flowgram.ai/variable-layout": "0.3.2", "inversify": "^6.0.1", "reflect-metadata": "~0.2.2", "styled-components": "^5" @@ -4028,9 +4028,9 @@ } }, "node_modules/@rc-component/trigger": { - "version": "2.2.7", - "resolved": "https://registry.npmmirror.com/@rc-component/trigger/-/trigger-2.2.7.tgz", - "integrity": "sha512-Qggj4Z0AA2i5dJhzlfFSmg1Qrziu8dsdHOihROL5Kl18seO2Eh/ZaTYt2c8a/CyGaTChnFry7BEYew1+/fhSbA==", + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/@rc-component/trigger/-/trigger-2.3.0.tgz", + "integrity": "sha512-iwaxZyzOuK0D7lS+0AQEtW52zUWxoGqTGkke3dRyb8pYiShmRpCjB/8TzPI4R6YySCH7Vm9BZj/31VPiiQTLBg==", "dependencies": { "@babel/runtime": "^7.23.2", "@rc-component/portal": "^1.1.0", @@ -5000,9 +5000,9 @@ } }, "node_modules/@uiw/codemirror-extensions-basic-setup": { - "version": "4.24.1", - "resolved": "https://registry.npmmirror.com/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.24.1.tgz", - "integrity": "sha512-o1m1a8eUS3fWERMbDFvN8t8sZUFPgDKNemmlQ5Ot2vKm+Ax84lKP1dhEFgkiOaZ1bDHk4T5h6SjHuTghrJHKww==", + "version": "4.24.2", + "resolved": "https://registry.npmmirror.com/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.24.2.tgz", + "integrity": "sha512-wW/gjLRvVUeYyhdh2TApn25cvdcR+Rhg6R/j3eTOvXQzU1HNzNYCVH4YKVIfgtfdM/Xs+N8fkk+rbr1YvBppCg==", "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/commands": "^6.0.0", @@ -5026,20 +5026,20 @@ } }, "node_modules/@uiw/codemirror-theme-vscode": { - "version": "4.24.1", - "resolved": "https://registry.npmmirror.com/@uiw/codemirror-theme-vscode/-/codemirror-theme-vscode-4.24.1.tgz", - "integrity": "sha512-w2/eaPcYsHi03aWoKzVxIWv5dBDKW4YPnjwyYLgFY3uNdZmSfoNkFhqW7GJgNNF77ATixPq2wm9XqYeOTtvuww==", + "version": "4.24.2", + "resolved": "https://registry.npmmirror.com/@uiw/codemirror-theme-vscode/-/codemirror-theme-vscode-4.24.2.tgz", + "integrity": "sha512-5rLvAMKNjqtHSy3BZnI1Q4ZLqUDDJC5fKOp8Mv5VjPqEmAxEAIGrIXBnhAFlRg5VjHbHEMtM1O5ugL3IeHoBdQ==", "dependencies": { - "@uiw/codemirror-themes": "4.24.1" + "@uiw/codemirror-themes": "4.24.2" }, "funding": { "url": "https://jaywcjlove.github.io/#/sponsor" } }, "node_modules/@uiw/codemirror-themes": { - "version": "4.24.1", - "resolved": "https://registry.npmmirror.com/@uiw/codemirror-themes/-/codemirror-themes-4.24.1.tgz", - "integrity": "sha512-hduBbFNiWNW6nYa2/giKQ9YpzhWNw87BGpCjC+cXYMZ7bCD6q5DC6Hw+7z7ZwSzEaOQvV91lmirOjJ8hn9+pkg==", + "version": "4.24.2", + "resolved": "https://registry.npmmirror.com/@uiw/codemirror-themes/-/codemirror-themes-4.24.2.tgz", + "integrity": "sha512-0fQusJE08APL+1WM0xYqvampVM2RpABHjvZbcJWHdRc+teZbrP8907VW1ZX1tO/7/xgRRt4Fc3RHPCcTs7b0NQ==", "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", @@ -5055,15 +5055,15 @@ } }, "node_modules/@uiw/react-codemirror": { - "version": "4.24.1", - "resolved": "https://registry.npmmirror.com/@uiw/react-codemirror/-/react-codemirror-4.24.1.tgz", - "integrity": "sha512-BivF4NLqbuBQK5gPVhSkOARi9nPXw8X5r25EnInPeY+I9l1dfEX8O9V6+0xHTlGHyUo0cNfGEF9t1KHEicUfJw==", + "version": "4.24.2", + "resolved": "https://registry.npmmirror.com/@uiw/react-codemirror/-/react-codemirror-4.24.2.tgz", + "integrity": "sha512-kp7DhTq4RR+M2zJBQBrHn1dIkBrtOskcwJX4vVsKGByReOvfMrhqRkGTxYMRDTX6x75EG2mvBJPDKYcUQcHWBw==", "dependencies": { "@babel/runtime": "^7.18.6", "@codemirror/commands": "^6.1.0", "@codemirror/state": "^6.1.1", "@codemirror/theme-one-dark": "^6.0.0", - "@uiw/codemirror-extensions-basic-setup": "4.24.1", + "@uiw/codemirror-extensions-basic-setup": "4.24.2", "codemirror": "^6.0.0" }, "funding": { @@ -5075,8 +5075,8 @@ "@codemirror/theme-one-dark": ">=6.0.0", "@codemirror/view": ">=6.0.0", "codemirror": ">=6.0.0", - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "react": ">=17.0.0", + "react-dom": ">=17.0.0" } }, "node_modules/@umijs/route-utils": { @@ -5472,9 +5472,9 @@ } }, "node_modules/antd": { - "version": "5.26.6", - "resolved": "https://registry.npmmirror.com/antd/-/antd-5.26.6.tgz", - "integrity": "sha512-k8ipeT+UL2tP/x4jHTXElScAxsD94JgrIEeGHj80nNO4dL9hqcmaOUBpHo3ieCf6MFjhS7gLUthysQeP6e7DUg==", + "version": "5.26.7", + "resolved": "https://registry.npmmirror.com/antd/-/antd-5.26.7.tgz", + "integrity": "sha512-iCyXN6+i2CUVEOSzzJKfbKeg115qoJhGvSkCh5uzAf9hANwHUOJQhsMn+KtN+Lx/2NQ6wfM7nGZ+7NPNO5Pn1w==", "dependencies": { "@ant-design/colors": "^7.2.1", "@ant-design/cssinjs": "^1.23.0", @@ -5487,7 +5487,7 @@ "@rc-component/mutate-observer": "^1.1.0", "@rc-component/qrcode": "~1.0.0", "@rc-component/tour": "~1.15.1", - "@rc-component/trigger": "^2.2.7", + "@rc-component/trigger": "^2.3.0", "classnames": "^2.5.1", "copy-to-clipboard": "^3.3.3", "dayjs": "^1.11.11", @@ -5517,7 +5517,7 @@ "rc-switch": "~4.1.0", "rc-table": "~7.51.1", "rc-tabs": "~15.6.1", - "rc-textarea": "~1.10.0", + "rc-textarea": "~1.10.1", "rc-tooltip": "~6.4.0", "rc-tree": "~5.13.1", "rc-tree-select": "~5.27.0", @@ -6151,6 +6151,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmmirror.com/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "optional": true, + "peer": true, + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/dayjs": { "version": "1.11.13", "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz", @@ -6631,9 +6648,9 @@ } }, "node_modules/eslint-plugin-better-tailwindcss": { - "version": "3.7.2", - "resolved": "https://registry.npmmirror.com/eslint-plugin-better-tailwindcss/-/eslint-plugin-better-tailwindcss-3.7.2.tgz", - "integrity": "sha512-uJnoDGmUPtxHHcIW5njEoh1CYlq39E4J2pWq+D7REDGhW41arSCeeaiiwAT4Ok04kXNvmFBiYmC6Jdd6Bz7o2Q==", + "version": "3.7.3", + "resolved": "https://registry.npmmirror.com/eslint-plugin-better-tailwindcss/-/eslint-plugin-better-tailwindcss-3.7.3.tgz", + "integrity": "sha512-7I2MM1/OetBamiNWGkAetzQtvph6N7B6Iy5nIU9srFkHXnqR5G6lFX7ZT+JZmLrirrYSn8E0THeJg9QTQaI/kQ==", "dev": true, "dependencies": { "@eslint/css-tree": "^3.6.2", @@ -9326,9 +9343,9 @@ } }, "node_modules/rc-textarea": { - "version": "1.10.0", - "resolved": "https://registry.npmmirror.com/rc-textarea/-/rc-textarea-1.10.0.tgz", - "integrity": "sha512-ai9IkanNuyBS4x6sOL8qu/Ld40e6cEs6pgk93R+XLYg0mDSjNBGey6/ZpDs5+gNLD7urQ14po3V6Ck2dJLt9SA==", + "version": "1.10.2", + "resolved": "https://registry.npmmirror.com/rc-textarea/-/rc-textarea-1.10.2.tgz", + "integrity": "sha512-HfaeXiaSlpiSp0I/pvWpecFEHpVysZ9tpDLNkxQbMvMz6gsr7aVZ7FpWP9kt4t7DB+jJXesYS0us1uPZnlRnwQ==", "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.1", @@ -11146,17 +11163,17 @@ } }, "node_modules/zod": { - "version": "4.0.10", - "resolved": "https://registry.npmmirror.com/zod/-/zod-4.0.10.tgz", - "integrity": "sha512-3vB+UU3/VmLL2lvwcY/4RV2i9z/YU0DTV/tDuYjrwmx5WeJ7hwy+rGEEx8glHp6Yxw7ibRbKSaIFBgReRPe5KA==", + "version": "4.0.14", + "resolved": "https://registry.npmmirror.com/zod/-/zod-4.0.14.tgz", + "integrity": "sha512-nGFJTnJN6cM2v9kXL+SOBq3AtjQby3Mv5ySGFof5UGRHrRioSJ5iG680cYNjE/yWk671nROcpPj4hAS8nyLhSw==", "funding": { "url": "https://github.com/sponsors/colinhacks" } }, "node_modules/zustand": { - "version": "5.0.6", - "resolved": "https://registry.npmmirror.com/zustand/-/zustand-5.0.6.tgz", - "integrity": "sha512-ihAqNeUVhe0MAD+X8M5UzqyZ9k3FFZLBTtqo6JLPwV53cbRB/mJwBI0PxcIgqhBBHlEs8G45OTDTMq3gNcLq3A==", + "version": "5.0.7", + "resolved": "https://registry.npmmirror.com/zustand/-/zustand-5.0.7.tgz", + "integrity": "sha512-Ot6uqHDW/O2VdYsKLLU8GQu8sCOM1LcoE8RwvLv9uuRT9s6SOHCKs0ZEOhxg+I1Ld+A1Q5lwx+UlKXXUoCZITg==", "engines": { "node": ">=12.20.0" }, diff --git a/ui/package.json b/ui/package.json index 8150cac20..4bfdbc5e7 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,7 +1,6 @@ { - "name": "ui", + "name": "@certimate/webui", "private": true, - "version": "0.0.0", "type": "module", "scripts": { "dev": "vite --host", @@ -15,13 +14,14 @@ "@codemirror/lang-yaml": "^6.1.2", "@codemirror/language": "^6.11.2", "@codemirror/legacy-modes": "^6.5.1", - "@flowgram.ai/fixed-layout-editor": "^0.2.28", + "@flowgram.ai/fixed-layout-editor": "^0.3.2", + "@flowgram.ai/document": "^0.3.2", "@tabler/icons-react": "^3.34.1", - "@uiw/codemirror-extensions-basic-setup": "^4.24.1", - "@uiw/codemirror-theme-vscode": "^4.24.1", - "@uiw/react-codemirror": "^4.24.1", + "@uiw/codemirror-extensions-basic-setup": "^4.24.2", + "@uiw/codemirror-theme-vscode": "^4.24.2", + "@uiw/react-codemirror": "^4.24.2", "ahooks": "^3.9.0", - "antd": "^5.26.6", + "antd": "^5.26.7", "antd-zod": "^7.0.0", "clsx": "^2.1.1", "cron-parser": "^5.3.0", @@ -38,8 +38,8 @@ "react-i18next": "^15.6.1", "react-router-dom": "^7.7.1", "tailwind-merge": "^3.3.1", - "zod": "^4.0.10", - "zustand": "^5.0.6" + "zod": "^4.0.14", + "zustand": "^5.0.7" }, "devDependencies": { "@eslint/js": "^9.32.0", @@ -56,7 +56,7 @@ "eslint": "^9.32.0", "eslint-config-prettier": "^10.1.8", "eslint-import-resolver-typescript": "^4.4.4", - "eslint-plugin-better-tailwindcss": "^3.7.2", + "eslint-plugin-better-tailwindcss": "^3.7.3", "eslint-plugin-import": "^2.32.0", "eslint-plugin-prettier": "^5.5.3", "eslint-plugin-react-hooks": "^5.2.0", diff --git a/ui/src/components/MultipleSplitValueInput.tsx b/ui/src/components/MultipleSplitValueInput.tsx index 2f571aabd..d161c8474 100644 --- a/ui/src/components/MultipleSplitValueInput.tsx +++ b/ui/src/components/MultipleSplitValueInput.tsx @@ -2,7 +2,7 @@ import { IconList } from "@tabler/icons-react"; import { useControllableValue } from "ahooks"; import { Button, Form, Input, type InputProps, Space } from "antd"; -import { nanoid } from "nanoid"; +import { nanoid } from "nanoid/non-secure"; import { useAntdForm } from "@/hooks"; import ModalForm from "./ModalForm"; diff --git a/ui/src/components/workflow/WorkflowElementsContainer.tsx b/ui/src/components/workflow/WorkflowElementsContainer.tsx index dcc83c724..bf189d3a0 100644 --- a/ui/src/components/workflow/WorkflowElementsContainer.tsx +++ b/ui/src/components/workflow/WorkflowElementsContainer.tsx @@ -30,15 +30,19 @@ const WorkflowElementsContainer = ({ className, style, disabled }: WorkflowEleme -
- -
-
+
- + ); diff --git a/ui/src/components/workflow/designer/Editor.tsx b/ui/src/components/workflow/designer/Editor.tsx new file mode 100644 index 000000000..eed080e4f --- /dev/null +++ b/ui/src/components/workflow/designer/Editor.tsx @@ -0,0 +1,119 @@ +import { useMemo, useRef } from "react"; +import { + ConstantKeys, + EditorRenderer, + FixedLayoutEditorProvider, + type FixedLayoutPluginContext, + type FixedLayoutProps, + type FlowDocumentJSON, + FlowTextKey, +} from "@flowgram.ai/fixed-layout-editor"; +import "@flowgram.ai/fixed-layout-editor/index.css"; +import { useDeepCompareEffect } from "ahooks"; +import { theme } from "antd"; + +import { getFlowComponents } from "./components"; +import NodeRender from "./NodeRender"; +import { getFlowNodeRegistries } from "./nodes"; +import { BlockNode } from "./nodes/_shared"; +import "./flowgram.css"; + +export interface EditorProps { + className?: string; + style?: React.CSSProperties; + children?: React.ReactNode; + initialData?: FlowDocumentJSON; + readonly?: boolean; +} + +const Editor = ({ className, style, children, initialData, readonly }: EditorProps) => { + const { token: themeToken } = theme.useToken(); + + const flowgramEditorRef = useRef(null); + const flowgramEditorProps = useMemo( + () => ({ + initialData: initialData, + + constants: { + [ConstantKeys.BASE_COLOR]: themeToken.colorBorder, + [ConstantKeys.BASE_ACTIVATED_COLOR]: themeToken.colorPrimary, + [ConstantKeys.NODE_SPACING]: 64, + [ConstantKeys.BRANCH_SPACING]: 64, + // [ConstantKeys.INLINE_BLOCKS_PADDING_TOP]: 48, + // [ConstantKeys.INLINE_BLOCKS_PADDING_BOTTOM]: 48, + }, + + background: { + backgroundColor: themeToken.colorBgContainer, + dotSize: 0, + }, + + playground: { + autoFocus: true, + autoResize: true, + preventGlobalGesture: true, + }, + + scroll: { + enableScrollLimit: true, + }, + + readonly: readonly, + + nodeEngine: { + enable: true, + }, + + variableEngine: { + enable: true, + }, + + materials: { + components: getFlowComponents(), + renderTexts: { + [FlowTextKey.TRY_START_TEXT]: "Try", + [FlowTextKey.TRY_END_TEXT]: "Finally", + [FlowTextKey.CATCH_TEXT]: "Catch", + }, + renderDefaultNode: NodeRender, + }, + + nodeRegistries: getFlowNodeRegistries(), + + getNodeDefaultRegistry(type) { + return { + type, + meta: { + defaultExpanded: true, + }, + formMeta: { + render: () => {type}, + }, + }; + }, + + onAllLayersRendered: (ctx) => { + // 画布初始化后向下滚动一点,露出可能被 Alert 遮挡的部分 + setTimeout(() => { + ctx.playground.config.scroll({ scrollY: -80 }); + }, 1); + }, + }), + [themeToken, initialData, readonly] + ); + + useDeepCompareEffect(() => { + flowgramEditorRef.current?.document?.fromJSON?.(initialData ?? {}); + }, [initialData]); + + return ( +
+ + + {children} + +
+ ); +}; + +export default Editor; diff --git a/ui/src/components/workflow/designer/NodeRender.tsx b/ui/src/components/workflow/designer/NodeRender.tsx new file mode 100644 index 000000000..55a40ac03 --- /dev/null +++ b/ui/src/components/workflow/designer/NodeRender.tsx @@ -0,0 +1,27 @@ +import { type NodeRenderProps, useNodeRender } from "@flowgram.ai/fixed-layout-editor"; + +export interface NodeProps extends NodeRenderProps {} + +const Node = (_: NodeProps) => { + const nodeRender = useNodeRender(); + + return ( +
{ + nodeRender.startDrag(e); + e.stopPropagation(); + }} + > + {nodeRender.form?.render()} +
+ ); +}; + +export default Node; diff --git a/ui/src/components/workflow/designer/Toolbar.tsx b/ui/src/components/workflow/designer/Toolbar.tsx new file mode 100644 index 000000000..72245af6f --- /dev/null +++ b/ui/src/components/workflow/designer/Toolbar.tsx @@ -0,0 +1,78 @@ +import { useCallback, useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { EditorState, FlowLayoutDefault, useClientContext, usePlaygroundTools, useRefresh } from "@flowgram.ai/fixed-layout-editor"; +import { IconHandStop, IconLayoutCards, IconMaximize, IconMinus, IconPlus, IconPointer } from "@tabler/icons-react"; +import { Button, Tooltip } from "antd"; + +import { mergeCls } from "@/utils/css"; + +export interface ToolbarProps { + className?: string; + style?: React.CSSProperties; +} + +const Toolbar = ({ className, style }: ToolbarProps) => { + const { t } = useTranslation(); + + const ctx = useClientContext(); + const { playground } = ctx; + + const tools = usePlaygroundTools({ minZoom: 0.1, maxZoom: 3, padding: 48 }); + + const refresh = useRefresh(); + useEffect(() => { + const disposable = playground.config.onReadonlyOrDisabledChange(() => refresh()); + return () => disposable.dispose(); + }, [playground]); + + const [isMouseFriendly, setIsMouseFriendly] = useState(playground.editorState.is(EditorState.STATE_MOUSE_FRIENDLY_SELECT.id)); + + const handleToggleLayout = useCallback(() => { + if (tools.isVertical) { + tools.changeLayout(FlowLayoutDefault.HORIZONTAL_FIXED_LAYOUT); + } else { + tools.changeLayout(FlowLayoutDefault.VERTICAL_FIXED_LAYOUT); + } + }, [tools.isVertical]); + + const handleToggleMouseFriendly = useCallback(() => { + if (isMouseFriendly) { + playground.editorState.changeState(EditorState.STATE_SELECT.id); + setIsMouseFriendly(false); + } else { + playground.editorState.changeState(EditorState.STATE_MOUSE_FRIENDLY_SELECT.id); + setIsMouseFriendly(true); + } + }, [isMouseFriendly]); + + return ( +
+
+ + + + +
+
+ ); +}; + +export default Toolbar; diff --git a/ui/src/components/workflow/designer/components/Adder.tsx b/ui/src/components/workflow/designer/components/Adder.tsx new file mode 100644 index 000000000..d915ae6bb --- /dev/null +++ b/ui/src/components/workflow/designer/components/Adder.tsx @@ -0,0 +1,65 @@ +import { type AdderProps as FlowgramAdderProps, useClientContext } from "@flowgram.ai/fixed-layout-editor"; + +import { IconPlus } from "@tabler/icons-react"; +import { Button, Dropdown } from "antd"; + +import { getFlowNodeRegistries } from "../nodes"; + +export interface AdderProps extends FlowgramAdderProps {} + +const Adder = ({ from, hoverActivated }: AdderProps) => { + const ctx = useClientContext(); + const { operation, playground } = ctx; + + const menuItems = getFlowNodeRegistries() + .filter((registry) => { + if (registry.canAdd != null) { + return registry.canAdd(ctx, from); + } + if (registry.meta?.addDisable != null) { + return registry.meta.addDisable; + } + return true; + }) + .map((registry) => { + const Icon = registry.meta?.icon; + + return { + key: registry.type, + label: registry.type, + icon: ( + + + + ), + onClick: () => { + const props = registry.onAdd!(ctx, from); + const block = operation.addFromNode(from, { + ...props, + blocks: props?.blocks ?? [], + }); + + setTimeout(() => { + playground.scrollToView({ + bounds: block.bounds, + scrollToCenter: true, + }); + }, 1); + }, + }; + }); + + return playground.config.readonlyOrDisabled ? null : ( +
+ + {hoverActivated ? ( +
+ ); +}; + +export default Adder; diff --git a/ui/src/components/workflow/designer/components/BranchAdder.tsx b/ui/src/components/workflow/designer/components/BranchAdder.tsx new file mode 100644 index 000000000..b2ca2c6db --- /dev/null +++ b/ui/src/components/workflow/designer/components/BranchAdder.tsx @@ -0,0 +1,62 @@ +import { useTranslation } from "react-i18next"; +import { FlowNodeBaseType, type FlowNodeEntity, type AdderProps as FlowgramAdderProps, useClientContext } from "@flowgram.ai/fixed-layout-editor"; +import { Button } from "antd"; +import { nanoid } from "nanoid"; + +import { BranchBlockNodeRegistry } from "../nodes/ConditionNode"; +import { CatchBlockNodeRegistry } from "../nodes/TryCatchNode"; +import { NodeType } from "../nodes/typings"; + +export interface BranchAdderProps extends FlowgramAdderProps {} + +const BranchAdder = ({ node }: BranchAdderProps) => { + const { t } = useTranslation(); + + const ctx = useClientContext(); + const { operation, playground } = ctx; + + const handleAddBranch = () => { + let block: FlowNodeEntity; + switch (node.flowNodeType) { + case NodeType.Condition: + block = operation.addBlock(node, BranchBlockNodeRegistry.onAdd!(ctx, node)); + break; + + case NodeType.TryCatch: + block = operation.addBlock(node, CatchBlockNodeRegistry.onAdd!(ctx, node)); + break; + + default: + console.warn(`[certimate] unsupported node type for adding branch: '${node.flowNodeType}'`); + block = operation.addBlock(node, { + id: nanoid(), + type: FlowNodeBaseType.BLOCK, + data: { + name: "Branch", + }, + }); + break; + } + + setTimeout(() => { + playground.scrollToView({ + bounds: block.bounds, + scrollToCenter: true, + }); + }, 1); + }; + + return playground.config.readonlyOrDisabled ? null : ( +
node.firstChild?.renderData?.toggleMouseEnter()} + onMouseLeave={() => node.firstChild?.renderData?.toggleMouseLeave()} + > + +
+ ); +}; + +export default BranchAdder; diff --git a/ui/src/components/workflow/designer/components/Collapse.tsx b/ui/src/components/workflow/designer/components/Collapse.tsx new file mode 100644 index 000000000..28560fd96 --- /dev/null +++ b/ui/src/components/workflow/designer/components/Collapse.tsx @@ -0,0 +1,9 @@ +import { type CollapseProps as FlowgramCollapseProps } from "@flowgram.ai/fixed-layout-editor"; + +export interface CollapseProps extends FlowgramCollapseProps {} + +const Collapse = (_: CollapseProps) => { + return null; +}; + +export default Collapse; diff --git a/ui/src/components/workflow/designer/components/DragHighlightAdder.tsx b/ui/src/components/workflow/designer/components/DragHighlightAdder.tsx new file mode 100644 index 000000000..f4543ef65 --- /dev/null +++ b/ui/src/components/workflow/designer/components/DragHighlightAdder.tsx @@ -0,0 +1,14 @@ +import { type DragNodeProps as FlowgramDragNodeProps } from "@flowgram.ai/fixed-layout-editor"; +import { IconGradienter } from "@tabler/icons-react"; + +const DragHighlightAdder = (_: FlowgramDragNodeProps) => { + return ( +
+
+ +
+
+ ); +}; + +export default DragHighlightAdder; diff --git a/ui/src/components/workflow/designer/components/DragNode.tsx b/ui/src/components/workflow/designer/components/DragNode.tsx new file mode 100644 index 000000000..e6a2ddd64 --- /dev/null +++ b/ui/src/components/workflow/designer/components/DragNode.tsx @@ -0,0 +1,26 @@ +import { type FlowNodeEntity, type DragNodeProps as FlowgramDragNodeProps, getNodeForm } from "@flowgram.ai/fixed-layout-editor"; +import { Badge, Card } from "antd"; + +export interface DragNodeProps extends FlowgramDragNodeProps { + dragStart: FlowNodeEntity; + dragNodes: FlowNodeEntity[]; +} + +const DragNode = ({ dragStart, dragNodes }: DragNodeProps) => { + const count = (dragNodes || []) + .map((n) => (n.allCollapsedChildren.length ? n.allCollapsedChildren.filter((_n) => !_n.hidden).length : 1)) + .reduce((acc, cur) => acc + cur, 0); + return ( + 1 ? count : 0} size="small"> +
+ +
+
{dragStart ? getNodeForm(dragStart)?.getValueIn("name") || `#${dragStart?.id}` : "\u00A0"}
+
+
+
+
+ ); +}; + +export default DragNode; diff --git a/ui/src/components/workflow/designer/components/DraggingAdder.tsx b/ui/src/components/workflow/designer/components/DraggingAdder.tsx new file mode 100644 index 000000000..97f52ed4e --- /dev/null +++ b/ui/src/components/workflow/designer/components/DraggingAdder.tsx @@ -0,0 +1,31 @@ +import { FlowDragLayer, type AdderProps as FlowgramAdderProps, usePlayground } from "@flowgram.ai/fixed-layout-editor"; +import { IconChevronsDown } from "@tabler/icons-react"; + +export interface DraggingAdderProps extends FlowgramAdderProps {} + +const DraggingAdder = ({ from }: DraggingAdderProps) => { + const playground = usePlayground(); + + const layer = playground.getLayer(FlowDragLayer); + if (!layer) return <>; + if ( + layer.options.canDrop && + !layer.options.canDrop({ + dragNodes: layer.dragEntities ?? [], + dropNode: from, + isBranch: false, + }) + ) { + return <>; + } + + return ( +
+
+ +
+
+ ); +}; + +export default DraggingAdder; diff --git a/ui/src/components/workflow/designer/components/Null.tsx b/ui/src/components/workflow/designer/components/Null.tsx new file mode 100644 index 000000000..fe29349c2 --- /dev/null +++ b/ui/src/components/workflow/designer/components/Null.tsx @@ -0,0 +1,11 @@ +import { type FlowNodeEntity } from "@flowgram.ai/fixed-layout-editor"; + +export interface NullProps { + node: FlowNodeEntity; +} + +const Null = (_: NullProps) => { + return null; +}; + +export default Null; diff --git a/ui/src/components/workflow/designer/components/TryCatchCollapse.tsx b/ui/src/components/workflow/designer/components/TryCatchCollapse.tsx new file mode 100644 index 000000000..77f68d38a --- /dev/null +++ b/ui/src/components/workflow/designer/components/TryCatchCollapse.tsx @@ -0,0 +1,69 @@ +import { useState } from "react"; +import { + type CustomLabelProps, + FlowNodeRenderData, + FlowNodeTransformData, + FlowRendererRegistry, + FlowTextKey, + useBaseColor, +} from "@flowgram.ai/fixed-layout-editor"; + +export interface TryCatchCollapseProps extends CustomLabelProps {} + +const TryCatchCollapse = ({ node, ...props }: TryCatchCollapseProps) => { + const { baseColor, baseActivatedColor } = useBaseColor(); + + const nodeActivateData = node.getData(FlowNodeRenderData)!; + const nodeTransformData = node.getData(FlowNodeTransformData)!; + + const [hoverActivated, setHoverActivated] = useState(false); + + const handleMouseEnter = () => { + setHoverActivated(true); + nodeActivateData.activated = true; + }; + + const handleMouseLeave = () => { + setHoverActivated(false); + nodeActivateData.activated = false; + }; + + if (!nodeTransformData || !nodeTransformData.parent) { + return <>; + } + + const width = nodeTransformData.inputPoint.x - nodeTransformData.parent.inputPoint.x; + const height = 40; + return ( +
+
+ {node.getService(FlowRendererRegistry).getText(FlowTextKey.CATCH_TEXT)} +
+ + {/* {renderCollapse()} */} +
+ ); +}; + +export default TryCatchCollapse; diff --git a/ui/src/components/workflow/designer/components/index.ts b/ui/src/components/workflow/designer/components/index.ts new file mode 100644 index 000000000..90fb868a3 --- /dev/null +++ b/ui/src/components/workflow/designer/components/index.ts @@ -0,0 +1,30 @@ +import { FlowRendererKey } from "@flowgram.ai/fixed-layout-editor"; + +import Adder from "./Adder"; +import BranchAdder from "./BranchAdder"; +import Collapse from "./Collapse"; +import DraggingAdder from "./DraggingAdder"; +import DragHighlightAdder from "./DragHighlightAdder"; +import DragNode from "./DragNode"; +import Null from "./Null"; +import TryCatchCollapse from "./TryCatchCollapse"; + +export const getFlowComponents = () => { + return { + [FlowRendererKey.ADDER]: Adder, + [FlowRendererKey.BRANCH_ADDER]: BranchAdder, + [FlowRendererKey.SLOT_ADDER]: Null, + + [FlowRendererKey.COLLAPSE]: Collapse, + [FlowRendererKey.TRY_CATCH_COLLAPSE]: TryCatchCollapse, + [FlowRendererKey.SLOT_COLLPASE]: Null, + + [FlowRendererKey.DRAG_NODE]: DragNode, + [FlowRendererKey.DRAG_HIGHLIGHT_ADDER]: DragHighlightAdder, + [FlowRendererKey.DRAG_BRANCH_HIGHLIGHT_ADDER]: DragHighlightAdder, + [FlowRendererKey.DRAGGABLE_ADDER]: DraggingAdder, + + [FlowRendererKey.CONTEXT_MENU_POPOVER]: Null, + [FlowRendererKey.SELECTOR_BOX_POPOVER]: Null, + }; +}; diff --git a/ui/src/components/workflow/designer/flowgram.css b/ui/src/components/workflow/designer/flowgram.css new file mode 100644 index 000000000..0e4ac1936 --- /dev/null +++ b/ui/src/components/workflow/designer/flowgram.css @@ -0,0 +1,22 @@ +/* 隐藏 flowgram 的标签背景 */ +/* flowgram 暂未提供相关配置项,这里需与 antd.colorBgContainer 保持一致 */ +:root { + --g-editor-background: #fff; +} +.dark { + --g-editor-background: #262c2d; +} + +/* 隐藏 flowgram 的折叠按钮 */ +.flow-canvas-collapse-adder > .flow-canvas-collapse { + display: hidden !important; + position: absolute !important; + top: -99999px !important; + left: -99999px !important; +} + +/* 控制 flowgram 线条样式 */ +/* flowgram 暂未提供相关配置项 */ +.flow-lines-container { + stroke-width: 1.5px; +} diff --git a/ui/src/components/workflow/designer/nodes/BusinessNode.tsx b/ui/src/components/workflow/designer/nodes/BusinessNode.tsx new file mode 100644 index 000000000..af9288615 --- /dev/null +++ b/ui/src/components/workflow/designer/nodes/BusinessNode.tsx @@ -0,0 +1,206 @@ +import { getI18n } from "react-i18next"; +import { IconCloudUpload, IconContract, IconDeviceDesktopSearch, IconPackage, IconSend } from "@tabler/icons-react"; +import { Avatar, Typography } from "antd"; +import { nanoid } from "nanoid"; + +import { deploymentProvidersMap, notificationProvidersMap } from "@/domain/provider"; + +import { BaseNode } from "./_shared"; +import { type NodeRegistry, NodeType } from "./typings"; + +export const BizApplyNodeRegistry: NodeRegistry = { + type: NodeType.BizApply, + + meta: { + helpText: getI18n().t("workflow_node.apply.help"), + + icon: IconContract, + iconColor: "#fff", + iconBgColor: "#5b65f5", + }, + + formMeta: { + render: ({ form }) => { + const { t } = getI18n(); + + const fieldDomains = form.getValueIn("config.domains"); + + return {fieldDomains ? fieldDomains.split(";").join("; ") : t("workflow.detail.design.nodes.placeholder")}; + }, + }, + + onAdd: () => { + const { t } = getI18n(); + + return { + id: nanoid(), + type: NodeType.BizApply, + data: { + name: t("workflow_node.apply.default_name"), + }, + }; + }, +}; + +export const BizUploadNodeRegistry: NodeRegistry = { + type: NodeType.BizUpload, + + meta: { + helpText: getI18n().t("workflow_node.upload.help"), + + icon: IconCloudUpload, + iconColor: "#fff", + iconBgColor: "#5b65f5", + }, + + formMeta: { + render: ({ form }) => { + const { t } = getI18n(); + + const fieldDomains = form.getValueIn("config.domains"); + + return {fieldDomains ? fieldDomains.split(";").join("; ") : t("workflow.detail.design.nodes.placeholder")}; + }, + }, + + onAdd: () => { + const { t } = getI18n(); + + return { + id: nanoid(), + type: NodeType.BizUpload, + data: { + name: t("workflow_node.upload.default_name"), + }, + }; + }, +}; + +export const BizMonitorNodeRegistry: NodeRegistry = { + type: NodeType.BizMonitor, + + meta: { + helpText: getI18n().t("workflow_node.monitor.help"), + + icon: IconDeviceDesktopSearch, + iconColor: "#fff", + iconBgColor: "#5b65f5", + }, + + formMeta: { + render: ({ form }) => { + const { t } = getI18n(); + + const fieldDomain = form.getValueIn("config.domain"); + const fieldHost = form.getValueIn("config.host"); + + return {fieldDomain || fieldHost ? fieldDomain || fieldHost : t("workflow.detail.design.nodes.placeholder")}; + }, + }, + + onAdd: () => { + const { t } = getI18n(); + + return { + id: nanoid(), + type: NodeType.BizMonitor, + data: { + name: t("workflow_node.monitor.default_name"), + }, + }; + }, +}; + +export const BizDeployNodeRegistry: NodeRegistry = { + type: NodeType.BizDeploy, + + meta: { + helpText: getI18n().t("workflow_node.deploy.help"), + + icon: IconPackage, + iconColor: "#fff", + iconBgColor: "#5b65f5", + }, + + formMeta: { + render: ({ form }) => { + const { t } = getI18n(); + + const fieldProvider = form.getValueIn("config.provider"); + + return ( + +
+ {fieldProvider ? ( + <> +
{t(deploymentProvidersMap.get(fieldProvider)?.name ?? "")}
+ + + ) : ( + t("workflow.detail.design.nodes.placeholder") + )} +
+
+ ); + }, + }, + + onAdd: () => { + const { t } = getI18n(); + + return { + id: nanoid(), + type: NodeType.BizMonitor, + data: { + name: t("workflow_node.deploy.default_name"), + }, + }; + }, +}; + +export const BizNotifyNodeRegistry: NodeRegistry = { + type: NodeType.BizNotify, + + meta: { + helpText: getI18n().t("workflow_node.notify.help"), + + icon: IconSend, + iconColor: "#fff", + iconBgColor: "#0693d4", + }, + + formMeta: { + render: ({ form }) => { + const { t } = getI18n(); + + const fieldProvider = form.getValueIn("config.provider"); + + return ( + +
+ {fieldProvider ? ( + <> +
{t(notificationProvidersMap.get(fieldProvider)?.name ?? "")}
+ + + ) : ( + t("workflow.detail.design.nodes.placeholder") + )} +
+
+ ); + }, + }, + + onAdd: () => { + const { t } = getI18n(); + + return { + id: nanoid(), + type: NodeType.BizNotify, + data: { + name: t("workflow_node.notify.default_name"), + }, + }; + }, +}; diff --git a/ui/src/components/workflow/designer/nodes/ConditionNode.tsx b/ui/src/components/workflow/designer/nodes/ConditionNode.tsx new file mode 100644 index 000000000..71f106c9d --- /dev/null +++ b/ui/src/components/workflow/designer/nodes/ConditionNode.tsx @@ -0,0 +1,108 @@ +import { getI18n } from "react-i18next"; +import { FlowNodeBaseType, FlowNodeSplitType, ValidateTrigger } from "@flowgram.ai/fixed-layout-editor"; +import { IconFilter, IconFilterFilled, IconSitemap } from "@tabler/icons-react"; +import { nanoid } from "nanoid"; + +import { BaseNode, BlockNode } from "./_shared"; +import { type NodeRegistry, NodeType } from "./typings"; + +export const ConditionNodeRegistry: NodeRegistry = { + type: NodeType.Condition, + + extend: FlowNodeSplitType.DYNAMIC_SPLIT, + + meta: { + helpText: getI18n().t("workflow_node.condition.help"), + + icon: IconSitemap, + iconColor: "#fff", + iconBgColor: "#373c43", + + expandable: false, + }, + + formMeta: { + validateTrigger: ValidateTrigger.onChange, + render: () => { + return ; + }, + }, + + onAdd() { + const { t } = getI18n(); + + return { + id: nanoid(), + type: NodeType.Condition, + data: { + name: t("workflow_node.condition.default_name"), + }, + blocks: [ + { + id: nanoid(), + type: NodeType.BranchBlock, + blocks: [], + data: { + name: t("workflow_node.branch_block.default_name") + " 1", + }, + }, + { + id: nanoid(), + type: NodeType.BranchBlock, + data: { + name: t("workflow_node.branch_block.default_name") + " 2", + }, + }, + ], + }; + }, +}; + +export const BranchBlockNodeRegistry: NodeRegistry = { + type: NodeType.BranchBlock, + + extend: FlowNodeBaseType.BLOCK, + + meta: { + addDisable: true, + copyDisable: true, + }, + + formMeta: { + validateTrigger: ValidateTrigger.onChange, + render: ({ form }) => { + const fieldExpr = form.getValueIn("config.expression"); + + return ( + +
+
+ {fieldExpr ? : } +
+
{form.getValueIn("name") || "\u00A0"}
+
+
+ ); + }, + }, + + canAdd: () => { + return false; + }, + + canDelete: (_, node) => { + return node.parent!.blocks.length >= 2; + }, + + onAdd() { + const { t } = getI18n(); + + return { + id: nanoid(), + type: NodeType.BranchBlock, + data: { + name: t("workflow_node.branch_block.default_name"), + }, + }; + }, +}; diff --git a/ui/src/components/workflow/designer/nodes/EndNode.tsx b/ui/src/components/workflow/designer/nodes/EndNode.tsx new file mode 100644 index 000000000..c47b23755 --- /dev/null +++ b/ui/src/components/workflow/designer/nodes/EndNode.tsx @@ -0,0 +1,75 @@ +import { getI18n } from "react-i18next"; +import { FlowNodeBaseType } from "@flowgram.ai/fixed-layout-editor"; +import { IconLogout } from "@tabler/icons-react"; +import { nanoid } from "nanoid"; + +import { BaseNode } from "./_shared"; +import { type NodeRegistry, NodeType } from "./typings"; + +export const EndNodeRegistry: NodeRegistry = { + type: NodeType.End, + + meta: { + helpText: getI18n().t("workflow_node.end.help"), + + icon: IconLogout, + iconColor: "#fff", + iconBgColor: "#336df4", + + isNodeEnd: true, + + expandable: false, + selectable: false, + + copyDisable: true, + }, + + formMeta: { + render: () => { + return ; + }, + }, + + canAdd(_, from) { + // You can only add to the last node of the branch + if (!from.isLast) return false; + + /** + * condition + * blockIcon + * inlineBlocks + * block1 + * blockOrderIcon + * <---- [add end] + * block2 + * blockOrderIcon + * end + */ + // originParent can determine whether it is condition , and then determine whether it is the last one + // https://github.com/bytedance/flowgram.ai/pull/146 + if (from.parent && from.parent.parent?.flowNodeType === FlowNodeBaseType.INLINE_BLOCKS && from.parent.originParent && !from.parent.originParent.isLast) { + const allBranches = from.parent.parent!.blocks; + // Determine whether the last node of all branch is end, All branches are not allowed to be end + const branchEndCount = allBranches.filter((block) => block.blocks[block.blocks.length - 1]?.getNodeMeta().isNodeEnd).length; + return branchEndCount < allBranches.length - 1; + } + + return true; + }, + + canDelete(ctx, node) { + return node.parent !== ctx.document.root; + }, + + onAdd() { + const { t } = getI18n(); + + return { + id: nanoid(), + type: NodeType.End, + data: { + name: t("workflow_node.end.default_name"), + }, + }; + }, +}; diff --git a/ui/src/components/workflow/designer/nodes/StartNode.tsx b/ui/src/components/workflow/designer/nodes/StartNode.tsx new file mode 100644 index 000000000..5b14291b7 --- /dev/null +++ b/ui/src/components/workflow/designer/nodes/StartNode.tsx @@ -0,0 +1,67 @@ +import { getI18n } from "react-i18next"; +import { IconRocket } from "@tabler/icons-react"; +import { Typography } from "antd"; + +import { WORKFLOW_TRIGGERS } from "@/domain/workflow"; + +import { BaseNode } from "./_shared"; +import { type NodeRegistry, NodeType } from "./typings"; + +export const StartNodeRegistry: NodeRegistry = { + type: NodeType.Start, + + meta: { + helpText: getI18n().t("workflow_node.start.help"), + + icon: IconRocket, + iconColor: "#fff", + iconBgColor: "#ed6d0c", + + isStart: true, + + expandable: false, + selectable: false, + + addDisable: true, + copyDisable: true, + deleteDisable: true, + }, + + formMeta: { + render: ({ form }) => { + const { t } = getI18n(); + + const fieldTrigger = form.getValueIn("config.trigger"); + const fieldTriggerCron = form.getValueIn("config.triggerCron"); + + return ( + +
+ {fieldTrigger ? ( + <> +
+ {fieldTrigger === WORKFLOW_TRIGGERS.SCHEDULED + ? t("workflow.props.trigger.scheduled") + : fieldTrigger === WORKFLOW_TRIGGERS.MANUAL + ? t("workflow.props.trigger.manual") + : "\u00A0"} +
+
{fieldTrigger === WORKFLOW_TRIGGERS.SCHEDULED ? fieldTriggerCron || "\u00A0" : ""}
+ + ) : ( + t("workflow.detail.design.nodes.placeholder") + )} +
+
+ ); + }, + }, + + canAdd: () => { + return false; + }, + + canDelete: () => { + return false; + }, +}; diff --git a/ui/src/components/workflow/designer/nodes/TryCatchNode.tsx b/ui/src/components/workflow/designer/nodes/TryCatchNode.tsx new file mode 100644 index 000000000..c4b0d7add --- /dev/null +++ b/ui/src/components/workflow/designer/nodes/TryCatchNode.tsx @@ -0,0 +1,105 @@ +import { getI18n } from "react-i18next"; +import { ValidateTrigger } from "@flowgram.ai/fixed-layout-editor"; +import { IconArrowsSplit, IconCircleX } from "@tabler/icons-react"; +import { nanoid } from "nanoid"; + +import { BaseNode, BlockNode } from "./_shared"; +import { type NodeRegistry, NodeType } from "./typings"; + +export const TryCatchNodeRegistry: NodeRegistry = { + type: NodeType.TryCatch, + + meta: { + helpText: getI18n().t("workflow_node.try_catch.help"), + + icon: IconArrowsSplit, + iconColor: "#fff", + iconBgColor: "#373c43", + + expandable: false, + }, + + formMeta: { + validateTrigger: ValidateTrigger.onChange, + render: () => { + return ; + }, + }, + + onAdd() { + const { t } = getI18n(); + + return { + id: nanoid(), + type: NodeType.TryCatch, + data: { + name: t("workflow_node.try_catch.default_name"), + }, + blocks: [ + { + id: nanoid(), + type: NodeType.TryBlock, + blocks: [], + }, + { + id: nanoid(), + type: NodeType.CatchBlock, + blocks: [ + { + id: nanoid(), + type: NodeType.End, + data: { + name: t("workflow_node.end.default_name"), + }, + }, + ], + data: { + name: t("workflow_node.catch_block.default_name"), + }, + }, + ], + }; + }, +}; + +export const CatchBlockNodeRegistry: NodeRegistry = { + type: NodeType.CatchBlock, + + meta: { + addDisable: true, + copyDisable: true, + }, + + formMeta: { + validateTrigger: ValidateTrigger.onChange, + render: ({ form }) => { + return ( + +
+
+ +
+
{form.getValueIn("name") || "\u00A0"}
+
+
+ ); + }, + }, + + canAdd: () => false, + + canDelete: (_, node) => node.parent != null && node.parent.blocks.length >= 2, + + onAdd() { + const { t } = getI18n(); + + return { + id: nanoid(), + type: NodeType.CatchBlock, + blocks: [], + data: { + name: t("workflow_node.catch_block.default_name"), + }, + }; + }, +}; diff --git a/ui/src/components/workflow/designer/nodes/_example.ts b/ui/src/components/workflow/designer/nodes/_example.ts new file mode 100644 index 000000000..cd6bc972f --- /dev/null +++ b/ui/src/components/workflow/designer/nodes/_example.ts @@ -0,0 +1,63 @@ +import { type FlowNodeRegistry } from "@flowgram.ai/fixed-layout-editor"; +import { nanoid } from "nanoid"; + +/** + * 自定义节点注册 + */ +export const nodeRegistry: FlowNodeRegistry = { + /** + * 自定义节点类型 + */ + type: "condition", + + /** + * 自定义节点扩展: + * - loop: 扩展为循环节点 + * - start: 扩展为开始节点 + * - dynamicSplit: 扩展为分支节点 + * - end: 扩展为结束节点 + * - tryCatch: 扩展为 tryCatch 节点 + * - break: 分支断开 + * - default: 扩展为普通节点 (默认) + */ + extend: "dynamicSplit", + + /** + * 节点配置信息 + */ + meta: { + isStart: false, // 是否为开始节点 + isNodeEnd: false, // 是否为结束节点,结束节点后边无法再添加节点 + draggable: false, // 是否可拖拽,如开始节点和结束节点无法拖拽 + selectable: false, // 触发器等开始节点不能被框选 + deleteDisable: true, // 禁止删除 + copyDisable: true, // 禁止copy + addDisable: true, // 禁止添加 + }, + + onAdd() { + return { + id: `condition_${nanoid(5)}`, + type: "condition", + data: { + title: "Condition", + }, + blocks: [ + { + id: nanoid(5), + type: "block", + data: { + title: "If_0", + }, + }, + { + id: nanoid(5), + type: "block", + data: { + title: "If_1", + }, + }, + ], + }; + }, +}; diff --git a/ui/src/components/workflow/designer/nodes/_shared.tsx b/ui/src/components/workflow/designer/nodes/_shared.tsx new file mode 100644 index 000000000..a9bd61bdb --- /dev/null +++ b/ui/src/components/workflow/designer/nodes/_shared.tsx @@ -0,0 +1,161 @@ +import { useMemo } from "react"; +import { useTranslation } from "react-i18next"; +import { useClientContext, useNodeRender } from "@flowgram.ai/fixed-layout-editor"; +import { IconCopy, IconDotsVertical, IconGripVertical, IconLabel, IconX } from "@tabler/icons-react"; +import { Button, type ButtonProps, Card, Dropdown, type MenuProps, Popover, Tooltip, Typography, theme } from "antd"; +import { mergeCls } from "@/utils/css"; + +import { type NodeRegistry } from "./typings"; + +export const BaseNode = ({ className, style, children }: { className?: string; style?: React.CSSProperties; children?: React.ReactNode }) => { + const { token: themeToken } = theme.useToken(); + + const ctx = useClientContext(); + const { playground } = ctx; + + const nodeRender = useNodeRender(); + const nodeRegistry = nodeRender.node.getNodeRegistry(); + + const NodeIcon = nodeRegistry.meta?.icon; + const renderNodeIcon = () => { + return NodeIcon == null ? null : ( +
+ +
+ ); + }; + + return ( +
+ +
+ {nodeRegistry.meta?.helpText == null ? ( + renderNodeIcon() + ) : ( + } mouseEnterDelay={1}> +
{renderNodeIcon()}
+
+ )} +
+
+ {nodeRender.data?.name || "\u00A0"} +
+ {children != null && ( +
+ {children} +
+ )} +
+
e.stopPropagation()}> + +
+
+
+ {!playground.config.readonlyOrDisabled && nodeRegistry.meta?.draggable === true && ( +
+ +
+ )} +
+ ); +}; + +export const BlockNode = ({ className, style, children }: { className?: string; style?: React.CSSProperties; children?: React.ReactNode }) => { + const ctx = useClientContext(); + const { playground } = ctx; + + const nodeRender = useNodeRender(); + const nodeRegistry = nodeRender.node.getNodeRegistry(); + + return ( + } placement="right"> +
+ +
+
{children ?? (nodeRender.data?.name || "\u00A0")}
+
+
+ {!playground.config.readonlyOrDisabled && nodeRegistry.meta?.draggable === true && ( +
+ +
+ )} +
+
+ ); +}; + +export const NodeMenuButton = ({ className, style, ...props }: ButtonProps) => { + const ctx = useClientContext(); + const { playground } = ctx; + + const menuItems = useNodeMenuItems(); + + return playground.config.readonlyOrDisabled ? null : ( + + - + +
+ + +
+
@@ -152,7 +171,7 @@ const WorkflowDetailBaseName = () => { const { notification } = App.useApp(); - const { workflow, setBaseInfo: setWorkflowBaseInfo } = useWorkflowStore(useZustandShallowSelector(["workflow", "setBaseInfo"])); + const { workflow, initialized, setBaseInfo: setWorkflowBaseInfo } = useWorkflowStore(useZustandShallowSelector(["workflow", "initialized", "setBaseInfo"])); const inputRef = useRef(null); @@ -194,7 +213,7 @@ const WorkflowDetailBaseName = () => { }; return ( -
+

{ > {workflow.name || "\u00A0"}

- - , - onClick: handleRollbackClick, - }, - ], - }} - trigger={["click"]} - > - + , + onClick: handleRollbackClick, + }, + ], + }} + trigger={["click"]} + > +
+
- - - +
+
+
+ +
+
+
+ ); }; +const compactWorkflowDraft = (root: WorkflowNode | undefined) => { + const { t } = getI18n(); + + // TODO: 仅为兼容适配 v0.3.x 数据,正式上线后待删除 + const res: FlowDocumentJSON["nodes"] = []; + + if (!root) { + res.push({ + id: nanoid(), + type: "start", + data: { + name: "Start", + }, + }); + } else { + const convert = (node: WorkflowNode | undefined) => { + const temp: typeof res = []; + + let current: typeof node = node; + while (current) { + switch (current.type) { + case WorkflowNodeType.Start: + temp.push({ + id: current.id, + type: "start", + data: { + name: current.name, + config: current.config, + }, + }); + break; + + case WorkflowNodeType.Apply: + temp.push({ + id: current.id, + type: "bizApply", + data: { + name: current.name, + config: current.config, + }, + }); + break; + + case WorkflowNodeType.Upload: + temp.push({ + id: current.id, + type: "bizUpload", + data: { + name: current.name, + config: current.config, + }, + }); + break; + + case WorkflowNodeType.Monitor: + temp.push({ + id: current.id, + type: "bizMonitor", + data: { + name: current.name, + config: current.config, + }, + }); + break; + + case WorkflowNodeType.Deploy: + temp.push({ + id: current.id, + type: "bizDeploy", + data: { + name: current.name, + config: current.config, + }, + }); + break; + + case WorkflowNodeType.Notify: + temp.push({ + id: current.id, + type: "bizNotify", + data: { + name: current.name, + config: current.config, + }, + }); + break; + + case WorkflowNodeType.ExecuteResultBranch: { + const tryNode = temp.pop()!; + temp.push({ + id: current.id, + type: "tryCatch", + blocks: [ + { + id: current.branches?.find((b) => b.type === WorkflowNodeType.ExecuteSuccess)?.id || nanoid(), + type: "tryBlock", + blocks: [tryNode], + data: { + name: current.branches?.find((b) => b.type === WorkflowNodeType.ExecuteSuccess)?.name, + }, + }, + { + id: current.branches?.find((b) => b.type === WorkflowNodeType.ExecuteFailure)?.id || nanoid(), + type: "catchBlock", + blocks: [ + ...convert(current.branches?.find((b) => b.type === WorkflowNodeType.ExecuteFailure)?.next), + { + id: nanoid(), + type: "end", + data: { + name: t("workflow_node.end.default_name"), + }, + }, + ], + data: { + name: current.branches?.find((b) => b.type === WorkflowNodeType.ExecuteFailure)?.name, + }, + }, + ], + data: { + name: current.name, + config: current.config, + }, + }); + + current = current.branches?.find((b) => b.type === WorkflowNodeType.ExecuteSuccess); + break; + } + + case WorkflowNodeType.Branch: { + temp.push({ + id: current.id, + type: "condition", + blocks: + current.branches?.map((branch) => { + return { + id: branch.id, + type: "branchBlock", + blocks: convert(branch.next), + data: { + name: branch.name, + config: branch.config, + }, + }; + }) ?? [], + data: { + name: current.name, + config: current.config, + }, + }); + break; + } + } + + current = current?.next; + } + + return temp; + }; + + res.push(...convert(root)); + } + + res.push({ + id: nanoid(), + type: "end", + data: { + name: t("workflow_node.end.default_name"), + }, + }); + + return res; +}; + export default WorkflowDetailDesign; diff --git a/ui/src/pages/workflows/WorkflowDetailDesignLegacy.tsx b/ui/src/pages/workflows/WorkflowDetailDesignLegacy.tsx new file mode 100644 index 000000000..5cb26f08c --- /dev/null +++ b/ui/src/pages/workflows/WorkflowDetailDesignLegacy.tsx @@ -0,0 +1,132 @@ +import { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { IconArrowBackUp, IconDots } from "@tabler/icons-react"; +import { Alert, App, Button, Card, Dropdown, Space } from "antd"; +import { isEqual } from "radash"; + +import Show from "@/components/Show"; +import WorkflowElementsContainer from "@/components/workflow/WorkflowElementsContainer"; +import { isAllNodesValidated } from "@/domain/workflow"; +import { WORKFLOW_RUN_STATUSES } from "@/domain/workflowRun"; +import { useZustandShallowSelector } from "@/hooks"; +import { useWorkflowStore } from "@/stores/workflow"; +import { getErrMsg } from "@/utils/error"; + +const WorkflowDetailDesign = () => { + const { t } = useTranslation(); + + const { message, modal, notification } = App.useApp(); + + const { workflow, ...workflowState } = useWorkflowStore(useZustandShallowSelector(["workflow", "init", "publish", "rollback"])); + + const [isPendingOrRunning, setIsPendingOrRunning] = useState(false); + const [allowRollback, setAllowRollback] = useState(false); + const [allowPublish, setAllowPublish] = useState(false); + + useEffect(() => { + const pending = workflow.lastRunStatus === WORKFLOW_RUN_STATUSES.PENDING || workflow.lastRunStatus === WORKFLOW_RUN_STATUSES.RUNNING; + setIsPendingOrRunning(pending); + }, [workflow]); + + useEffect(() => { + const hasContent = !!workflow.content; + const hasChanges = workflow.hasDraft! || !isEqual(workflow.draft, workflow.content); + setAllowRollback(!isPendingOrRunning && hasContent && hasChanges); + setAllowPublish(!isPendingOrRunning && hasChanges); + }, [workflow.content, workflow.draft, workflow.hasDraft, isPendingOrRunning]); + + const handleRollbackClick = () => { + modal.confirm({ + title: t("workflow.action.rollback.modal.title"), + content: t("workflow.action.rollback.modal.content"), + onOk: async () => { + try { + await workflowState.rollback(); + + message.success(t("common.text.operation_succeeded")); + } catch (err) { + console.error(err); + notification.error({ message: t("common.text.request_error"), description: getErrMsg(err) }); + } + }, + }); + }; + + const handlePublishClick = () => { + if (!isAllNodesValidated(workflow.draft!)) { + message.warning(t("workflow.action.publish.errmsg.uncompleted")); + return; + } + + modal.confirm({ + title: t("workflow.action.publish.modal.title"), + content: t("workflow.action.publish.modal.content"), + onOk: async () => { + try { + await workflowState.publish(); + + message.success(t("common.text.operation_succeeded")); + } catch (err) { + console.error(err); + notification.error({ message: t("common.text.request_error"), description: getErrMsg(err) }); + } + }, + }); + }; + + return ( +
+ +
+
+
+
+
+
+ + {t("workflow.detail.design.unpublished_draft.alert")}
} showIcon type="warning" /> + +
+ + + , + onClick: handleRollbackClick, + }, + ], + }} + trigger={["click"]} + > +
+
+
+
+ + +
+ + + ); +}; + +export default WorkflowDetailDesign; diff --git a/ui/src/pages/workflows/WorkflowDetailRuns.tsx b/ui/src/pages/workflows/WorkflowDetailRuns.tsx index f5950da80..1aa551ed0 100644 --- a/ui/src/pages/workflows/WorkflowDetailRuns.tsx +++ b/ui/src/pages/workflows/WorkflowDetailRuns.tsx @@ -1,8 +1,8 @@ import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; -import { IconBrowserShare, IconHistory, IconPlayerPause, IconTrash } from "@tabler/icons-react"; +import { IconBrowserShare, IconDotsVertical, IconHistory, IconPlayerPause, IconTrash } from "@tabler/icons-react"; import { useRequest } from "ahooks"; -import { Alert, App, Button, Skeleton, Table, type TableProps, Tooltip } from "antd"; +import { Alert, App, Button, Dropdown, Skeleton, Table, type TableProps, Tooltip } from "antd"; import dayjs from "dayjs"; import { ClientResponseError } from "pocketbase"; @@ -98,53 +98,63 @@ const WorkflowDetailRuns = () => { key: "$action", align: "end", fixed: "right", - width: 120, + width: 64, render: (_, record) => { - const allowCancel = record.status === WORKFLOW_RUN_STATUSES.PENDING || record.status === WORKFLOW_RUN_STATUSES.RUNNING; - const aloowDelete = - record.status === WORKFLOW_RUN_STATUSES.SUCCEEDED || - record.status === WORKFLOW_RUN_STATUSES.FAILED || - record.status === WORKFLOW_RUN_STATUSES.CANCELED; + const cancelDisabled = !([WORKFLOW_RUN_STATUSES.PENDING, WORKFLOW_RUN_STATUSES.RUNNING] as string[]).includes(record.status); + const deleteDisabled = !cancelDisabled; return ( -
- -
+ + + + ), + onClick: () => { + handleRecordDetailClick(record); + }, + }, + { + key: "cancel", + label: t("workflow_run.action.cancel.button"), + icon: ( + + + + ), + disabled: cancelDisabled, + onClick: () => { + handleRecordCancelClick(record); + }, + }, + { + type: "divider", + }, + { + key: "delete", + label: t("workflow_run.action.delete.button"), + icon: ( + + + + ), + danger: true, + disabled: deleteDisabled, + onClick: () => { + handleRecordDeleteClick(record); + }, + }, + ], + }} + trigger={["click"]} + > +