From 0a76d336a8ea8dc041cbf2ca893b2ba6d5be50e2 Mon Sep 17 00:00:00 2001 From: Philipp Reinking Date: Sat, 21 Sep 2024 13:31:41 +0200 Subject: [PATCH 01/43] update sidebar block --- package-lock.json | 262 +++++++----------- package.json | 8 +- .../js/components/Factory/Main/BlockType.vue | 15 +- .../js/components/Factory/Sidebar/Block.vue | 74 ++++- resources/js/stores/form.ts | 14 +- 5 files changed, 176 insertions(+), 197 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0a8c9669..29f2ed39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "2.0.1", "license": "GNU Affero General Public License v3.0", "dependencies": { - "@deck9/ui": "^0.15.0", + "@deck9/ui": "^0.15.1", "@headlessui/vue": "^1.7.23", "@highlightjs/vue-plugin": "^2.1.0", "@inertiajs/vue3": "^1.2.0", @@ -26,8 +26,8 @@ "@tiptap/vue-3": "^2.7.2", "@types/lodash": "^4.17.7", "@types/node": "^22.5.5", - "@typescript-eslint/eslint-plugin": "^8.5.0", - "@typescript-eslint/parser": "^8.5.0", + "@typescript-eslint/eslint-plugin": "^8.6.0", + "@typescript-eslint/parser": "^8.6.0", "@vitejs/plugin-vue": "^5.1.4", "@vueuse/core": "^11.1.0", "autoprefixer": "^10.4.20", @@ -63,7 +63,7 @@ "prettier": "^3.3.3", "prettier-eslint": "^16.3.0", "prettier-plugin-tailwindcss": "^0.6.6", - "puppeteer": "^23.3.0", + "puppeteer": "^23.4.0", "tailwind-config-viewer": "^2.0.4", "vite": "^5.4.6", "vitest": "^2.1.1" @@ -318,10 +318,9 @@ } }, "node_modules/@deck9/ui": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@deck9/ui/-/ui-0.15.0.tgz", - "integrity": "sha512-O3biiHnY/gjNQ77XkJzNEDkz1sEJ3Ory60h18aY4isX/ck8q9/3lnlmn1XfnWEwix9BuUkGMvpdLkrl+qY3Z0A==", - "license": "MIT", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@deck9/ui/-/ui-0.15.1.tgz", + "integrity": "sha512-UnJO4l+BTsj/gj7RvBmA57BP8u/AA973bh9A3dMPvBM8A75ISTnWCPes9C5IYh8ZaiohSCbx4dMameZliEsRgQ==", "dependencies": { "@deck9/tailwindcss-recursive-font-helper": "^1.0.1", "@floating-ui/vue": "^1.0.4", @@ -1454,7 +1453,6 @@ "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.4.0.tgz", "integrity": "sha512-x8J1csfIygOwf6D6qUAZ0ASk3z63zPb7wkNeHRerCMh82qWKUrOgkuP005AJC8lDL6/evtXETGEJVcwykKT4/g==", "dev": true, - "license": "Apache-2.0", "dependencies": { "debug": "^4.3.6", "extract-zip": "^2.0.1", @@ -2225,8 +2223,7 @@ "version": "0.23.0", "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/cookie": { "version": "0.4.1", @@ -2286,23 +2283,21 @@ "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", "dev": true, - "license": "MIT", "optional": true, "dependencies": { "@types/node": "*" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.5.0.tgz", - "integrity": "sha512-lHS5hvz33iUFQKuPFGheAB84LwcJ60G8vKnEhnfcK1l8kGVLro2SFYW6K0/tj8FUhRJ0VHyg1oAfg50QGbPPHw==", - "license": "MIT", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.6.0.tgz", + "integrity": "sha512-UOaz/wFowmoh2G6Mr9gw60B1mm0MzUtm6Ic8G2yM1Le6gyj5Loi/N+O5mocugRGY+8OeeKmkMmbxNqUCq3B4Sg==", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.5.0", - "@typescript-eslint/type-utils": "8.5.0", - "@typescript-eslint/utils": "8.5.0", - "@typescript-eslint/visitor-keys": "8.5.0", + "@typescript-eslint/scope-manager": "8.6.0", + "@typescript-eslint/type-utils": "8.6.0", + "@typescript-eslint/utils": "8.6.0", + "@typescript-eslint/visitor-keys": "8.6.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -2326,15 +2321,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.5.0.tgz", - "integrity": "sha512-gF77eNv0Xz2UJg/NbpWJ0kqAm35UMsvZf1GHj8D9MRFTj/V3tAciIWXfmPLsAAF/vUlpWPvUDyH1jjsr0cMVWw==", - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/scope-manager": "8.5.0", - "@typescript-eslint/types": "8.5.0", - "@typescript-eslint/typescript-estree": "8.5.0", - "@typescript-eslint/visitor-keys": "8.5.0", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.6.0.tgz", + "integrity": "sha512-eQcbCuA2Vmw45iGfcyG4y6rS7BhWfz9MQuk409WD47qMM+bKCGQWXxvoOs1DUp+T7UBMTtRTVT+kXr7Sh4O9Ow==", + "dependencies": { + "@typescript-eslint/scope-manager": "8.6.0", + "@typescript-eslint/types": "8.6.0", + "@typescript-eslint/typescript-estree": "8.6.0", + "@typescript-eslint/visitor-keys": "8.6.0", "debug": "^4.3.4" }, "engines": { @@ -2354,13 +2348,12 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.5.0.tgz", - "integrity": "sha512-06JOQ9Qgj33yvBEx6tpC8ecP9o860rsR22hWMEd12WcTRrfaFgHr2RB/CA/B+7BMhHkXT4chg2MyboGdFGawYg==", - "license": "MIT", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.6.0.tgz", + "integrity": "sha512-ZuoutoS5y9UOxKvpc/GkvF4cuEmpokda4wRg64JEia27wX+PysIE9q+lzDtlHHgblwUWwo5/Qn+/WyTUvDwBHw==", "dependencies": { - "@typescript-eslint/types": "8.5.0", - "@typescript-eslint/visitor-keys": "8.5.0" + "@typescript-eslint/types": "8.6.0", + "@typescript-eslint/visitor-keys": "8.6.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2371,13 +2364,12 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.5.0.tgz", - "integrity": "sha512-N1K8Ix+lUM+cIDhL2uekVn/ZD7TZW+9/rwz8DclQpcQ9rk4sIL5CAlBC0CugWKREmDjBzI/kQqU4wkg46jWLYA==", - "license": "MIT", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.6.0.tgz", + "integrity": "sha512-dtePl4gsuenXVwC7dVNlb4mGDcKjDT/Ropsk4za/ouMBPplCLyznIaR+W65mvCvsyS97dymoBRrioEXI7k0XIg==", "dependencies": { - "@typescript-eslint/typescript-estree": "8.5.0", - "@typescript-eslint/utils": "8.5.0", + "@typescript-eslint/typescript-estree": "8.6.0", + "@typescript-eslint/utils": "8.6.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -2395,10 +2387,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.5.0.tgz", - "integrity": "sha512-qjkormnQS5wF9pjSi6q60bKUHH44j2APxfh9TQRXK8wbYVeDYYdYJGIROL87LGZZ2gz3Rbmjc736qyL8deVtdw==", - "license": "MIT", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.6.0.tgz", + "integrity": "sha512-rojqFZGd4MQxw33SrOy09qIDS8WEldM8JWtKQLAjf/X5mGSeEFh5ixQlxssMNyPslVIk9yzWqXCsV2eFhYrYUw==", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -2408,13 +2399,12 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.5.0.tgz", - "integrity": "sha512-vEG2Sf9P8BPQ+d0pxdfndw3xIXaoSjliG0/Ejk7UggByZPKXmJmw3GW5jV2gHNQNawBUyfahoSiCFVov0Ruf7Q==", - "license": "BSD-2-Clause", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.6.0.tgz", + "integrity": "sha512-MOVAzsKJIPIlLK239l5s06YXjNqpKTVhBVDnqUumQJja5+Y94V3+4VUFRA0G60y2jNnTVwRCkhyGQpavfsbq/g==", "dependencies": { - "@typescript-eslint/types": "8.5.0", - "@typescript-eslint/visitor-keys": "8.5.0", + "@typescript-eslint/types": "8.6.0", + "@typescript-eslint/visitor-keys": "8.6.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -2439,7 +2429,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -2448,7 +2437,6 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -2460,15 +2448,14 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.5.0.tgz", - "integrity": "sha512-6yyGYVL0e+VzGYp60wvkBHiqDWOpT63pdMV2CVG4LVDd5uR6q1qQN/7LafBZtAtNIn/mqXjsSeS5ggv/P0iECw==", - "license": "MIT", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.6.0.tgz", + "integrity": "sha512-eNp9cWnYf36NaOVjkEUznf6fEgVy1TWpE0o52e4wtojjBx7D1UV2WAWGzR+8Y5lVFtpMLPwNbC67T83DWSph4A==", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.5.0", - "@typescript-eslint/types": "8.5.0", - "@typescript-eslint/typescript-estree": "8.5.0" + "@typescript-eslint/scope-manager": "8.6.0", + "@typescript-eslint/types": "8.6.0", + "@typescript-eslint/typescript-estree": "8.6.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2482,12 +2469,11 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.5.0.tgz", - "integrity": "sha512-yTPqMnbAZJNy2Xq2XU8AdtOW9tJIr+UQb64aXB9f3B1498Zx9JorVgFJcZpEc9UBuCCrdzKID2RGAMkYcDtZOw==", - "license": "MIT", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.6.0.tgz", + "integrity": "sha512-wapVFfZg9H0qOYh4grNVQiMklJGluQrOUiOhYRrQWhx7BY/+I1IYb8BczWNbbUpO+pqy0rDciv3lQH5E1bCLrg==", "dependencies": { - "@typescript-eslint/types": "8.5.0", + "@typescript-eslint/types": "8.6.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -3406,7 +3392,6 @@ "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", "dev": true, - "license": "MIT", "dependencies": { "tslib": "^2.0.1" }, @@ -3500,8 +3485,7 @@ "version": "1.6.6", "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", - "dev": true, - "license": "Apache-2.0" + "dev": true }, "node_modules/balanced-match": { "version": "1.0.2", @@ -3513,15 +3497,13 @@ "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz", "integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==", "dev": true, - "license": "Apache-2.0", "optional": true }, "node_modules/bare-fs": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.3.tgz", - "integrity": "sha512-7RYKL+vZVCyAsMLi5SPu7QGauGGT8avnP/HO571ndEuV4MYdGXvLhtW67FuLPeEI8EiIY7zbbRR9x7x7HU0kgw==", + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.5.tgz", + "integrity": "sha512-SlE9eTxifPDJrT6YgemQ1WGFleevzwY+XAP1Xqgl56HtcrisC2CHCZ2tq6dBpcH2TnNxwUEUGhweo+lrQtYuiw==", "dev": true, - "license": "Apache-2.0", "optional": true, "dependencies": { "bare-events": "^2.0.0", @@ -3530,11 +3512,10 @@ } }, "node_modules/bare-os": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.2.tgz", - "integrity": "sha512-HZoJwzC+rZ9lqEemTMiO0luOePoGYNBgsLLgegKR/cljiJvcDNhDZQkzC+NC5Oh0aHbdBNSOHpghwMuB5tqhjg==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.4.tgz", + "integrity": "sha512-z3UiI2yi1mK0sXeRdc4O1Kk8aOa/e+FNWZcTiPB/dfTWyLypuE99LibgRaQki914Jq//yAWylcAt+mknKdixRQ==", "dev": true, - "license": "Apache-2.0", "optional": true }, "node_modules/bare-path": { @@ -3542,22 +3523,20 @@ "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.3.tgz", "integrity": "sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==", "dev": true, - "license": "Apache-2.0", "optional": true, "dependencies": { "bare-os": "^2.1.0" } }, "node_modules/bare-stream": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.2.1.tgz", - "integrity": "sha512-YTB47kHwBW9zSG8LD77MIBAAQXjU2WjAkMHeeb7hUplVs6+IoM5I7uEVQNPMB7lj9r8I76UMdoMkGnCodHOLqg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.3.0.tgz", + "integrity": "sha512-pVRWciewGUeCyKEuRxwv06M079r+fRjAQjBEK2P6OYGrO43O+Z0LrPZZEjlc4mB6C2RpZ9AxJ1s7NLEtOHO6eA==", "dev": true, - "license": "Apache-2.0", "optional": true, "dependencies": { "b4a": "^1.6.6", - "streamx": "^2.18.0" + "streamx": "^2.20.0" } }, "node_modules/base64-js": { @@ -3578,8 +3557,7 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/base64id": { "version": "2.0.0", @@ -3596,7 +3574,6 @@ "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", "dev": true, - "license": "MIT", "engines": { "node": ">=10.0.0" } @@ -3900,7 +3877,6 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -3911,7 +3887,6 @@ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true, - "license": "MIT", "engines": { "node": "*" } @@ -4090,7 +4065,6 @@ "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.6.5.tgz", "integrity": "sha512-RuLrmzYrxSb0s9SgpB+QN5jJucPduZQ/9SIe76MDxYJuecPW5mxMdacJ1f4EtgiV+R0p3sCkznTMvH0MPGFqjA==", "dev": true, - "license": "Apache-2.0", "dependencies": { "mitt": "3.0.1", "urlpattern-polyfill": "10.0.0", @@ -4104,8 +4078,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/co": { "version": "4.6.0", @@ -4414,7 +4387,6 @@ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 14" } @@ -4511,7 +4483,6 @@ "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", "dev": true, - "license": "MIT", "dependencies": { "ast-types": "^0.13.4", "escodegen": "^2.1.0", @@ -4563,11 +4534,10 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1330662", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1330662.tgz", - "integrity": "sha512-pzh6YQ8zZfz3iKlCvgzVCu22NdpZ8hNmwU6WnQjNVquh0A9iVosPtNLWDwaWVGyrntQlltPFztTMK5Cg6lfCuw==", - "dev": true, - "license": "BSD-3-Clause" + "version": "0.0.1342118", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1342118.tgz", + "integrity": "sha512-75fMas7PkYNDTmDyb6PRJCH7ILmHLp+BhrZGeMsa4bCh40DTxgCz2NRy5UDzII4C5KuD0oBMZ9vXKhEl6UD/3w==", + "dev": true }, "node_modules/didyoumean": { "version": "1.2.2", @@ -4716,7 +4686,6 @@ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, - "license": "MIT", "dependencies": { "once": "^1.4.0" } @@ -4945,7 +4914,6 @@ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "esprima": "^4.0.1", "estraverse": "^5.2.0", @@ -5120,7 +5088,6 @@ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, - "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -5202,7 +5169,6 @@ "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", @@ -5227,8 +5193,7 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/fast-glob": { "version": "3.3.2", @@ -5268,7 +5233,6 @@ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "dev": true, - "license": "MIT", "dependencies": { "pend": "~1.2.0" } @@ -5398,7 +5362,6 @@ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dev": true, - "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -5476,7 +5439,6 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, - "license": "MIT", "dependencies": { "pump": "^3.0.0" }, @@ -5492,7 +5454,6 @@ "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", "dev": true, - "license": "MIT", "dependencies": { "basic-ftp": "^5.0.2", "data-uri-to-buffer": "^6.0.2", @@ -5832,8 +5793,7 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "BSD-3-Clause" + ] }, "node_modules/ignore": { "version": "5.3.2", @@ -5919,7 +5879,6 @@ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", "dev": true, - "license": "MIT", "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" @@ -6284,8 +6243,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/jsdom": { "version": "25.0.0", @@ -6945,7 +6903,6 @@ "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4.0" } @@ -7139,7 +7096,6 @@ "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==", "dev": true, - "license": "MIT", "dependencies": { "@tootallnate/quickjs-emscripten": "^0.23.0", "agent-base": "^7.0.2", @@ -7159,7 +7115,6 @@ "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", "dev": true, - "license": "MIT", "dependencies": { "degenerator": "^5.0.0", "netmask": "^2.0.2" @@ -7314,8 +7269,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/picocolors": { "version": "1.1.0", @@ -7879,7 +7833,6 @@ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -8106,7 +8059,6 @@ "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", "dev": true, - "license": "MIT", "dependencies": { "agent-base": "^7.0.2", "debug": "^4.3.4", @@ -8126,7 +8078,6 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, - "license": "ISC", "engines": { "node": ">=12" } @@ -8144,11 +8095,10 @@ "license": "MIT" }, "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", "dev": true, - "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -8172,18 +8122,17 @@ } }, "node_modules/puppeteer": { - "version": "23.3.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-23.3.0.tgz", - "integrity": "sha512-e2jY8cdWSUGsrLxqGm3hIbJq/UIk1uOY8XY7SM51leXkH7shrIyE91lK90Q9byX6tte+cyL3HKqlWBEd6TjWTA==", + "version": "23.4.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-23.4.0.tgz", + "integrity": "sha512-FxgFFJI7NAsX8uebiEDSjS86vufz9TaqERQHShQT0lCbSRI3jUPEcz/0HdwLiYvfYNsc1zGjqY3NsGZya4PvUA==", "dev": true, "hasInstallScript": true, - "license": "Apache-2.0", "dependencies": { "@puppeteer/browsers": "2.4.0", "chromium-bidi": "0.6.5", "cosmiconfig": "^9.0.0", - "devtools-protocol": "0.0.1330662", - "puppeteer-core": "23.3.0", + "devtools-protocol": "0.0.1342118", + "puppeteer-core": "23.4.0", "typed-query-selector": "^2.12.0" }, "bin": { @@ -8194,16 +8143,15 @@ } }, "node_modules/puppeteer-core": { - "version": "23.3.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-23.3.0.tgz", - "integrity": "sha512-sB2SsVMFs4gKad5OCdv6w5vocvtEUrRl0zQqSyRPbo/cj1Ktbarmhxy02Zyb9R9HrssBcJDZbkrvBnbaesPyYg==", + "version": "23.4.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-23.4.0.tgz", + "integrity": "sha512-fqkIP5FOcb38jfBj/OcBz1wFaI9nk40uQKSORvnXws6wCbep2dg8yxZ3ddJxBIfQsxoiEOvnrykFinUScrB/ew==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@puppeteer/browsers": "2.4.0", "chromium-bidi": "0.6.5", - "debug": "^4.3.6", - "devtools-protocol": "0.0.1330662", + "debug": "^4.3.7", + "devtools-protocol": "0.0.1342118", "typed-query-selector": "^2.12.0", "ws": "^8.18.0" }, @@ -8255,8 +8203,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/randombytes": { "version": "2.1.0", @@ -8791,7 +8738,6 @@ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" @@ -8889,7 +8835,6 @@ "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "dev": true, - "license": "MIT", "dependencies": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" @@ -8904,7 +8849,6 @@ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", "dev": true, - "license": "MIT", "dependencies": { "agent-base": "^7.1.1", "debug": "^4.3.4", @@ -8945,8 +8889,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true, - "license": "BSD-3-Clause" + "dev": true }, "node_modules/stackback": { "version": "0.0.2", @@ -8996,11 +8939,10 @@ "license": "MIT" }, "node_modules/streamx": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.20.0.tgz", - "integrity": "sha512-ZGd1LhDeGFucr1CUCTBOS58ZhEendd0ttpGT3usTvosS4ntIwKN9LJFp+OeCSprsCPL14BXVRZlHGRY1V9PVzQ==", + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.20.1.tgz", + "integrity": "sha512-uTa0mU6WUC65iUvzKH4X9hEdvSW7rbPxPtwfWiLMSj3qTdQbAiUboZTxauKfpFuGIGa1C2BYijZ7wgdUXICJhA==", "dev": true, - "license": "MIT", "dependencies": { "fast-fifo": "^1.3.2", "queue-tick": "^1.0.1", @@ -9289,7 +9231,6 @@ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz", "integrity": "sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==", "dev": true, - "license": "MIT", "dependencies": { "pump": "^3.0.0", "tar-stream": "^3.1.5" @@ -9304,7 +9245,6 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", "dev": true, - "license": "MIT", "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", @@ -9370,11 +9310,10 @@ "peer": true }, "node_modules/text-decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.1.tgz", - "integrity": "sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.0.tgz", + "integrity": "sha512-n1yg1mOj9DNpk3NeZOx7T6jchTbyJS3i3cucbNN6FcdPriMZx7NsgrGpWWdWZZGxD7ES1XB+3uoqHMgOKaN+fg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "b4a": "^1.6.4" } @@ -9407,8 +9346,7 @@ "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/tiny-case": { "version": "1.0.3", @@ -9562,8 +9500,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", - "dev": true, - "license": "0BSD" + "dev": true }, "node_modules/tsscmp": { "version": "1.0.6", @@ -9613,8 +9550,7 @@ "version": "2.12.0", "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz", "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/typescript": { "version": "5.6.2", @@ -9659,7 +9595,6 @@ "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", "dev": true, - "license": "MIT", "dependencies": { "buffer": "^5.2.1", "through": "^2.3.8" @@ -9742,8 +9677,7 @@ "version": "10.0.0", "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/util-deprecate": { "version": "1.0.2", @@ -10408,7 +10342,6 @@ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dev": true, - "license": "MIT", "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" @@ -10481,7 +10414,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index b2054c84..df461a43 100644 --- a/package.json +++ b/package.json @@ -26,13 +26,13 @@ "prettier": "^3.3.3", "prettier-eslint": "^16.3.0", "prettier-plugin-tailwindcss": "^0.6.6", - "puppeteer": "^23.3.0", + "puppeteer": "^23.4.0", "tailwind-config-viewer": "^2.0.4", "vite": "^5.4.6", "vitest": "^2.1.1" }, "dependencies": { - "@deck9/ui": "^0.15.0", + "@deck9/ui": "^0.15.1", "@headlessui/vue": "^1.7.23", "@highlightjs/vue-plugin": "^2.1.0", "@inertiajs/vue3": "^1.2.0", @@ -49,8 +49,8 @@ "@tiptap/vue-3": "^2.7.2", "@types/lodash": "^4.17.7", "@types/node": "^22.5.5", - "@typescript-eslint/eslint-plugin": "^8.5.0", - "@typescript-eslint/parser": "^8.5.0", + "@typescript-eslint/eslint-plugin": "^8.6.0", + "@typescript-eslint/parser": "^8.6.0", "@vitejs/plugin-vue": "^5.1.4", "@vueuse/core": "^11.1.0", "autoprefixer": "^10.4.20", diff --git a/resources/js/components/Factory/Main/BlockType.vue b/resources/js/components/Factory/Main/BlockType.vue index 48e3d2f8..06027856 100644 --- a/resources/js/components/Factory/Main/BlockType.vue +++ b/resources/js/components/Factory/Main/BlockType.vue @@ -18,22 +18,13 @@ /> -
- -
- -
-
diff --git a/resources/js/components/Factory/Sidebar/Storyboard.vue b/resources/js/components/Factory/Sidebar/Storyboard.vue index 80b7e9bd..902b1e3b 100644 --- a/resources/js/components/Factory/Sidebar/Storyboard.vue +++ b/resources/js/components/Factory/Sidebar/Storyboard.vue @@ -64,6 +64,7 @@ /> + diff --git a/resources/js/components/Factory/Sidebar/BlockLogicEdit.vue b/resources/js/components/Factory/Sidebar/BlockLogicEdit.vue index c2dec00b..a293d78e 100644 --- a/resources/js/components/Factory/Sidebar/BlockLogicEdit.vue +++ b/resources/js/components/Factory/Sidebar/BlockLogicEdit.vue @@ -16,7 +16,7 @@ leave-from="translate-x-0" leave-to="-translate-x-full" > - +
@@ -43,10 +43,7 @@
-

This is the block logic editor.

-
{{
-                      store.block
-                    }}
+
- { return state.isBlockMenuEnabled; }, + + blocksTree: (state): TreeNode[] => { + const tree: TreeNode[] = []; + const map: Record = {}; + + state.blocks?.forEach((block) => { + map[block.uuid] = { block, children: [] }; + }); + + state.blocks?.forEach((block) => { + if (block.parent_block) { + const parent = map[block.parent_block]; + if (parent) { + parent.children.push(map[block.uuid]); + } + } else { + tree.push(map[block.uuid]); + } + }); + + return tree; + }, }, actions: { diff --git a/resources/js/stores/logic.ts b/resources/js/stores/logic.ts index cdbc39b3..d39576a9 100644 --- a/resources/js/stores/logic.ts +++ b/resources/js/stores/logic.ts @@ -1,3 +1,4 @@ +import { useForm } from "@/stores"; import { defineStore } from "pinia"; interface LogicStore { @@ -24,4 +25,41 @@ export const useLogic = defineStore("logic", { this.isShowingLogicEditor = false; }, }, + + getters: { + availableSourceBlocks(state): Array { + const formStore = useForm(); + + const result: FormBlockModel[] = []; + let found = false; + + const traverse = (node: TreeNode) => { + if (found) return; + + result.push(node.block); + + if (node.block.uuid === state.block?.uuid) { + found = true; + return; + } + + for (const child of node.children) { + traverse(child); + if (found) break; + } + }; + + for (const rootNode of formStore.blocksTree) { + traverse(rootNode); + if (found) break; + } + + // Remove the last element (the found block) from the result + if (found) { + result.pop(); + } + + return result; + }, + }, }); diff --git a/resources/js/types/models.d.ts b/resources/js/types/models.d.ts index 58d7133f..24a9bab4 100644 --- a/resources/js/types/models.d.ts +++ b/resources/js/types/models.d.ts @@ -64,6 +64,11 @@ interface FormWebhookModel extends BaseModel { headers: Record | null; } +interface TreeNode { + block: FormBlockModel; + children: TreeNode[]; +} + interface FormBlockModel extends BaseModel { type: FormBlockType; message: string | null; diff --git a/resources/js/utils/index.ts b/resources/js/utils/index.ts index 8436df2d..e4b70f61 100644 --- a/resources/js/utils/index.ts +++ b/resources/js/utils/index.ts @@ -67,3 +67,11 @@ export function replaceRouteQuery(query: Record): void { window.history.replaceState(historyState, "", url.toString()); } + +export function getTextFromHtml(html: string): string { + const div = document.createElement("div"); + div.innerHTML = html; + const text = div.textContent || div.innerText || ""; + + return text; +} From 7e0d4dafb9ee539b90ab71f1f80721359a9abacc Mon Sep 17 00:00:00 2001 From: Philipp Reinking Date: Thu, 3 Oct 2024 00:18:24 +0200 Subject: [PATCH 04/43] wip --- .../Factory/Sidebar/BlockHideLogic.vue | 166 +++++++++--------- .../Factory/Sidebar/BlockLogicEdit.vue | 20 ++- resources/js/stores/logic.ts | 4 + 3 files changed, 107 insertions(+), 83 deletions(-) diff --git a/resources/js/components/Factory/Sidebar/BlockHideLogic.vue b/resources/js/components/Factory/Sidebar/BlockHideLogic.vue index 0e0b8082..73172de3 100644 --- a/resources/js/components/Factory/Sidebar/BlockHideLogic.vue +++ b/resources/js/components/Factory/Sidebar/BlockHideLogic.vue @@ -5,101 +5,103 @@ description="Hide this block based on one or more conditions" /> -
-
- When +
diff --git a/resources/js/components/Factory/Sidebar/BlockLogicEdit.vue b/resources/js/components/Factory/Sidebar/BlockLogicEdit.vue index a293d78e..cd945706 100644 --- a/resources/js/components/Factory/Sidebar/BlockLogicEdit.vue +++ b/resources/js/components/Factory/Sidebar/BlockLogicEdit.vue @@ -19,6 +19,7 @@
+ { + isSaving.value = true; + + store.saveBlockLogic(); + + setTimeout(() => { + isSaving.value = false; + store.hideLogicEditor(); + }, 2000); +}; + const close = () => { store.hideLogicEditor(); }; diff --git a/resources/js/stores/logic.ts b/resources/js/stores/logic.ts index d39576a9..a7f4a255 100644 --- a/resources/js/stores/logic.ts +++ b/resources/js/stores/logic.ts @@ -24,6 +24,10 @@ export const useLogic = defineStore("logic", { this.block = null; this.isShowingLogicEditor = false; }, + + saveBlockLogic() { + console.log("save block logic"); + }, }, getters: { From 16bdf52727f68b962213c109f4e0bcca2cde330c Mon Sep 17 00:00:00 2001 From: Philipp Reinking Date: Fri, 4 Oct 2024 14:24:52 +0200 Subject: [PATCH 05/43] wip --- .../Factory/Sidebar/BlockHideLogic.vue | 27 +++++++------------ .../Factory/Sidebar/BlockLogicEdit.vue | 5 ++-- resources/js/stores/logic.ts | 23 +++++++++++++++- resources/js/types/models.d.ts | 24 +++++++++++++++++ 4 files changed, 59 insertions(+), 20 deletions(-) diff --git a/resources/js/components/Factory/Sidebar/BlockHideLogic.vue b/resources/js/components/Factory/Sidebar/BlockHideLogic.vue index 73172de3..4ae6cc10 100644 --- a/resources/js/components/Factory/Sidebar/BlockHideLogic.vue +++ b/resources/js/components/Factory/Sidebar/BlockHideLogic.vue @@ -107,20 +107,12 @@ diff --git a/resources/js/components/Factory/Sidebar/BlockLogicEdit.vue b/resources/js/components/Factory/Sidebar/BlockLogicEdit.vue index cd945706..69bc1363 100644 --- a/resources/js/components/Factory/Sidebar/BlockLogicEdit.vue +++ b/resources/js/components/Factory/Sidebar/BlockLogicEdit.vue @@ -100,8 +100,9 @@ const saveBlockLogic = () => { setTimeout(() => { isSaving.value = false; - store.hideLogicEditor(); - }, 2000); + // TODO hide when saving is done + // store.hideLogicEditor(); + }, 250); }; const close = () => { diff --git a/resources/js/stores/logic.ts b/resources/js/stores/logic.ts index a7f4a255..9387c492 100644 --- a/resources/js/stores/logic.ts +++ b/resources/js/stores/logic.ts @@ -4,6 +4,7 @@ import { defineStore } from "pinia"; interface LogicStore { block: FormBlockModel | null; isShowingLogicEditor: boolean; + hideRule: FormBlockRule | null; } export const useLogic = defineStore("logic", { @@ -11,6 +12,7 @@ export const useLogic = defineStore("logic", { return { block: null, isShowingLogicEditor: false, + hideRule: null, }; }, @@ -26,7 +28,26 @@ export const useLogic = defineStore("logic", { }, saveBlockLogic() { - console.log("save block logic"); + console.log("save rules", [this.hideRule]); + }, + + updateHideRule(conditions: Array) { + if (!this.block) { + return; + } + + if (!this.hideRule) { + this.hideRule = { + form_block_id: this.block?.id, + name: "Hide block", + conditions, + action: "hide", + actionPayload: null, + evaluate: "before", + }; + } else { + this.hideRule.conditions = conditions; + } }, }, diff --git a/resources/js/types/models.d.ts b/resources/js/types/models.d.ts index 24a9bab4..dec5abf7 100644 --- a/resources/js/types/models.d.ts +++ b/resources/js/types/models.d.ts @@ -69,6 +69,30 @@ interface TreeNode { children: TreeNode[]; } +type Operator = + | "equals" + | "equalsNot" + | "contains" + | "containsNot" + | "isLowerThan" + | "isGreaterThan"; + +interface FormBlockCondition { + source?: { key: FormBlockModel["uuid"] }; + operator: { key: Operator }; + value: string; + chainOperator: "or" | "and"; +} + +interface FormBlockRule { + form_block_id: number; + name: string; + conditions: Array; + action: "show" | "hide" | "goto"; + actionPayload: string | null; + evaluate: "before" | "after"; +} + interface FormBlockModel extends BaseModel { type: FormBlockType; message: string | null; From d8949860bf3301b8540ba91975a7ff6c12e677ca Mon Sep 17 00:00:00 2001 From: Philipp Reinking Date: Fri, 4 Oct 2024 14:47:27 +0200 Subject: [PATCH 06/43] fix linter --- .../js/components/Factory/Sidebar/BlockHideLogic.vue | 2 +- resources/js/components/Factory/Sidebar/Group.vue | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/resources/js/components/Factory/Sidebar/BlockHideLogic.vue b/resources/js/components/Factory/Sidebar/BlockHideLogic.vue index 4ae6cc10..84b74ddb 100644 --- a/resources/js/components/Factory/Sidebar/BlockHideLogic.vue +++ b/resources/js/components/Factory/Sidebar/BlockHideLogic.vue @@ -107,7 +107,7 @@ diff --git a/resources/js/components/Factory/Sidebar/BlockHideLogic.vue b/resources/js/components/Factory/Sidebar/BlockHideLogic.vue deleted file mode 100644 index 38afcff2..00000000 --- a/resources/js/components/Factory/Sidebar/BlockHideLogic.vue +++ /dev/null @@ -1,164 +0,0 @@ - - - diff --git a/resources/js/components/Factory/Sidebar/BlockLogicEdit.vue b/resources/js/components/Factory/Sidebar/BlockLogicEdit.vue index 69bc1363..04fde1b3 100644 --- a/resources/js/components/Factory/Sidebar/BlockLogicEdit.vue +++ b/resources/js/components/Factory/Sidebar/BlockLogicEdit.vue @@ -17,9 +17,8 @@ leave-to="-translate-x-full" > -
Block Logic +
-
- +
+ +
- +
@@ -82,8 +96,8 @@ import { TransitionChild, TransitionRoot, } from "@headlessui/vue"; -import BlockHideLogic from "./BlockHideLogic.vue"; -import { /* D9Label, D9Input, D9Select, */ D9Button, D9Icon } from "@deck9/ui"; +import BlockLogicRule from "./BlockLogicRule.vue"; +import { D9Button, D9Icon } from "@deck9/ui"; import { useLogic } from "@/stores"; import { storeToRefs } from "pinia"; @@ -91,12 +105,12 @@ import { storeToRefs } from "pinia"; const store = useLogic(); const isSaving = ref(false); -const { isShowingLogicEditor } = storeToRefs(store); +const { isShowingLogicEditor, block } = storeToRefs(store); -const saveBlockLogic = () => { +const save = async () => { isSaving.value = true; - store.saveBlockLogic(); + await store.saveBlockLogic(); setTimeout(() => { isSaving.value = false; diff --git a/resources/js/components/Factory/Sidebar/BlockLogicRule.vue b/resources/js/components/Factory/Sidebar/BlockLogicRule.vue new file mode 100644 index 00000000..872e434d --- /dev/null +++ b/resources/js/components/Factory/Sidebar/BlockLogicRule.vue @@ -0,0 +1,199 @@ + + + diff --git a/resources/js/stores/logic.ts b/resources/js/stores/logic.ts index 4f8936ef..a9b4e580 100644 --- a/resources/js/stores/logic.ts +++ b/resources/js/stores/logic.ts @@ -1,7 +1,11 @@ import { useForm } from "@/stores"; import { defineStore } from "pinia"; -import { callCreateFormBlockLogic } from "@/api/logics"; +import { + callCreateFormBlockLogic, + callUpdateFormBlockLogic, + callDeleteFormBlockLogic, +} from "@/api/logics"; interface LogicStore { block: FormBlockModel | null; @@ -9,6 +13,15 @@ interface LogicStore { hideRule: FormBlockLogic | null; } +export const operators: Array<{ key: Operator; label: string }> = [ + { key: "equals", label: "is equal to" }, + { key: "equalsNot", label: "is not equal to" }, + { key: "contains", label: "contains" }, + { key: "containsNot", label: "does not contain" }, + { key: "isLowerThan", label: "is lower than" }, + { key: "isGreaterThan", label: "is greater than" }, +]; + const transformConditionForBackend = ( condition: EditableFormBlockBlockLogicCondition, ): FormBlockLogicCondition => { @@ -39,56 +52,135 @@ export const useLogic = defineStore("logic", { this.isShowingLogicEditor = false; }, - async saveBlockLogic() { + addRule() { if (!this.block) { return; } + if (!this.block.logics) { + this.block.logics = []; + } + + this.block.logics.push({ + form_block_id: this.block.id, + name: "Rule #" + (this.block.logics.length + 1), + action: "hide", + actionPayload: null, + evaluate: "before", + conditions: [], + }); + }, + + async removeRule(index: number) { + if (!this.block || !this.block.logics) { + return; + } + try { - console.log("save rules", [this.hideRule]); - // create new logic on backend - const response = await callCreateFormBlockLogic( - this.block?.id, - { - ...this.hideRule, - }, + const response = await callDeleteFormBlockLogic( + this.block.logics[index], ); - if (response.status === 201) { - this.hideRule = response.data; + if (response.status === 200) { + this.block.logics.splice(index, 1); } } catch (error) { - console.warn(error); + console.warn(`Error deleting rule:`, error); } }, - updateHideRule( - conditions: Array, - ) { + async saveBlockLogic() { + if (!this.block || !this.block.logics) { + return; + } + + const results = await Promise.allSettled( + this.block.logics.map((logic) => this.saveSingleRule(logic)), + ); + + const failedSaves = results.filter( + (result) => result.status === "rejected", + ); + + if (failedSaves.length > 0) { + console.warn(`Failed to save ${failedSaves.length} rule(s):`); + failedSaves.forEach((failure, index) => { + if (failure.status === "rejected") { + console.warn( + `Rule ${index + 1} failed:`, + failure.reason, + ); + } + }); + } + + return { + failed: failedSaves.length, + totalRules: this.block.logics.length, + }; + }, + + async saveSingleRule(logic: FormBlockLogic) { + if (!this.block) { + throw new Error("Block is not defined"); + } + + try { + if (!logic.uuid) { + const response = await callCreateFormBlockLogic( + this.block.id, + logic, + ); + if (response.status === 201) { + return response.data; + } else { + throw new Error( + `Unexpected response status: ${response.status}`, + ); + } + } else { + const response = await callUpdateFormBlockLogic(logic); + + if (response.status === 200) { + return response.data; + } else { + throw new Error( + `Unexpected response status: ${response.status}`, + ); + } + } + } catch (error) { + console.warn(`Error saving rule:`, error); + throw error; + } + }, + + updateBlockLogic(logic: FormBlockLogic, index: number) { if (!this.block) { return; } - const transformedConditions = conditions.map((c) => + if (!this.block.logics) { + this.block.logics = []; + } + + const transformedConditions = logic.conditions.map((c) => transformConditionForBackend(c), ); - if (!this.hideRule) { - this.hideRule = { - form_block_id: this.block?.id, - name: "Hide block", - conditions: transformedConditions, - action: "hide", - actionPayload: null, - evaluate: "before", - }; - } else { - this.hideRule.conditions = transformedConditions; - } + logic.conditions = transformedConditions; + + this.block.logics[index] = logic; }, }, getters: { + allBlocks(): Array | null { + const formStore = useForm(); + + return formStore.blocks; + }, + availableSourceBlocks(state): Array { const formStore = useForm(); diff --git a/resources/js/types/models.d.ts b/resources/js/types/models.d.ts index 3a95a094..e43f2e52 100644 --- a/resources/js/types/models.d.ts +++ b/resources/js/types/models.d.ts @@ -90,9 +90,13 @@ interface EditableFormBlockBlockLogicCondition extends FormBlockLogicCondition { } interface FormBlockLogic { + id?: number; + uuid?: string; form_block_id: number; name: string; - conditions: Array; + conditions: + | Array + | Array; action: "show" | "hide" | "goto"; actionPayload: string | null; evaluate: "before" | "after"; From 58f635e734e5107f734adab320c9346be02811ea Mon Sep 17 00:00:00 2001 From: Philipp Reinking Date: Sat, 5 Oct 2024 19:54:03 +0200 Subject: [PATCH 10/43] wip --- app/Http/Controllers/Api/FormBlockLogicController.php | 7 +++++++ .../js/components/Factory/Shared/LabelToggle.vue | 2 +- .../js/components/Factory/Sidebar/BlockLogicRule.vue | 10 ++++++---- routes/api.php | 1 + tests/Feature/FormBlockLogicTest.php | 11 +++++++++++ 5 files changed, 26 insertions(+), 5 deletions(-) diff --git a/app/Http/Controllers/Api/FormBlockLogicController.php b/app/Http/Controllers/Api/FormBlockLogicController.php index ff365be4..4bdfb889 100644 --- a/app/Http/Controllers/Api/FormBlockLogicController.php +++ b/app/Http/Controllers/Api/FormBlockLogicController.php @@ -18,4 +18,11 @@ public function update(FormBlockLogicRequest $request, FormBlockLogic $logic) { return response()->json($logic->update($request->validated())); } + + public function delete(FormBlockLogic $logic) + { + $logic->delete(); + + return response()->json(null, 200); + } } diff --git a/resources/js/components/Factory/Shared/LabelToggle.vue b/resources/js/components/Factory/Shared/LabelToggle.vue index 7c6832cd..430f2b00 100644 --- a/resources/js/components/Factory/Shared/LabelToggle.vue +++ b/resources/js/components/Factory/Shared/LabelToggle.vue @@ -1,5 +1,5 @@
+ + +
+ +
+
+ If + the response for block + jR + contains + Köln +
+
+ + hide this block +
+
+
diff --git a/resources/js/components/Factory/Sidebar/Group.vue b/resources/js/components/Factory/Sidebar/Group.vue index 5594c078..b61bcc79 100644 --- a/resources/js/components/Factory/Sidebar/Group.vue +++ b/resources/js/components/Factory/Sidebar/Group.vue @@ -6,25 +6,22 @@ :class="[cardStyle, { 'opacity-50': block.is_disabled }]" @click.stop="workbench.putOnWorkbench(block)" > -

- + + {{ block.title ?? "Group" }} ({{ t("admin.blocks", groupCount) }}) -

+
+
diff --git a/resources/js/stores/form.ts b/resources/js/stores/form.ts index c078b020..dbb3399d 100644 --- a/resources/js/stores/form.ts +++ b/resources/js/stores/form.ts @@ -24,6 +24,7 @@ interface FormStore { mapping: Record | null; isCssTransitionEnabled: boolean; isBlockMenuEnabled: boolean; + showLogicInStoryboard: boolean; } export const useForm = defineStore("form", { @@ -34,6 +35,7 @@ export const useForm = defineStore("form", { blocks: null, isCssTransitionEnabled: true, isBlockMenuEnabled: true, + showLogicInStoryboard: false, }; }, @@ -123,6 +125,10 @@ export const useForm = defineStore("form", { this.isBlockMenuEnabled = false; }, + toggleLogicInStoryboard() { + this.showLogicInStoryboard = !this.showLogicInStoryboard; + }, + async refreshForm(includeSubmissions = false) { if (this.form) { const response = await callGetForm(this.form); From e47d5d87e3381dee4bf1542857bf78f28684745e Mon Sep 17 00:00:00 2001 From: Philipp Reinking Date: Fri, 18 Oct 2024 15:32:19 +0200 Subject: [PATCH 18/43] fix ui of block logic in sidebar --- .../Factory/Sidebar/BlockLogicVisualizer.vue | 51 ++++++++++--------- .../components/Factory/Sidebar/Storyboard.vue | 7 --- resources/js/stores/form.ts | 2 +- 3 files changed, 27 insertions(+), 33 deletions(-) diff --git a/resources/js/components/Factory/Sidebar/BlockLogicVisualizer.vue b/resources/js/components/Factory/Sidebar/BlockLogicVisualizer.vue index 05826d12..4ce565ee 100644 --- a/resources/js/components/Factory/Sidebar/BlockLogicVisualizer.vue +++ b/resources/js/components/Factory/Sidebar/BlockLogicVisualizer.vue @@ -3,51 +3,52 @@ class="mt-4 space-y-4" v-if="showBlockLogic && block && block.logics && block.logics.length > 0" > -
+
-
-
-
- {{ condition.chainOperator }} - If -
+ +
+ {{ condition.chainOperator }} + If +
+ + +
{{ condition.source }}
{{ condition.operator }}
{{ condition.value }}
+ + + + +
+ then
-
-
- then -
+ +
@@ -72,12 +66,13 @@ diff --git a/resources/js/components/Factory/Sidebar/Storyboard.vue b/resources/js/components/Factory/Sidebar/Storyboard.vue index b0ca28e9..111570ac 100644 --- a/resources/js/components/Factory/Sidebar/Storyboard.vue +++ b/resources/js/components/Factory/Sidebar/Storyboard.vue @@ -64,7 +64,7 @@ />
- + diff --git a/resources/js/stores/conversation.ts b/resources/js/stores/conversation.ts index 9dbabdd0..f5c1937d 100644 --- a/resources/js/stores/conversation.ts +++ b/resources/js/stores/conversation.ts @@ -13,7 +13,7 @@ type ConversationStore = { session?: FormSessionModel; storyboard: PublicFormBlockModel[] | null; queue: PublicFormBlockModel[] | null; - current: number; + current: PublicFormBlockModel["id"] | null; payload: FormSubmitPayload; isProcessing: boolean; isSubmitted: boolean; @@ -21,6 +21,41 @@ type ConversationStore = { uploads: FormFileUploads; }; +function createFlatQueue( + blocks: PublicFormBlockModel[], + parent_block: string | null = null, +): PublicFormBlockModel[] { + return blocks + .filter((block) => block.parent_block === parent_block) + .flatMap((block) => { + const queueItem = block; + if (block.type === "group") { + const children = blocks.filter( + (b) => b.parent_block === block.id, + ); + return [queueItem, ...createFlatQueue(children, block.id)]; + } + return [queueItem]; + }); +} + +function isBlockVisible( + block: PublicFormBlockModel, + payload: FormSubmitPayload, +): boolean { + if (!block.logics?.length) { + return true; + } + + block.logics + ?.filter((logic) => logic.evaluate === "before") + .forEach((logic) => { + console.log(logic, payload); + }); + + return true; // Default to visible +} + export const useConversation = defineStore("form", { state: (): ConversationStore => { return { @@ -28,7 +63,7 @@ export const useConversation = defineStore("form", { session: undefined, storyboard: null, queue: null, - current: 0, + current: null, payload: {}, isProcessing: false, isSubmitted: false, @@ -38,37 +73,62 @@ export const useConversation = defineStore("form", { }, getters: { - isFirstBlock(state): boolean { - if (!state.queue) { + isFirstBlock(): boolean { + if (!this.processedQueue) { return false; } - return state.current === 0; + return this.currentBlockIndex === 0; }, - isLastBlock(state): boolean { - if (!state.queue) { + isLastBlock(): boolean { + if (!this.processedQueue) { return false; } - return state.current + 1 >= state.queue.length; + return this.currentBlockIndex + 1 >= this.processedQueue.length; }, - currentBlock: (state): PublicFormBlockModel | null => { - if (state.queue && state.queue.length >= state.current) { - return state.queue[state.current]; + processedQueue(state): PublicFormBlockModel[] { + if (!state.queue) { + return []; } - return null; + return state.queue + .filter((block) => isBlockVisible(block, state.payload)) + .filter((block) => block.type !== "group"); + }, + + currentBlockIndex(state): number { + return this.processedQueue.findIndex( + (block) => block.id === state.current, + ); + }, + + currentBlock(): PublicFormBlockModel | null { + if (!this.processedQueue || !this.processedQueue.length) { + return null; + } + + if (this.currentBlockIndex === -1) { + return null; + } + + try { + return this.processedQueue[this.currentBlockIndex]; + } catch (e) { + console.warn("Current block not found in processed queue", e); + return null; + } }, currentPayload( state, ): FormBlockInteractionPayload | FormBlockInteractionPayload[] | null { - if (!this.currentBlock) return null; + if (!state.current) return null; - if (state.payload[this.currentBlock.id]) { - return state.payload[this.currentBlock.id]; + if (state.payload[state.current]) { + return state.payload[state.current]; } return null; @@ -137,19 +197,10 @@ export const useConversation = defineStore("form", { return ref( !state.isSubmitted && state.payload && - Object.keys(state.payload).length > 0 && - state.current > 0, + Object.keys(state.payload).length > 0, ); }, - currentBlockIdentifier(): string | null { - if (!this.currentBlock) { - return null; - } - - return this.currentBlock.title || this.currentBlock.id; - }, - callToActionUrl(state): string | null { if (!state.form || !state.session) { return null; @@ -251,21 +302,16 @@ export const useConversation = defineStore("form", { } } - const storyboardResponse = await callGetFormStoryboard(id); - const formSessionResponse = await callCreateFormSession(id, params); + const [formSessionResponse, storyboardResponse] = await Promise.all( + [callCreateFormSession(id, params), callGetFormStoryboard(id)], + ); this.session = formSessionResponse.data; this.storyboard = storyboardResponse.data.blocks; - this.queue = this.storyboard.filter((block) => { - return block.parent_block === null; - }); + this.queue = createFlatQueue(this.storyboard); - // if the first block is a group, we need to evaluate it - if (this.currentBlock?.type === "group") { - this.evaluateGroupBlock(this.currentBlock); - this.next(); - } + this.current = this.processedQueue[0].id ?? null; }, enableInputMode() { @@ -280,9 +326,9 @@ export const useConversation = defineStore("form", { action: PublicFormBlockInteractionModel, value: string | boolean | number | File[] | null, ) { - if (!this.currentBlock) return; + if (!this.current) return; - this.payload[this.currentBlock.id] = { + this.payload[this.current] = { payload: value, actionId: action.id, }; @@ -297,16 +343,16 @@ export const useConversation = defineStore("form", { | null, keepChecked: boolean | null = null, ) { - if (!this.currentBlock) return; + if (!this.current) return; const givenPayload = { payload: value, actionId: action.id, }; - const currentPayload = this.payload[this.currentBlock.id]; + const currentPayload = this.payload[this.current]; if (!Array.isArray(currentPayload)) { - this.payload[this.currentBlock.id] = [givenPayload]; + this.payload[this.current] = [givenPayload]; } else { const foundIndex = currentPayload.findIndex( (p) => p.actionId === action.id, @@ -324,17 +370,20 @@ export const useConversation = defineStore("form", { } }, + goToIndex(index: number) { + if (index >= 0 && index < this.processedQueue.length) { + this.current = this.processedQueue[index].id; + } else { + console.warn("Index out of bounds", index); + } + }, + back() { if (this.isFirstBlock) { return; } - this.current -= 1; - - // if we are on a group block, we need to go back again - if (this.currentBlock?.type === "group") { - this.back(); - } + this.goToIndex(this.currentBlockIndex - 1); }, /** @@ -400,15 +449,7 @@ export const useConversation = defineStore("form", { return Promise.reject(new Error("Form or session not set")); } } else { - this.current += 1; - - // need to check if the next block is a group block - if (this.currentBlock?.type === "group") { - this.evaluateGroupBlock(this.currentBlock); - - // we call next, since the group block has no other action - return this.next(); - } + this.goToIndex(this.currentBlockIndex + 1); return Promise.resolve(false); } diff --git a/resources/js/types/models.d.ts b/resources/js/types/models.d.ts index e43f2e52..b5ccd60e 100644 --- a/resources/js/types/models.d.ts +++ b/resources/js/types/models.d.ts @@ -203,6 +203,7 @@ type PublicFormBlockModel = { parent_block: string | null; is_required: boolean | null; interactions: Array; + logics: Array | undefined; }; type PublicFormModel = { From b0ca8af4928e5e7e81220ce37389f1919d809a8b Mon Sep 17 00:00:00 2001 From: Philipp Reinking Date: Thu, 24 Oct 2024 17:25:48 +0200 Subject: [PATCH 26/43] remove pre --- resources/js/forms/classic/ClassicForm.vue | 2 -- 1 file changed, 2 deletions(-) diff --git a/resources/js/forms/classic/ClassicForm.vue b/resources/js/forms/classic/ClassicForm.vue index 7cf6b87a..69920a04 100644 --- a/resources/js/forms/classic/ClassicForm.vue +++ b/resources/js/forms/classic/ClassicForm.vue @@ -13,8 +13,6 @@ }" >
-
{{ store.processedQueue }}
-
From 74a978f49f00ba39e407d5147b988bb165470391 Mon Sep 17 00:00:00 2001 From: Philipp Reinking Date: Fri, 25 Oct 2024 12:47:26 +0200 Subject: [PATCH 27/43] fix nested button markup --- resources/js/components/Factory/Sidebar/Block.vue | 6 +++--- resources/js/components/Factory/Sidebar/Group.vue | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/resources/js/components/Factory/Sidebar/Block.vue b/resources/js/components/Factory/Sidebar/Block.vue index ecb1bfa3..dd5b3b64 100644 --- a/resources/js/components/Factory/Sidebar/Block.vue +++ b/resources/js/components/Factory/Sidebar/Block.vue @@ -2,8 +2,8 @@
- +
diff --git a/resources/js/components/Factory/Sidebar/Group.vue b/resources/js/components/Factory/Sidebar/Group.vue index 83e669af..51d67c82 100644 --- a/resources/js/components/Factory/Sidebar/Group.vue +++ b/resources/js/components/Factory/Sidebar/Group.vue @@ -1,13 +1,13 @@ From b1304ca7349d17d46bd02b570de0ca9d131681c9 Mon Sep 17 00:00:00 2001 From: Philipp Reinking Date: Fri, 25 Oct 2024 16:44:04 +0200 Subject: [PATCH 28/43] fix navigator and transition bug --- .../classic/layout/FormSubmittedPage.vue | 36 +++++++++---------- .../js/forms/classic/layout/Navigator.vue | 6 +++- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/resources/js/forms/classic/layout/FormSubmittedPage.vue b/resources/js/forms/classic/layout/FormSubmittedPage.vue index 476a1048..32b1bae7 100644 --- a/resources/js/forms/classic/layout/FormSubmittedPage.vue +++ b/resources/js/forms/classic/layout/FormSubmittedPage.vue @@ -1,23 +1,23 @@ diff --git a/resources/js/forms/classic/layout/Navigator.vue b/resources/js/forms/classic/layout/Navigator.vue index 7ef7f264..3457d114 100644 --- a/resources/js/forms/classic/layout/Navigator.vue +++ b/resources/js/forms/classic/layout/Navigator.vue @@ -82,6 +82,10 @@ const currentPage = computed(() => { }); const progress = computed(() => { - return Math.round((store.currentBlockIndex / totalPages.value) * 100); + if (store.currentBlockIndex <= 0) { + return 0; + } + + return Math.round(((store.currentBlockIndex + 1) / totalPages.value) * 100); }); From 98db4c9d7386cc92517be2a7393f7adf15ffcbf1 Mon Sep 17 00:00:00 2001 From: Philipp Reinking Date: Thu, 31 Oct 2024 15:38:05 +0100 Subject: [PATCH 29/43] add show hide logic evaluation --- resources/js/stores/conversation.ts | 84 +++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 3 deletions(-) diff --git a/resources/js/stores/conversation.ts b/resources/js/stores/conversation.ts index f5c1937d..d7ad32c1 100644 --- a/resources/js/stores/conversation.ts +++ b/resources/js/stores/conversation.ts @@ -7,6 +7,7 @@ import { callUploadFiles, } from "@/api/conversation"; import { Ref, ref } from "vue"; +import { isBlock } from "typescript"; type ConversationStore = { form?: PublicFormModel; @@ -41,19 +42,96 @@ function createFlatQueue( function isBlockVisible( block: PublicFormBlockModel, - payload: FormSubmitPayload, + responses: FormSubmitPayload, ): boolean { if (!block.logics?.length) { return true; } + // block is visible by default + let isBlockVisible = true; + block.logics ?.filter((logic) => logic.evaluate === "before") .forEach((logic) => { - console.log(logic, payload); + // each logic result is false by default + + // check if the logic is true for the current payload + const evaluatedConditions = logic.conditions.map((condition) => { + let result = false; + + if (condition.source && responses[condition.source]) { + const response = responses[condition.source]; + + // get payload value or combine to string if it is an array + const responseValue = + "payload" in response + ? response.payload + : response.map((p) => p.payload).join(", "); + + switch (condition.operator) { + case "equals": + result = responseValue === condition.value; + break; + case "equalsNot": + result = responseValue !== condition.value; + break; + case "contains": + result = responseValue.includes(condition.value); + break; + case "containsNot": + result = !responseValue.includes(condition.value); + break; + case "isLowerThan": + result = responseValue < condition.value; + break; + case "isGreaterThan": + result = responseValue > condition.value; + break; + } + } + + return { + ...condition, + result, + }; + }); + + let currentIndex = 0; + const conditionGroups: any[] = []; + + // split conditions each time an "or" operator is found + evaluatedConditions.forEach((condition, index) => { + if (index === 0) { + conditionGroups[currentIndex] = [condition]; + } else { + if (condition.chainOperator === "or") { + currentIndex++; + } + + if (!conditionGroups[currentIndex]) { + conditionGroups[currentIndex] = []; + } + + conditionGroups[currentIndex].push(condition); + } + }); + + const finalResult = conditionGroups.some((group) => { + return group.every((condition) => { + return condition.result; + }); + }); + + // if the logic is true, then execute the block aciton + if (logic.action === "show") { + isBlockVisible = finalResult; + } else if (logic.action === "hide") { + isBlockVisible = !finalResult; + } }); - return true; // Default to visible + return isBlockVisible; } export const useConversation = defineStore("form", { From c5d5fe72bc979e574411ed31159ab8e86958a8b1 Mon Sep 17 00:00:00 2001 From: Philipp Reinking Date: Fri, 1 Nov 2024 15:14:54 +0100 Subject: [PATCH 30/43] add goto settings for logic in sidebar --- app/Http/Requests/FormBlockLogicRequest.php | 3 +- .../components/Factory/Shared/LabelToggle.vue | 8 +++- .../Factory/Sidebar/BlockLogicRule.vue | 46 +++++++++++++++++-- .../Factory/Sidebar/BlockLogicVisualizer.vue | 7 ++- .../js/components/Factory/Sidebar/Group.vue | 2 +- resources/js/stores/logic.ts | 2 +- 6 files changed, 58 insertions(+), 10 deletions(-) diff --git a/app/Http/Requests/FormBlockLogicRequest.php b/app/Http/Requests/FormBlockLogicRequest.php index e165056f..60bc7c2b 100644 --- a/app/Http/Requests/FormBlockLogicRequest.php +++ b/app/Http/Requests/FormBlockLogicRequest.php @@ -28,7 +28,8 @@ public function rules(): array 'conditions.*.operator' => 'required|string|in:equals,equalsNot,contains,containsNot,isLowerThan,isGreaterThan', 'conditions.*.value' => 'required|string', 'conditions.*.chainOperator' => 'required|string|in:and,or', - 'action' => 'required|string|in:hide,show', + 'action' => 'required|string|in:hide,show,goto', + 'actionPayload' => 'nullable|string', 'evaluate' => 'required|string|in:before,after', ]; } diff --git a/resources/js/components/Factory/Shared/LabelToggle.vue b/resources/js/components/Factory/Shared/LabelToggle.vue index d99d2382..33bf8ee2 100644 --- a/resources/js/components/Factory/Shared/LabelToggle.vue +++ b/resources/js/components/Factory/Shared/LabelToggle.vue @@ -17,7 +17,7 @@ ? 'bg-white text-blue-700 ring-blue-600' : 'bg-white text-grey-500 hover:text-grey-900 hover:ring-blue-600', !active && !checked ? 'ring-inset' : '', - index === 0 ? 'rounded-l-md' : 'rounded-r-md', + index === 0 ? 'rounded-l-md' : 'last:rounded-r-md', 'group flex items-center justify-center px-3 py-2 leading-none text-sm border border-grey-300', ]" > @@ -65,6 +65,12 @@ const props = withDefaults( const value = ref(props.modelValue); +watch(props, () => { + if (props.modelValue !== value.value) { + value.value = props.modelValue; + } +}); + watch(value, (value) => { emit("update:modelValue", value); }); diff --git a/resources/js/components/Factory/Sidebar/BlockLogicRule.vue b/resources/js/components/Factory/Sidebar/BlockLogicRule.vue index 1fc3953c..98820b26 100644 --- a/resources/js/components/Factory/Sidebar/BlockLogicRule.vue +++ b/resources/js/components/Factory/Sidebar/BlockLogicRule.vue @@ -16,7 +16,7 @@
-
+ + +
+ + +
+ +
{{ rule }}
{ const evaluate = ref(props.rule.evaluate); const action = ref(props.rule.action); const conditions: Ref> = ref([]); +const target = ref | null>(null); const getBlockOption = (block: FormBlockModel) => { const text = getTextFromHtml(block.message ?? ""); @@ -164,6 +177,16 @@ const getBlockOption = (block: FormBlockModel) => { }; }; +if (props.rule.actionPayload) { + const found = logicStore.allBlocks?.find( + (block) => block.uuid === props.rule.actionPayload, + ); + + if (found) { + target.value = getBlockOption(found); + } +} + // if the loaded rule has already conditions, we should use those if (props.rule.conditions) { const editableConditions = props.rule.conditions.map((condition) => { @@ -212,22 +235,35 @@ const hasConditions = computed(() => { }); const availableSourceBlocks = computed(() => { - return logicStore.availableSourceBlocks - .filter((block) => block.type !== "group") + return logicStore.availableSourceBlocks.map((block) => { + return getBlockOption(block); + }); +}); + +const availableTargetBlocks = computed(() => { + return logicStore.allBlocks + ?.filter((block) => block.type !== "group") .map((block) => { return getBlockOption(block); }); }); watch( - [conditions, evaluate, action], + [conditions, evaluate, action, target], () => { + if (action.value === "hide" || action.value === "show") { + evaluate.value = "before"; + } else if (action.value === "goto") { + evaluate.value = "after"; + } + logicStore.updateBlockLogic( { ...props.rule, conditions: conditions.value, evaluate: evaluate.value, action: action.value, + actionPayload: target.value?.key ?? null, }, props.index, ); diff --git a/resources/js/components/Factory/Sidebar/BlockLogicVisualizer.vue b/resources/js/components/Factory/Sidebar/BlockLogicVisualizer.vue index 4ce565ee..0ad4f6b0 100644 --- a/resources/js/components/Factory/Sidebar/BlockLogicVisualizer.vue +++ b/resources/js/components/Factory/Sidebar/BlockLogicVisualizer.vue @@ -54,10 +54,15 @@ show this block -