From 56e5577e4d8d78144bc6424bf34fc2acac62075f Mon Sep 17 00:00:00 2001 From: Neel Date: Wed, 6 Aug 2025 14:04:59 -0400 Subject: [PATCH 1/5] chore(vscode-extension): removing eslint and adding pnpm / node engines --- packages/vscode-extension/.eslintrc.json | 25 - packages/vscode-extension/package-lock.json | 3887 ------------------- packages/vscode-extension/package.json | 14 +- 3 files changed, 7 insertions(+), 3919 deletions(-) delete mode 100644 packages/vscode-extension/.eslintrc.json delete mode 100644 packages/vscode-extension/package-lock.json diff --git a/packages/vscode-extension/.eslintrc.json b/packages/vscode-extension/.eslintrc.json deleted file mode 100644 index d25565bb97..0000000000 --- a/packages/vscode-extension/.eslintrc.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "env": { - "browser": false, - "commonjs": true, - "es6": true, - "node": true, - "mocha": true - }, - "parserOptions": { - "ecmaVersion": 2018, - "ecmaFeatures": { - "jsx": true - }, - "sourceType": "module" - }, - "rules": { - "no-const-assign": "warn", - "no-this-before-super": "warn", - "no-undef": "warn", - "no-unreachable": "warn", - "no-unused-vars": "warn", - "constructor-super": "warn", - "valid-typeof": "warn" - } -} diff --git a/packages/vscode-extension/package-lock.json b/packages/vscode-extension/package-lock.json deleted file mode 100644 index 820b53dad7..0000000000 --- a/packages/vscode-extension/package-lock.json +++ /dev/null @@ -1,3887 +0,0 @@ -{ - "name": "semoss-vscode", - "version": "0.0.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "semoss-vscode", - "version": "0.0.1", - "license": "UNLICENSED", - "dependencies": { - "archiver": "^7.0.1", - "axios": "^1.3.4", - "form-data": "^4.0.0", - "ncp": "^2.0.0", - "node-stream-zip": "^1.15.0" - }, - "devDependencies": { - "@eslint/js": "^9.26.0", - "@types/glob": "^8.1.0", - "@types/mocha": "^10.0.1", - "@types/node": "18.16.9", - "@types/vscode": "^1.76.0", - "@vscode/test-electron": "^2.2.3", - "esbuild": "^0.25.4", - "eslint": "^8.57.1", - "glob": "^8.1.0", - "globals": "^16.0.0", - "mocha": "^10.2.0", - "rimraf": "^3.0.2", - "typescript": "^4.9.5" - }, - "engines": { - "vscode": "^1.90.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", - "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz", - "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz", - "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz", - "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz", - "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz", - "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz", - "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz", - "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz", - "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz", - "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz", - "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz", - "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz", - "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz", - "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz", - "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz", - "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz", - "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz", - "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz", - "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz", - "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz", - "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz", - "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz", - "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz", - "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", - "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", - "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "9.26.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.26.0.tgz", - "integrity": "sha512-I9XlJawFdSMvWjDt6wksMCrgns5ggLNfFwFvnShsleWruvXM514Qxk8V246efTw+eo9JABvVz+u3q2RiAowKxQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@types/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/minimatch": "^5.1.2", - "@types/node": "*" - } - }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/mocha": { - "version": "10.0.10", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", - "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "18.16.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.9.tgz", - "integrity": "sha512-IeB32oIV4oGArLrd7znD2rkHQ6EDCM+2Sr76dJnrHwv9OHBTTM6nuDLK9bmikXzPa0ZlWMWtRGo/Uw4mrzQedA==", - "dev": true - }, - "node_modules/@types/vscode": { - "version": "1.99.1", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.99.1.tgz", - "integrity": "sha512-cQlqxHZ040ta6ovZXnXRxs3fJiTmlurkIWOfZVcLSZPcm9J4ikFpXuB7gihofGn5ng+kDVma5EmJIclfk0trPQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "dev": true, - "license": "ISC" - }, - "node_modules/@vscode/test-electron": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.5.2.tgz", - "integrity": "sha512-8ukpxv4wYe0iWMRQU18jhzJOHkeGKbnw7xWRX3Zw1WJA4cEKbHcmmLPdPrPtL6rhDcrlCZN+xKRpv09n4gRHYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.5", - "jszip": "^3.10.1", - "ora": "^8.1.0", - "semver": "^7.6.2" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "license": "MIT", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, - "node_modules/acorn": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/archiver": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", - "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", - "license": "MIT", - "dependencies": { - "archiver-utils": "^5.0.2", - "async": "^3.2.4", - "buffer-crc32": "^1.0.0", - "readable-stream": "^4.0.0", - "readdir-glob": "^1.1.2", - "tar-stream": "^3.0.0", - "zip-stream": "^6.0.1" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/archiver-utils": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", - "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", - "license": "MIT", - "dependencies": { - "glob": "^10.0.0", - "graceful-fs": "^4.2.0", - "is-stream": "^2.0.1", - "lazystream": "^1.0.0", - "lodash": "^4.17.15", - "normalize-path": "^3.0.0", - "readable-stream": "^4.0.0" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/archiver-utils/node_modules/brace-expansion": { - "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" - } - }, - "node_modules/archiver-utils/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/archiver-utils/node_modules/minimatch": { - "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" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "license": "MIT" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, - "node_modules/axios": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", - "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/b4a": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", - "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", - "license": "Apache-2.0" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/bare-events": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz", - "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==", - "license": "Apache-2.0", - "optional": true - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true, - "license": "ISC" - }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/buffer-crc32": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", - "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/compress-commons": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", - "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", - "license": "MIT", - "dependencies": { - "crc-32": "^1.2.0", - "crc32-stream": "^6.0.0", - "is-stream": "^2.0.1", - "normalize-path": "^3.0.0", - "readable-stream": "^4.0.0" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "license": "MIT" - }, - "node_modules/crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "license": "Apache-2.0", - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/crc32-stream": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", - "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", - "license": "MIT", - "dependencies": { - "crc-32": "^1.2.0", - "readable-stream": "^4.0.0" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "license": "MIT" - }, - "node_modules/emoji-regex": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", - "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", - "dev": true, - "license": "MIT" - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/esbuild": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", - "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.4", - "@esbuild/android-arm": "0.25.4", - "@esbuild/android-arm64": "0.25.4", - "@esbuild/android-x64": "0.25.4", - "@esbuild/darwin-arm64": "0.25.4", - "@esbuild/darwin-x64": "0.25.4", - "@esbuild/freebsd-arm64": "0.25.4", - "@esbuild/freebsd-x64": "0.25.4", - "@esbuild/linux-arm": "0.25.4", - "@esbuild/linux-arm64": "0.25.4", - "@esbuild/linux-ia32": "0.25.4", - "@esbuild/linux-loong64": "0.25.4", - "@esbuild/linux-mips64el": "0.25.4", - "@esbuild/linux-ppc64": "0.25.4", - "@esbuild/linux-riscv64": "0.25.4", - "@esbuild/linux-s390x": "0.25.4", - "@esbuild/linux-x64": "0.25.4", - "@esbuild/netbsd-arm64": "0.25.4", - "@esbuild/netbsd-x64": "0.25.4", - "@esbuild/openbsd-arm64": "0.25.4", - "@esbuild/openbsd-x64": "0.25.4", - "@esbuild/sunos-x64": "0.25.4", - "@esbuild/win32-arm64": "0.25.4", - "@esbuild/win32-ia32": "0.25.4", - "@esbuild/win32-x64": "0.25.4" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-fifo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", - "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", - "license": "MIT" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" - }, - "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/form-data": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", - "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", - "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/globals": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz", - "integrity": "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "license": "MIT", - "bin": { - "he": "bin/he" - } - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-interactive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", - "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "dev": true, - "license": "(MIT OR GPL-3.0-or-later)", - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - } - }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/jszip/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/jszip/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/lazystream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", - "license": "MIT", - "dependencies": { - "readable-stream": "^2.0.5" - }, - "engines": { - "node": ">= 0.6.3" - } - }, - "node_modules/lazystream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/lazystream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/lazystream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "immediate": "~3.0.5" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "license": "ISC" - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/mocha": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", - "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-colors": "^4.1.3", - "browser-stdout": "^1.3.1", - "chokidar": "^3.5.3", - "debug": "^4.3.5", - "diff": "^5.2.0", - "escape-string-regexp": "^4.0.0", - "find-up": "^5.0.0", - "glob": "^8.1.0", - "he": "^1.2.0", - "js-yaml": "^4.1.0", - "log-symbols": "^4.1.0", - "minimatch": "^5.1.6", - "ms": "^2.1.3", - "serialize-javascript": "^6.0.2", - "strip-json-comments": "^3.1.1", - "supports-color": "^8.1.1", - "workerpool": "^6.5.1", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9", - "yargs-unparser": "^2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/ncp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", - "integrity": "sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==", - "license": "MIT", - "bin": { - "ncp": "bin/ncp" - } - }, - "node_modules/node-stream-zip": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.15.0.tgz", - "integrity": "sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==", - "engines": { - "node": ">=0.12.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/antelle" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ora": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", - "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^5.3.0", - "cli-cursor": "^5.0.0", - "cli-spinners": "^2.9.2", - "is-interactive": "^2.0.0", - "is-unicode-supported": "^2.0.0", - "log-symbols": "^6.0.0", - "stdin-discarder": "^0.2.2", - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ora/node_modules/chalk": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", - "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/ora/node_modules/is-unicode-supported": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", - "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/log-symbols": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", - "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^5.3.0", - "is-unicode-supported": "^1.3.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/log-symbols/node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "license": "BlueOak-1.0.0" - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true, - "license": "(MIT AND Zlib)" - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "license": "MIT", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/readable-stream": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", - "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", - "license": "MIT", - "dependencies": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", - "process": "^0.11.10", - "string_decoder": "^1.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/readdir-glob": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", - "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.1.0" - } - }, - "node_modules/readdir-glob/node_modules/brace-expansion": { - "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" - } - }, - "node_modules/readdir-glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", - "dev": true, - "license": "MIT", - "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true, - "license": "MIT" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/stdin-discarder": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", - "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/streamx": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.0.tgz", - "integrity": "sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==", - "license": "MIT", - "dependencies": { - "fast-fifo": "^1.3.2", - "text-decoder": "^1.1.0" - }, - "optionalDependencies": { - "bare-events": "^2.2.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", - "license": "MIT", - "dependencies": { - "b4a": "^1.6.4", - "fast-fifo": "^1.2.0", - "streamx": "^2.15.0" - } - }, - "node_modules/text-decoder": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", - "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", - "license": "Apache-2.0", - "dependencies": { - "b4a": "^1.6.4" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/workerpool": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", - "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zip-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", - "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", - "license": "MIT", - "dependencies": { - "archiver-utils": "^5.0.0", - "compress-commons": "^6.0.2", - "readable-stream": "^4.0.0" - }, - "engines": { - "node": ">= 14" - } - } - } -} diff --git a/packages/vscode-extension/package.json b/packages/vscode-extension/package.json index 8d6808d08d..0bc0e9e8ca 100644 --- a/packages/vscode-extension/package.json +++ b/packages/vscode-extension/package.json @@ -6,9 +6,6 @@ "version": "0.0.1", "license": "UNLICENSED", "private": true, - "engines": { - "vscode": "^1.90.0" - }, "categories": [ "Other" ], @@ -98,8 +95,6 @@ } }, "scripts": { - "lint": "eslint .", - "pretest": "npm run lint", "test": "node ./test/runTest.js", "vscode:prepublish": "npm run esbuild-base -- --minify", "esbuild-base": "esbuild ./extension.js --bundle --outfile=out/main.js --external:vscode --external:util --external:fs --external:path --external:os --external:crypto --external:http --external:https --external:stream --external:zlib --external:buffer --format=cjs --platform=node --metafile=out/meta.json", @@ -110,14 +105,12 @@ "clean": "rimraf out" }, "devDependencies": { - "@eslint/js": "^9.26.0", "@types/glob": "^8.1.0", "@types/mocha": "^10.0.1", "@types/node": "18.16.9", "@types/vscode": "^1.76.0", "@vscode/test-electron": "^2.2.3", "esbuild": "^0.25.4", - "eslint": "^8.57.1", "glob": "^8.1.0", "globals": "^16.0.0", "mocha": "^10.2.0", @@ -130,5 +123,12 @@ "form-data": "^4.0.0", "ncp": "^2.0.0", "node-stream-zip": "^1.15.0" + }, + "packageManager": "pnpm@10.13.1", + "engines": { + "pnpm": "~10.13.0", + "node": ">=24.4.0 <25", + "vscode": "^1.90.0" } + } From a66f418b390a513062719e4068a89805dd1943f9 Mon Sep 17 00:00:00 2001 From: Neel Date: Wed, 6 Aug 2025 14:28:36 -0400 Subject: [PATCH 2/5] chore: updating biome rules to recommended and turning off useEffect autofix --- biome.json | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/biome.json b/biome.json index 0b61afe967..6ee1d16a90 100644 --- a/biome.json +++ b/biome.json @@ -34,14 +34,18 @@ "linter": { "enabled": true, "rules": { - "recommended": false, + "recommended": true, "complexity": { "noUselessFragments": "error" }, "correctness": { "noUnusedVariables": "error", "noUnusedImports": "error", - "useExhaustiveDependencies": "warn" + "useExhaustiveDependencies": { + "fix": "none", + "level": "warn", + "options": {} + } }, "style": { "useConst": "error" From f8deeca43e2d30548c13bb5841e815db604baeca Mon Sep 17 00:00:00 2001 From: Neel Date: Wed, 6 Aug 2025 15:15:00 -0400 Subject: [PATCH 3/5] chore: fixing pnpm lock --- pnpm-lock.yaml | 272 ------------------------------------------------- 1 file changed, 272 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 90ee4c3541..25496cc2d8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -593,9 +593,6 @@ importers: specifier: ^1.15.0 version: 1.15.0 devDependencies: - '@eslint/js': - specifier: ^9.26.0 - version: 9.31.0 '@types/glob': specifier: ^8.1.0 version: 8.1.0 @@ -614,9 +611,6 @@ importers: esbuild: specifier: ^0.25.4 version: 0.25.5 - eslint: - specifier: ^8.57.1 - version: 8.57.1 glob: specifier: ^8.1.0 version: 8.1.0 @@ -1214,28 +1208,6 @@ packages: cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.7.0': - resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.12.1': - resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/eslintrc@2.1.4': - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@eslint/js@8.57.1': - resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@eslint/js@9.31.0': - resolution: {integrity: sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@floating-ui/core@1.7.1': resolution: {integrity: sha512-azI0DrjMMfIug/ExbBaeDVJXcY0a7EPvPjb2xAJPa4HeimBX+Z18HK8QQR3jb6356SnDDdxx+hinMLcJEDdOjw==} @@ -1251,19 +1223,6 @@ packages: '@floating-ui/utils@0.2.9': resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} - '@humanwhocodes/config-array@0.13.0': - resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - - '@humanwhocodes/object-schema@2.0.3': - resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} - deprecated: Use @eslint/object-schema instead - '@icons/material@0.2.4': resolution: {integrity: sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==} peerDependencies: @@ -2603,11 +2562,6 @@ packages: peerDependencies: acorn: ^8.14.0 - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn-walk@8.3.4: resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} @@ -3498,9 +3452,6 @@ packages: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} @@ -3741,33 +3692,11 @@ packages: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} - eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint@8.57.1: - resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. - hasBin: true - - espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} - engines: {node: '>=0.10'} - esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} @@ -3845,9 +3774,6 @@ packages: fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-uri@3.0.6: resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} @@ -3880,10 +3806,6 @@ packages: resolution: {integrity: sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==} engines: {node: '>=4'} - file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} - file-selector@0.6.0: resolution: {integrity: sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==} engines: {node: '>= 12'} @@ -4035,10 +3957,6 @@ packages: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} @@ -4063,10 +3981,6 @@ packages: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} - globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} - globals@16.3.0: resolution: {integrity: sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==} engines: {node: '>=18'} @@ -4090,9 +4004,6 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - has-ansi@2.0.0: resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==} engines: {node: '>=0.10.0'} @@ -4452,10 +4363,6 @@ packages: resolution: {integrity: sha512-kyiNFFLU0Ampr6SDZitD/DwUo4Zs1nSdnygUBqsu3LooL00Qvb5j+UnvApUn/TTj1J3OuE6BTdQ5rudKmU2ZaA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - is-path-inside@4.0.0: resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} engines: {node: '>=12'} @@ -4769,9 +4676,6 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - json-stringify-pretty-compact@4.0.0: resolution: {integrity: sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==} @@ -4878,10 +4782,6 @@ packages: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} @@ -5587,10 +5487,6 @@ packages: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - ora@8.2.0: resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==} engines: {node: '>=18'} @@ -5990,10 +5886,6 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - prettier@2.8.8: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} engines: {node: '>=10.13.0'} @@ -6805,9 +6697,6 @@ packages: text-segmentation@1.0.3: resolution: {integrity: sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==} - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} @@ -6945,18 +6834,10 @@ packages: resolution: {integrity: sha512-kc8ZibdRcuWUG1pbYSBFWqmIjynlD8Lp7IB6U3vIzvOv9VG+6Sp8bzyeBWE3Oi8XV5KsQrznyRTBPvrf99E4mA==} hasBin: true - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - type-detect@4.0.8: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} - type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - type-fest@0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} @@ -7399,10 +7280,6 @@ packages: resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==} engines: {node: '>=8'} - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - wordwrap@1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} @@ -8138,31 +8015,6 @@ snapshots: '@esbuild/win32-x64@0.25.5': optional: true - '@eslint-community/eslint-utils@4.7.0(eslint@8.57.1)': - dependencies: - eslint: 8.57.1 - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.12.1': {} - - '@eslint/eslintrc@2.1.4': - dependencies: - ajv: 6.12.6 - debug: 4.4.1(supports-color@8.1.1) - espree: 9.6.1 - globals: 13.24.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@8.57.1': {} - - '@eslint/js@9.31.0': {} - '@floating-ui/core@1.7.1': dependencies: '@floating-ui/utils': 0.2.9 @@ -8180,18 +8032,6 @@ snapshots: '@floating-ui/utils@0.2.9': {} - '@humanwhocodes/config-array@0.13.0': - dependencies: - '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.1(supports-color@8.1.1) - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/object-schema@2.0.3': {} - '@icons/material@0.2.4(react@18.3.1)': dependencies: react: 18.3.1 @@ -9855,10 +9695,6 @@ snapshots: dependencies: acorn: 8.15.0 - acorn-jsx@5.3.2(acorn@8.15.0): - dependencies: - acorn: 8.15.0 - acorn-walk@8.3.4: dependencies: acorn: 8.15.0 @@ -10816,8 +10652,6 @@ snapshots: deep-eql@5.0.2: {} - deep-is@0.1.4: {} - deepmerge@4.3.1: {} define-data-property@1.1.4: @@ -11118,68 +10952,8 @@ snapshots: esrecurse: 4.3.0 estraverse: 4.3.0 - eslint-scope@7.2.2: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint@8.57.1: - dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.1) - '@eslint-community/regexpp': 4.12.1 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.1 - '@humanwhocodes/config-array': 0.13.0 - '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.3.0 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.1(supports-color@8.1.1) - doctrine: 3.0.0 - escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - esquery: 1.6.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - - espree@9.6.1: - dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) - eslint-visitor-keys: 3.4.3 - esprima@4.0.1: {} - esquery@1.6.0: - dependencies: - estraverse: 5.3.0 - esrecurse@4.3.0: dependencies: estraverse: 5.3.0 @@ -11250,8 +11024,6 @@ snapshots: fast-json-stable-stringify@2.1.0: {} - fast-levenshtein@2.0.6: {} - fast-uri@3.0.6: {} fastq@1.19.1: @@ -11282,10 +11054,6 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 - file-entry-cache@6.0.1: - dependencies: - flat-cache: 3.2.0 - file-selector@0.6.0: dependencies: tslib: 2.5.3 @@ -11452,10 +11220,6 @@ snapshots: dependencies: is-glob: 4.0.3 - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - glob-to-regexp@0.4.1: {} glob@10.4.5: @@ -11490,10 +11254,6 @@ snapshots: globals@11.12.0: {} - globals@13.24.0: - dependencies: - type-fest: 0.20.2 - globals@16.3.0: {} globalthis@1.0.4: @@ -11523,8 +11283,6 @@ snapshots: graceful-fs@4.2.11: {} - graphemer@1.4.0: {} - has-ansi@2.0.0: dependencies: ansi-regex: 2.1.1 @@ -11921,8 +11679,6 @@ snapshots: is-path-cwd@3.0.0: {} - is-path-inside@3.0.3: {} - is-path-inside@4.0.0: {} is-plain-obj@2.1.0: {} @@ -12431,8 +12187,6 @@ snapshots: json-schema-traverse@1.0.0: {} - json-stable-stringify-without-jsonify@1.0.1: {} - json-stringify-pretty-compact@4.0.0: {} json5@2.2.3: {} @@ -12532,11 +12286,6 @@ snapshots: leven@3.1.0: {} - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - lie@3.3.0: dependencies: immediate: 3.0.6 @@ -13474,15 +13223,6 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - ora@8.2.0: dependencies: chalk: 5.3.0 @@ -13854,8 +13594,6 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - prelude-ls@1.2.1: {} - prettier@2.8.8: {} pretty-error@4.0.0: @@ -14817,8 +14555,6 @@ snapshots: dependencies: utrie: 1.0.2 - text-table@0.2.0: {} - through@2.3.8: {} tiny-invariant@1.3.3: {} @@ -14980,14 +14716,8 @@ snapshots: turbo-windows-64: 2.5.4 turbo-windows-arm64: 2.5.4 - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - type-detect@4.0.8: {} - type-fest@0.20.2: {} - type-fest@0.21.3: {} type-fest@0.3.1: {} @@ -15655,8 +15385,6 @@ snapshots: dependencies: string-width: 4.2.3 - word-wrap@1.2.5: {} - wordwrap@1.0.0: {} workerpool@6.5.1: {} From 9f066e0f6e02f73bd2585374106afa59183d9d92 Mon Sep 17 00:00:00 2001 From: Neel Date: Wed, 6 Aug 2025 17:19:25 -0400 Subject: [PATCH 4/5] chore(shared): refactoring structure --- libs/shared/index.ts | 1 - libs/shared/package.json | 2 +- libs/shared/{components => src}/flex-layout/Layout.tsx | 0 .../{components => src}/flex-layout/flexlayout.css | 0 libs/shared/{components => src}/flex-layout/index.ts | 0 libs/shared/{components => src}/index.ts | 0 libs/shared/tsconfig.json | 10 ++-------- packages/client/src/components/workspace/Workspace.tsx | 7 ++++--- 8 files changed, 7 insertions(+), 13 deletions(-) delete mode 100644 libs/shared/index.ts rename libs/shared/{components => src}/flex-layout/Layout.tsx (100%) rename libs/shared/{components => src}/flex-layout/flexlayout.css (100%) rename libs/shared/{components => src}/flex-layout/index.ts (100%) rename libs/shared/{components => src}/index.ts (100%) diff --git a/libs/shared/index.ts b/libs/shared/index.ts deleted file mode 100644 index 40b494c5f8..0000000000 --- a/libs/shared/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./components"; diff --git a/libs/shared/package.json b/libs/shared/package.json index 0549661a5a..ca685f1d2e 100644 --- a/libs/shared/package.json +++ b/libs/shared/package.json @@ -2,7 +2,7 @@ "name": "@semoss/shared", "version": "1.0.0-beta.1", "exports": { - ".": "./index.ts" + ".": "./src/index.ts" }, "license": "MIT", "dependencies": { diff --git a/libs/shared/components/flex-layout/Layout.tsx b/libs/shared/src/flex-layout/Layout.tsx similarity index 100% rename from libs/shared/components/flex-layout/Layout.tsx rename to libs/shared/src/flex-layout/Layout.tsx diff --git a/libs/shared/components/flex-layout/flexlayout.css b/libs/shared/src/flex-layout/flexlayout.css similarity index 100% rename from libs/shared/components/flex-layout/flexlayout.css rename to libs/shared/src/flex-layout/flexlayout.css diff --git a/libs/shared/components/flex-layout/index.ts b/libs/shared/src/flex-layout/index.ts similarity index 100% rename from libs/shared/components/flex-layout/index.ts rename to libs/shared/src/flex-layout/index.ts diff --git a/libs/shared/components/index.ts b/libs/shared/src/index.ts similarity index 100% rename from libs/shared/components/index.ts rename to libs/shared/src/index.ts diff --git a/libs/shared/tsconfig.json b/libs/shared/tsconfig.json index 824c0a4653..d7bbaf44da 100644 --- a/libs/shared/tsconfig.json +++ b/libs/shared/tsconfig.json @@ -11,12 +11,6 @@ "allowSyntheticDefaultImports": true, "resolveJsonModule": true, - /* Emit */ - "declaration": true, - "outDir": "./dist", - "declarationDir": "./dist/types", - "emitDeclarationOnly": true, - /* Skip */ "skipLibCheck": true, "allowJs": true, @@ -25,9 +19,9 @@ /* Lang and Env */ "paths": { - "@/*": ["./components/*"] + "@/*": ["./src/*"], } }, - "include": ["components"], + "include": ["src"], "exclude": ["dist", "node_modules"] } diff --git a/packages/client/src/components/workspace/Workspace.tsx b/packages/client/src/components/workspace/Workspace.tsx index cabfe5e2ce..1158502f8f 100644 --- a/packages/client/src/components/workspace/Workspace.tsx +++ b/packages/client/src/components/workspace/Workspace.tsx @@ -12,7 +12,6 @@ import { Typography, } from "@semoss/ui"; import { Actions, DockLocation, Layout, TabNode } from "@semoss/shared"; -import { Layout as FlexLayout } from "flexlayout-react" // TODO: Why cant i export from shared import { ClosePage } from "@/assets/img/ClosePage"; import SEMOSS_BLACK_LOGO from "@/assets/img/SEMOSS_BLACK_LOGO.png"; @@ -23,6 +22,8 @@ import { NavbarHeader, NavbarLeft, NavbarRight } from "../shared"; import { WorkspaceLoading } from "./WorkspaceLoading"; import { WorkspaceOverlay } from "./WorkspaceOverlay"; +type LayoutType = React.ElementRef + const StyledMain = styled("div")(() => ({ position: "relative", height: "100%", @@ -109,12 +110,12 @@ type WorkspaceProps = { options: WorkspaceOptions; /** Factor method */ - factory: (node: TabNode, layout: FlexLayout) => React.ReactNode; + factory: (node: TabNode, layout: LayoutType) => React.ReactNode; }; export const Workspace = observer((props: WorkspaceProps) => { const { navbarActions, workspace, options, factory = () => null } = props; - const layoutRef = useRef(null); + const layoutRef = useRef(null); const model = workspace.model; // build the model from the layout From 600d8ca21f77ebb49d467a25f455690963fea4da Mon Sep 17 00:00:00 2001 From: Neel Date: Wed, 6 Aug 2025 17:22:11 -0400 Subject: [PATCH 5/5] chore: running autofix --- libs/renderer/rollup.config.js | 103 +- libs/renderer/src/Renderer.tsx | 2 +- .../accordion-block/AccordionBlock.tsx | 148 +- .../block-defaults/accordion-block/config.tsx | 44 +- .../block-defaults/accordion-block/index.ts | 2 +- .../block-defaults/audio-block/AudioBlock.tsx | 90 +- .../block-defaults/audio-block/config.tsx | 41 +- .../block-defaults/audio-block/index.ts | 2 +- .../audio-input-block/AudioInputBlock.tsx | 402 +- .../audio-input-block/config.tsx | 55 +- .../block-defaults/audio-input-block/index.ts | 2 +- .../block-defaults.constants.tsx | 50 +- .../button-block/ButtonBlock.tsx | 136 +- .../block-defaults/button-block/config.tsx | 53 +- .../block-defaults/button-block/index.ts | 2 +- .../checkbox-block/CheckboxBlock.tsx | 104 +- .../block-defaults/checkbox-block/config.tsx | 52 +- .../block-defaults/checkbox-block/index.ts | 2 +- .../block-defaults/chip-block/ChipBlock.tsx | 294 +- .../block-defaults/chip-block/config.tsx | 52 +- .../block-defaults/chip-block/index.ts | 2 +- .../container-block/ContainerBlock.tsx | 142 +- .../block-defaults/container-block/config.tsx | 67 +- .../block-defaults/container-block/index.ts | 2 +- .../divider-block/DividerBlock.tsx | 139 +- .../block-defaults/divider-block/config.tsx | 46 +- .../block-defaults/divider-block/index.ts | 2 +- .../CustomContextMenu.tsx | 172 +- .../Visualization.constants.ts | 118 +- .../VisualizationBlock.tsx | 381 +- .../VizBlockContextMenu.tsx | 172 +- .../echart-visualization-block/config.tsx | 82 +- .../variant/Gantt/Gantt.tsx | 1704 +- .../variant/bar-chart/Bar.tsx | 538 +- .../variant/bar-chart/ChartContextMenu.tsx | 401 +- .../variant/dendrogram/Dendrogram.tsx | 620 +- .../dendrogram/DendrogramChartField.tsx | 328 +- .../variant/line-chart/Line.tsx | 612 +- .../variant/map-chart/Map.tsx | 542 +- .../variant/map-chart/MapChartProcessData.tsx | 4322 ++- .../variant/map-chart/MapChartTooltipData.ts | 2076 +- .../variant/map-chart/MapSelector.ts | 1184 +- .../variant/map-chart/map-utility.tsx | 2 +- .../variant/pie-chart/Pie.tsx | 424 +- .../variant/scatter-plot/ScatterPlot.tsx | 372 +- .../scatter-plot/ScatterPlotProcessData.ts | 4118 +- .../scatter-plot/ScatterPlotSelector.ts | 994 +- .../scatter-plot/ScatterPlotTooltipData.ts | 2146 +- .../variant/stack-chart/StackChart.tsx | 1383 +- .../flip-card-block/FlipCardBlock.tsx | 163 +- .../block-defaults/flip-card-block/config.tsx | 54 +- .../block-defaults/grid-block/GridBlock.tsx | 874 +- .../grid-block/GridBlockContextMenu.tsx | 150 +- .../block-defaults/grid-block/config.tsx | 64 +- .../grid-block/grid-block.types.ts | 12 +- .../block-defaults/grid-block/index.ts | 2 +- .../GridDynamicFrameBlock.tsx | 457 +- .../grid-dynamic-frame-block/config.tsx | 62 +- .../block-defaults/html-block/HTMLBlock.tsx | 74 +- .../block-defaults/html-block/config.tsx | 20 +- .../block-defaults/icon-block/IconBlock.tsx | 116 +- .../block-defaults/icon-block/config.tsx | 48 +- .../iframe-block/IframeBlock.tsx | 95 +- .../block-defaults/iframe-block/config.tsx | 38 +- .../block-defaults/image-block/ImageBlock.tsx | 63 +- .../block-defaults/image-block/config.tsx | 54 +- .../src/components/block-defaults/index.ts | 400 +- .../block-defaults/input-block/InputBlock.tsx | 162 +- .../block-defaults/input-block/config.tsx | 68 +- .../iteration-block/IterationBlock.tsx | 289 +- .../block-defaults/iteration-block/config.tsx | 40 +- .../block-defaults/iteration-block/index.ts | 2 +- .../block-defaults/link-block/LinkBlock.tsx | 4 +- .../block-defaults/link-block/config.tsx | 44 +- .../block-defaults/logs-block/LogsBlock.tsx | 105 +- .../block-defaults/logs-block/config.tsx | 34 +- .../markdown-block/MarkdownBlock.tsx | 76 +- .../block-defaults/markdown-block/config.tsx | 40 +- .../mermaid-block/MermaidBlock.tsx | 196 +- .../block-defaults/mermaid-block/config.tsx | 20 +- .../block-defaults/modal-block/ModalBlock.tsx | 429 +- .../block-defaults/modal-block/config.tsx | 56 +- .../block-defaults/modal-block/index.ts | 2 +- .../block-defaults/page-block/PageBlock.tsx | 106 +- .../block-defaults/page-block/config.tsx | 48 +- .../pdfViewer-block/PDFViewerBlock.tsx | 381 +- .../block-defaults/pdfViewer-block/config.tsx | 42 +- .../popover-block/PopoverBlock.tsx | 438 +- .../block-defaults/popover-block/config.tsx | 52 +- .../progress-block/ProgressBlock.tsx | 173 +- .../block-defaults/progress-block/config.tsx | 38 +- .../block-defaults/radio-block/RadioBlock.tsx | 179 +- .../block-defaults/radio-block/config.tsx | 72 +- .../ratings-block/RatingsBlock.tsx | 147 +- .../block-defaults/ratings-block/config.tsx | 48 +- .../select-block/SelectBlock.tsx | 4 +- .../block-defaults/select-block/config.tsx | 4 +- .../sidebar-block/SidebarBlock.tsx | 164 +- .../block-defaults/sidebar-block/config.tsx | 54 +- .../slider-block/SliderBlock.tsx | 140 +- .../block-defaults/slider-block/config.tsx | 56 +- .../switch-block/SwitchBlock.tsx | 199 +- .../block-defaults/switch-block/config.tsx | 58 +- .../block-defaults/text-block/TextBlock.tsx | 4 +- .../block-defaults/text-block/config.tsx | 44 +- .../block-defaults/theme-block/ThemeBlock.tsx | 43 +- .../block-defaults/theme-block/config.tsx | 38 +- .../time-picker-block/TimePickerBlock.tsx | 211 +- .../time-picker-block/config.tsx | 76 +- .../toggle-button-block/ToggleButtonBlock.tsx | 154 +- .../toggle-button-block/config.tsx | 76 +- .../upload-block/UploadBlock.tsx | 260 +- .../block-defaults/upload-block/config.tsx | 111 +- .../VegaVisualizationBlock.tsx | 116 +- .../vega-visualization-block/config.tsx | 26 +- .../FilterComponent.tsx | 1002 +- .../VisualizationFilterBlock.tsx | 309 +- .../visualization-filter-block/config.tsx | 68 +- .../visualization-filter-block/index.ts | 2 +- .../renderer/src/components/blocks/Blocks.tsx | 68 +- libs/renderer/src/components/blocks/Error.tsx | 2 +- .../src/components/blocks/Loading.tsx | 2 +- .../src/components/blocks/RendererEngine.tsx | 199 +- libs/renderer/src/components/blocks/Slot.tsx | 62 +- .../src/components/blocks/Unauthorized.tsx | 2 +- libs/renderer/src/components/blocks/index.ts | 2 +- .../cell-defaults/code-cell/CodeCell.tsx | 1723 +- .../cell-defaults/code-cell/config.ts | 50 +- .../code-cell/icons/MarkdownIcon.tsx | 30 +- .../code-cell/icons/PythonIcon.tsx | 36 +- .../cell-defaults/code-cell/icons/RIcon.tsx | 36 +- .../cell-defaults/code-cell/icons/index.ts | 2 +- .../cell-defaults/code-cell/index.ts | 2 +- .../CollapseTransformationCell.tsx | 433 +- .../collapse-transformation-cell/config.tsx | 70 +- .../collapse-transformation-cell/index.ts | 2 +- .../ColumnTypeTransformationCell.tsx | 338 +- .../column-type-transformation-cell/config.ts | 48 +- .../column-type-transformation-cell/index.ts | 2 +- .../CumulativeSumTransformationCell.tsx | 439 +- .../config.tsx | 64 +- .../index.ts | 2 +- .../data-import-cell/DataImportCell.tsx | 1122 +- .../cell-defaults/data-import-cell/config.ts | 50 +- .../DateDifferenceTransformationCell.tsx | 736 +- .../config.ts | 108 +- .../EncodeColumnTransformationCell.tsx | 279 +- .../config.tsx | 56 +- .../filter-data-cell/FilterDataCell.tsx | 2031 +- .../cell-defaults/filter-data-cell/config.ts | 34 +- .../src/components/cell-defaults/index.ts | 188 +- .../JoinTransformationCell.tsx | 527 +- .../join-transformation-cell/config.ts | 78 +- .../cell-defaults/llm-cell/LLMCell.tsx | 381 +- .../cell-defaults/llm-cell/LLMCellVariant.tsx | 440 +- .../cell-defaults/llm-cell/config.ts | 44 +- .../query-import-cell/DatabaseTables.tsx | 246 +- .../query-import-cell/QueryImportCell.tsx | 776 +- .../cell-defaults/query-import-cell/config.ts | 28 +- .../send-email-cell/SendEmailCell.tsx | 660 +- .../cell-defaults/send-email-cell/config.ts | 62 +- .../ColumnTransformationField.tsx | 213 +- ...ncodeColumnCheckboxTransformationField.tsx | 463 +- .../MultiCellColumnTransformationField.tsx | 215 +- .../TransformationCellInput.tsx | 260 +- .../TransformationCellRunActionButton.tsx | 106 +- .../TransformationMultiCellInput.tsx | 358 +- .../shared/transformation/index.ts | 6 +- .../transformation.constants.tsx | 192 +- .../transformation/transformation.types.tsx | 108 +- .../TimestampTransformationCell.tsx | 351 +- .../timestamp-transformation-cell/config.ts | 48 +- .../unfilter-data-cell/UnFilterDataCell.tsx | 322 +- .../unfilter-data-cell/config.ts | 34 +- .../UpdateRowTransformationCell.tsx | 580 +- .../update-row-transformation-cell/config.ts | 66 +- .../UppercaseTransformationCell.tsx | 297 +- .../uppercase-transformation-cell/config.ts | 56 +- .../components/shared/DataImportFormModal.tsx | 3720 +- libs/renderer/src/constants.ts | 78 +- libs/renderer/src/contexts/Blocks.context.tsx | 16 +- libs/renderer/src/global.d.ts | 32 +- libs/renderer/src/hooks/index.ts | 14 +- libs/renderer/src/hooks/useBlock.tsx | 434 +- libs/renderer/src/hooks/useBlocks.tsx | 10 +- libs/renderer/src/hooks/useBlocksPixel.tsx | 17 +- libs/renderer/src/hooks/useFrame.tsx | 285 +- libs/renderer/src/hooks/useFrameHeaders.tsx | 123 +- libs/renderer/src/hooks/useTypeWriter.ts | 58 +- libs/renderer/src/index.ts | 123 +- .../src/store/notebook/notebook.store.ts | 211 +- libs/renderer/src/store/state/cell.state.ts | 860 +- libs/renderer/src/store/state/index.ts | 12 +- .../store/state/migration/MigrationManager.ts | 2 +- .../src/store/state/migration/index.ts | 3 +- ...ate__1_0_0_alpha_10__to__1_0_0_alpha_11.ts | 224 +- ...te__1_0_0_alpha_11__to___1_0_0_alpha_12.ts | 42 +- ...te__1_0_0_alpha_12__to___1_0_0_alpha_13.ts | 4 +- ...grate__1_0_0_alpha_1__to__1_0_0_alpha_2.ts | 70 +- ...rate__1_0_0_alpha_2__to___1_0_0_alpha_3.ts | 98 +- ...rate__1_0_0_alpha_3__to___1_0_0_alpha_4.ts | 26 +- ...rate__1_0_0_alpha_4__to___1_0_0_alpha_5.ts | 158 +- ...rate__1_0_0_alpha_5__to___1_0_0_alpha_6.ts | 32 +- ...rate__1_0_0_alpha_6__to___1_0_0_alpha_7.ts | 32 +- ...ate__1_0_0_alpha_7__to___1_0_0_alpha_8_.ts | 44 +- ...ate__1_0_0_alpha_8__to___1_0_0_alpha_9_.ts | 100 +- ...te__1_0_0_alpha_9__to___1_0_0_alpha_10_.ts | 86 +- ...migrate__1_0_0_alpha__to__1_0_0_alpha_1.ts | 566 +- .../store/state/migration/migration.types.ts | 38 +- libs/renderer/src/store/state/query.state.ts | 788 +- .../renderer/src/store/state/state.actions.ts | 6 +- .../src/store/state/state.constants.ts | 60 +- libs/renderer/src/store/state/state.store.ts | 14 +- libs/renderer/src/store/state/state.types.ts | 8 +- .../block-defaults/AccordionBlock.spec.tsx | 126 +- .../block-defaults/AudioBlock.spec.tsx | 230 +- .../block-defaults/CheckboxBlock.spec.tsx | 226 +- .../testing/block-defaults/ChipBlock.spec.tsx | 158 +- .../block-defaults/ContainerBlock.spec.tsx | 352 +- .../block-defaults/DividerBlock.spec.tsx | 146 +- .../testing/block-defaults/GridBlock.spec.tsx | 126 +- .../testing/block-defaults/HTMLBlock.spec.tsx | 116 +- .../testing/block-defaults/IconBlock.spec.tsx | 80 +- .../block-defaults/IframeBlock.spec.tsx | 192 +- .../block-defaults/ImageBlock.spec.tsx | 82 +- .../block-defaults/InputBlock.spec.tsx | 312 +- .../testing/block-defaults/LinkBlock.spec.tsx | 76 +- .../testing/block-defaults/LogsBlock.spec.tsx | 108 +- .../block-defaults/MarkdownBlock.spec.tsx | 114 +- .../testing/block-defaults/Popover.spec.tsx | 348 +- .../block-defaults/ProgressBlock.spec.tsx | 368 +- .../block-defaults/RadioBlock.spec.tsx | 258 +- .../block-defaults/RatingsBlock.spec.tsx | 117 +- .../block-defaults/SidebarBlock.spec.tsx | 142 +- .../block-defaults/SliderBlock.spec.tsx | 140 +- .../block-defaults/SwitchBlock.spec.tsx | 104 +- .../testing/block-defaults/TextBlock.spec.tsx | 122 +- .../block-defaults/TimePickerBlock.spec.tsx | 240 +- .../block-defaults/ToggleButtonBlock.spec.tsx | 456 +- .../block-defaults/UploadBlock.spec.tsx | 220 +- libs/renderer/src/testing/test.spec.ts | 10 +- libs/renderer/src/testing/utils/index.tsx | 216 +- libs/renderer/src/types/types.d.ts | 124 +- libs/renderer/src/utility/index.ts | 383 +- libs/renderer/tsconfig.json | 56 +- libs/renderer/vitest.config.ts | 65 +- libs/renderer/vitest.setup.ts | 74 +- libs/sdk/rollup.config.js | 53 +- libs/sdk/src/api/auth.ts | 128 +- libs/sdk/src/api/base.ts | 498 +- libs/sdk/src/api/file.ts | 138 +- libs/sdk/src/api/index.ts | 4 +- libs/sdk/src/constants.ts | 24 +- libs/sdk/src/env.ts | 122 +- libs/sdk/src/index.ts | 4 +- .../js-frameworks/react/InsightProvider.tsx | 180 +- libs/sdk/src/js-frameworks/react/index.ts | 3 +- .../src/js-frameworks/react/useDebounced.ts | 44 +- .../js-frameworks/react/useDebouncedValue.ts | 26 +- .../sdk/src/js-frameworks/react/useInsight.ts | 11 +- libs/sdk/src/js-frameworks/react/usePixel.ts | 276 +- libs/sdk/src/stores/insight/insight.store.ts | 1476 +- libs/sdk/src/types.ts | 20 +- libs/sdk/src/utility/error.ts | 14 +- libs/sdk/src/utility/fetch.ts | 186 +- libs/sdk/src/utility/index.ts | 2 +- libs/sdk/tsconfig.json | 54 +- libs/shared/src/flex-layout/Layout.tsx | 8 +- libs/shared/src/flex-layout/index.ts | 2 +- libs/shared/tsconfig.json | 2 +- libs/ui/.storybook/main.js | 57 +- libs/ui/.storybook/preview.js | 109 +- libs/ui/rollup.config.js | 97 +- .../Accordion/Accordion.stories.tsx | 46 +- .../ui/src/components/Accordion/Accordion.tsx | 94 +- .../components/Accordion/AccordionDetails.tsx | 24 +- .../components/Accordion/AccordionSummary.tsx | 32 +- libs/ui/src/components/Accordion/index.ts | 16 +- .../ui/src/components/Alert/Alert.stories.tsx | 52 +- libs/ui/src/components/Alert/Alert.tsx | 216 +- .../components/Alert/AlertTitle.stories.tsx | 14 +- libs/ui/src/components/Alert/AlertTitle.tsx | 28 +- libs/ui/src/components/Alert/index.ts | 6 +- .../src/components/AppBar/AppBar.stories.tsx | 16 +- libs/ui/src/components/AppBar/AppBar.tsx | 8 +- libs/ui/src/components/AppBar/index.ts | 2 +- .../Autocomplete/Autocomplete.stories.tsx | 178 +- .../components/Autocomplete/Autocomplete.tsx | 171 +- libs/ui/src/components/Autocomplete/index.ts | 2 +- .../src/components/Avatar/Avatar.stories.tsx | 26 +- libs/ui/src/components/Avatar/Avatar.tsx | 64 +- libs/ui/src/components/Avatar/index.ts | 2 +- .../AvatarGroup/AvatarGroup.stories.tsx | 50 +- .../components/AvatarGroup/AvatarGroup.tsx | 68 +- libs/ui/src/components/AvatarGroup/index.ts | 2 +- .../components/Backdrop/Backdrop.stories.tsx | 128 +- libs/ui/src/components/Backdrop/Backdrop.tsx | 32 +- libs/ui/src/components/Backdrop/index.ts | 2 +- .../ui/src/components/Badge/Badge.stories.tsx | 50 +- libs/ui/src/components/Badge/Badge.tsx | 106 +- libs/ui/src/components/Badge/index.ts | 2 +- libs/ui/src/components/Box/Box.stories.tsx | 6 +- libs/ui/src/components/Box/Box.tsx | 32 +- libs/ui/src/components/Box/index.ts | 2 +- .../Breadcrumbs/Breadcrumbs.stories.tsx | 154 +- .../components/Breadcrumbs/Breadcrumbs.tsx | 72 +- libs/ui/src/components/Breadcrumbs/index.ts | 6 +- .../src/components/Button/Button.stories.tsx | 52 +- libs/ui/src/components/Button/Button.tsx | 324 +- libs/ui/src/components/Button/index.ts | 2 +- .../ButtonGroup/ButtonGroup.stories.tsx | 18 +- .../components/ButtonGroup/ButtonGroup.tsx | 94 +- libs/ui/src/components/ButtonGroup/index.ts | 6 +- libs/ui/src/components/Card/Card.stories.tsx | 186 +- libs/ui/src/components/Card/Card.tsx | 24 +- .../ui/src/components/Card/CardActionArea.tsx | 27 +- .../components/Card/CardActions.stories.tsx | 71 +- libs/ui/src/components/Card/CardActions.tsx | 48 +- .../components/Card/CardContent.stories.tsx | 29 +- libs/ui/src/components/Card/CardContent.tsx | 38 +- .../components/Card/CardHeader.stories.tsx | 76 +- libs/ui/src/components/Card/CardHeader.tsx | 74 +- .../src/components/Card/CardMedia.stories.tsx | 7 +- libs/ui/src/components/Card/CardMedia.tsx | 56 +- libs/ui/src/components/Card/index.ts | 34 +- .../components/Checkbox/Checkbox.stories.tsx | 50 +- libs/ui/src/components/Checkbox/Checkbox.tsx | 209 +- libs/ui/src/components/Checkbox/index.ts | 2 +- .../Checklist/Checklist.stories.tsx | 22 +- .../ui/src/components/Checklist/Checklist.tsx | 88 +- libs/ui/src/components/Chip/Chip.stories.tsx | 74 +- libs/ui/src/components/Chip/Chip.tsx | 500 +- libs/ui/src/components/Chip/index.ts | 2 +- .../CircularProgress.stories.tsx | 38 +- .../CircularProgress/CircularProgress.tsx | 104 +- .../src/components/CircularProgress/index.ts | 5 +- libs/ui/src/components/Code/Code.stories.tsx | 27 +- libs/ui/src/components/Code/Code.tsx | 198 +- libs/ui/src/components/Code/CodeContainer.tsx | 32 +- libs/ui/src/components/Code/index.ts | 6 +- .../components/Collapse/Collapse.stories.tsx | 28 +- libs/ui/src/components/Collapse/Collapse.tsx | 66 +- libs/ui/src/components/Collapse/index.ts | 2 +- .../Container/Container.stories.tsx | 6 +- .../ui/src/components/Container/Container.tsx | 74 +- libs/ui/src/components/Container/index.ts | 2 +- .../DatePicker/DatePicker.stories.tsx | 32 +- .../src/components/DatePicker/DatePicker.tsx | 91 +- libs/ui/src/components/DatePicker/index.ts | 2 +- .../components/Divider/Divider.stories.tsx | 100 +- libs/ui/src/components/Divider/Divider.tsx | 100 +- libs/ui/src/components/Divider/index.ts | 2 +- .../src/components/Drawer/Drawer.stories.tsx | 48 +- libs/ui/src/components/Drawer/Drawer.tsx | 120 +- .../components/Dropzone/Dropzone.stories.tsx | 26 +- libs/ui/src/components/Dropzone/Dropzone.tsx | 153 +- libs/ui/src/components/Dropzone/index.ts | 2 +- .../components/FileDropzone/FileDisplay.tsx | 213 +- .../FileDropzone/FileDropzone.stories.tsx | 57 +- .../components/FileDropzone/FileDropzone.tsx | 719 +- .../components/FileDropzone/InputOptions.ts | 24 +- libs/ui/src/components/FileDropzone/index.ts | 2 +- .../src/components/FileDropzone/useValue.ts | 100 +- .../FileUpload/FileUpload.stories.tsx | 6 +- .../src/components/FileUpload/FileUpload.tsx | 14 +- libs/ui/src/components/FileUpload/index.ts | 2 +- .../components/FormControl/FormControl.tsx | 128 +- .../FormControl/FormControlLabel.tsx | 108 +- .../src/components/FormControl/FormLabel.tsx | 88 +- libs/ui/src/components/FormControl/index.ts | 11 +- libs/ui/src/components/Grid/Grid.stories.tsx | 88 +- libs/ui/src/components/Grid/index.ts | 2 +- libs/ui/src/components/Icon/Icon.stories.tsx | 54 +- libs/ui/src/components/Icon/index.ts | 2 +- .../IconButton/IconButton.stories.tsx | 66 +- libs/ui/src/components/IconButton/index.ts | 2 +- .../InputAdornment/InputAdornment.stories.tsx | 30 +- .../InputAdornment/InputAdornment.tsx | 14 +- .../ui/src/components/InputAdornment/index.ts | 2 +- .../LinearProgress/LinearProgress.stories.tsx | 137 +- .../LinearProgress/LinearProgress.tsx | 77 +- .../ui/src/components/LinearProgress/index.ts | 2 +- libs/ui/src/components/Link/Link.stories.tsx | 62 +- libs/ui/src/components/Link/Link.tsx | 100 +- libs/ui/src/components/Link/index.ts | 2 +- libs/ui/src/components/List/List.stories.tsx | 132 +- libs/ui/src/components/List/List.tsx | 76 +- .../src/components/List/ListItem.stories.tsx | 69 +- libs/ui/src/components/List/ListItem.tsx | 130 +- .../ui/src/components/List/ListItemAvatar.tsx | 17 +- .../List/ListItemButton.stories.tsx | 67 +- .../ui/src/components/List/ListItemButton.tsx | 106 +- .../components/List/ListItemIcon.stories.tsx | 25 +- libs/ui/src/components/List/ListItemIcon.tsx | 24 +- .../components/List/ListItemText.stories.tsx | 32 +- libs/ui/src/components/List/ListItemText.tsx | 22 +- libs/ui/src/components/List/index.ts | 34 +- .../LoadingScreen/LoadingScreen.tsx | 159 +- .../LoadingScreen/LoadingScreenContext.tsx | 29 +- .../LoadingScreen/LoadingScreenTrigger.tsx | 40 +- .../ui/src/components/LoadingScreen/index.tsx | 8 +- .../LoadingScreen/useLoadingScreen.tsx | 23 +- .../components/Markdown/Markdown.stories.tsx | 20 +- libs/ui/src/components/Markdown/Markdown.tsx | 233 +- libs/ui/src/components/Markdown/index.ts | 2 +- libs/ui/src/components/Menu/Menu.stories.tsx | 84 +- libs/ui/src/components/Menu/Menu.tsx | 134 +- .../src/components/Menu/MenuItem.stories.tsx | 68 +- libs/ui/src/components/Menu/MenuItem.tsx | 110 +- libs/ui/src/components/Menu/index.ts | 6 +- .../ui/src/components/Modal/Modal.stories.tsx | 96 +- libs/ui/src/components/Modal/Modal.tsx | 122 +- libs/ui/src/components/Modal/ModalActions.tsx | 40 +- libs/ui/src/components/Modal/ModalContent.tsx | 40 +- .../src/components/Modal/ModalContentText.tsx | 24 +- libs/ui/src/components/Modal/ModalTitle.tsx | 34 +- libs/ui/src/components/Modal/index.ts | 31 +- .../Notification/Notification.stories.tsx | 54 +- .../components/Notification/Notification.tsx | 324 +- .../Notification/NotificationContext.tsx | 37 +- .../Notification/notification.types.ts | 26 +- .../Notification/useNotification.tsx | 11 +- .../Pagination/Pagination.stories.tsx | 54 +- .../src/components/Pagination/Pagination.tsx | 128 +- libs/ui/src/components/Pagination/index.ts | 2 +- .../ui/src/components/Paper/Paper.stories.tsx | 8 +- libs/ui/src/components/Paper/Paper.tsx | 54 +- libs/ui/src/components/Paper/index.ts | 2 +- .../PhoneNumberPicker.stories.tsx | 29 +- .../PhoneNumberPicker/PhoneNumberPicker.tsx | 30 +- .../src/components/PhoneNumberPicker/index.ts | 5 +- .../components/Popover/Popover.stories.tsx | 141 +- libs/ui/src/components/Popover/Popover.tsx | 200 +- libs/ui/src/components/Popover/index.ts | 2 +- .../components/RadioGroup/Radio.stories.tsx | 50 +- libs/ui/src/components/RadioGroup/Radio.tsx | 224 +- .../RadioGroup/RadioGroup.stories.tsx | 72 +- .../src/components/RadioGroup/RadioGroup.tsx | 88 +- libs/ui/src/components/RadioGroup/index.ts | 6 +- .../src/components/Search/Search.stories.tsx | 38 +- libs/ui/src/components/Search/Search.tsx | 108 +- .../ui/src/components/Select/Item.stories.tsx | 96 +- .../src/components/Select/Select.stories.tsx | 208 +- libs/ui/src/components/Select/Select.tsx | 266 +- libs/ui/src/components/Select/index.ts | 4 +- .../components/SelectStack/Item.stories.tsx | 96 +- .../SelectStack/SelectStack.stories.tsx | 226 +- .../components/SelectStack/SelectStack.tsx | 346 +- libs/ui/src/components/SelectStack/index.ts | 4 +- .../components/Skeleton/Skeleton.stories.tsx | 30 +- libs/ui/src/components/Skeleton/Skeleton.tsx | 50 +- libs/ui/src/components/Skeleton/index.ts | 2 +- .../src/components/Slider/Slider.stories.tsx | 44 +- libs/ui/src/components/Slider/Slider.tsx | 122 +- libs/ui/src/components/Slider/index.ts | 2 +- .../components/Snackbar/Snackbar.stories.tsx | 92 +- libs/ui/src/components/Snackbar/Snackbar.tsx | 99 +- libs/ui/src/components/Snackbar/index.ts | 2 +- .../ui/src/components/Stack/Stack.stories.tsx | 56 +- libs/ui/src/components/Stack/Stack.tsx | 36 +- libs/ui/src/components/Stack/index.ts | 2 +- .../src/components/Switch/Switch.stories.tsx | 46 +- libs/ui/src/components/Switch/Switch.tsx | 228 +- libs/ui/src/components/Switch/index.ts | 2 +- .../ui/src/components/Table/Table.stories.tsx | 574 +- libs/ui/src/components/Table/Table.tsx | 48 +- .../components/Table/TableBody.stories.tsx | 14 +- libs/ui/src/components/Table/TableBody.tsx | 30 +- .../components/Table/TableCell.stories.tsx | 14 +- libs/ui/src/components/Table/TableCell.tsx | 107 +- .../Table/TableContainer.stories.tsx | 14 +- .../src/components/Table/TableContainer.tsx | 27 +- .../components/Table/TableFooter.stories.tsx | 12 +- libs/ui/src/components/Table/TableFooter.tsx | 26 +- .../components/Table/TableHead.stories.tsx | 14 +- libs/ui/src/components/Table/TableHead.tsx | 24 +- .../Table/TablePagination.stories.tsx | 32 +- .../src/components/Table/TablePagination.tsx | 105 +- .../src/components/Table/TableRow.stories.tsx | 14 +- libs/ui/src/components/Table/TableRow.tsx | 24 +- .../src/components/Table/TableSortLabel.tsx | 28 +- libs/ui/src/components/Table/index.ts | 53 +- libs/ui/src/components/Tabs/Tab.tsx | 70 +- libs/ui/src/components/Tabs/Tabs.stories.tsx | 120 +- libs/ui/src/components/Tabs/Tabs.tsx | 66 +- libs/ui/src/components/Tabs/index.ts | 6 +- .../components/Terminal/Terminal.stories.tsx | 113 +- libs/ui/src/components/Terminal/Terminal.tsx | 817 +- .../components/Terminal/TerminalSpinner.ts | 128 +- libs/ui/src/components/Terminal/index.ts | 2 +- libs/ui/src/components/Terminal/utility.ts | 132 +- .../components/TextArea/TextArea.stories.tsx | 41 +- libs/ui/src/components/TextArea/TextArea.tsx | 74 +- libs/ui/src/components/TextArea/index.ts | 2 +- .../TextField/TextField.stories.tsx | 10 +- .../ui/src/components/TextField/TextField.tsx | 30 +- libs/ui/src/components/TextField/index.ts | 2 +- .../TextFieldStack/TextFieldStack.stories.tsx | 10 +- .../TextFieldStack/TextFieldStack.tsx | 136 +- .../ui/src/components/TextFieldStack/index.ts | 2 +- .../ThemeProvider/ThemeProvider.stories.tsx | 47 +- .../ThemeProvider/ThemeProvider.tsx | 69 +- libs/ui/src/components/ThemeProvider/index.ts | 2 +- .../ToggleButton/ToggleButton.stories.tsx | 8 +- .../components/ToggleButton/ToggleButton.tsx | 128 +- libs/ui/src/components/ToggleButton/index.ts | 2 +- .../ToggleButtonGroup.stories.tsx | 30 +- .../ToggleButtonGroup/ToggleButtonGroup.tsx | 116 +- .../src/components/ToggleButtonGroup/index.ts | 5 +- .../components/ToggleTabsGroup/ToggleTab.tsx | 6 +- .../ToggleTabsGroup.stories.tsx | 107 +- .../ToggleTabsGroup/ToggleTabsGroup.tsx | 123 +- .../src/components/ToggleTabsGroup/index.ts | 4 +- .../components/Toolbar/Toolbar.stories.tsx | 16 +- libs/ui/src/components/Toolbar/Toolbar.tsx | 8 +- libs/ui/src/components/Toolbar/index.ts | 2 +- .../components/Tooltip/Tooltip.stories.tsx | 62 +- libs/ui/src/components/Tooltip/Tooltip.tsx | 134 +- libs/ui/src/components/Tooltip/index.ts | 2 +- libs/ui/src/components/TreeView/TreeItem.tsx | 22 +- .../components/TreeView/TreeView.stories.tsx | 98 +- libs/ui/src/components/TreeView/TreeView.tsx | 136 +- libs/ui/src/components/TreeView/index.ts | 6 +- .../TruncatedText/TruncatedText.tsx | 81 +- .../Typography/Typography.stories.tsx | 34 +- .../src/components/Typography/Typography.tsx | 154 +- libs/ui/src/components/Typography/index.ts | 2 +- libs/ui/src/index.ts | 125 +- libs/ui/src/theme.ts | 1796 +- libs/ui/tsconfig.json | 54 +- libs/ui/tsconfig.lib.json | 42 +- libs/ui/tsconfig.spec.json | 34 +- libs/ui/tsconfig.storybook.json | 50 +- packages/cli/.vscode/launch.json | 46 +- packages/cli/bin/dev.js | 4 +- packages/cli/bin/run.js | 4 +- packages/cli/src/commands/deploy.ts | 487 +- packages/cli/src/commands/init.ts | 363 +- packages/cli/src/constants.ts | 12 +- packages/cli/src/index.ts | 2 +- packages/cli/src/types.ts | 18 +- packages/cli/test/smss.json | 4 +- packages/cli/tsconfig.json | 26 +- packages/client/src/App.tsx | 279 +- packages/client/src/AppWrapper.tsx | 84 +- packages/client/src/api/auth.ts | 1482 +- packages/client/src/api/databases.ts | 131 +- packages/client/src/api/engines.ts | 642 +- packages/client/src/api/index.ts | 2 +- packages/client/src/api/projects.ts | 2 +- packages/client/src/api/teams.ts | 466 +- packages/client/src/assets/AddVariable.tsx | 56 +- packages/client/src/assets/Database.tsx | 52 +- packages/client/src/assets/ModelBrain.tsx | 36 +- packages/client/src/assets/blocks/index.ts | 225 +- packages/client/src/assets/img/AddPage.tsx | 28 +- packages/client/src/assets/img/AdminPanel.tsx | 36 +- packages/client/src/assets/img/ArchiveBox.tsx | 28 +- packages/client/src/assets/img/BuildDb.tsx | 54 +- packages/client/src/assets/img/ClosePage.tsx | 36 +- packages/client/src/assets/img/ConnectDb.tsx | 54 +- .../client/src/assets/img/ConnectModel.tsx | 54 +- .../client/src/assets/img/ConnectStorage.tsx | 54 +- .../client/src/assets/img/Construction.tsx | 36 +- packages/client/src/assets/img/CopyDb.tsx | 54 +- packages/client/src/assets/img/Database.tsx | 52 +- .../client/src/assets/img/DatabaseLayers.tsx | 44 +- packages/client/src/assets/img/Folder.tsx | 38 +- packages/client/src/assets/img/Function.tsx | 39 +- packages/client/src/assets/img/Group.tsx | 52 +- .../client/src/assets/img/GroupRounded.tsx | 84 +- packages/client/src/assets/img/Java.tsx | 68 +- packages/client/src/assets/img/Jobs.tsx | 28 +- packages/client/src/assets/img/Link.tsx | 30 +- packages/client/src/assets/img/ModelBrain.tsx | 36 +- .../client/src/assets/img/NotebookIcon.tsx | 20 +- .../client/src/assets/img/PaintRounded.tsx | 28 +- .../client/src/assets/img/PersonRounded.tsx | 36 +- packages/client/src/assets/img/SEMOSS.tsx | 50 +- packages/client/src/assets/img/Vector.tsx | 36 +- .../client/src/components/app/AppCards.tsx | 104 +- .../src/components/app/AppDeleteModal.tsx | 135 +- .../client/src/components/app/AppFilter.tsx | 94 +- .../src/components/app/AppLandscapeCard.tsx | 574 +- .../client/src/components/app/AppSettings.tsx | 1640 +- .../src/components/app/AppTemplates.tsx | 176 +- .../client/src/components/app/AppTileCard.tsx | 1921 +- .../components/app/BrowseTempateTitleCard.tsx | 748 +- .../src/components/app/ChangeAccessModal.tsx | 427 +- .../src/components/app/DependencyTable.tsx | 147 +- .../components/app/EditDependenciesModal.tsx | 383 +- .../src/components/app/EditDetailsModal.tsx | 686 +- .../client/src/components/app/NewAppModal.tsx | 688 +- .../client/src/components/app/NewAppStep.tsx | 125 +- .../src/components/app/app-details.utility.ts | 362 +- .../client/src/components/app/app.images.ts | 80 +- .../client/src/components/app/app.types.ts | 48 +- packages/client/src/components/app/index.ts | 33 +- .../app/save-app/AddAppCloneModal.tsx | 9 +- .../components/app/save-app/AddAppModal.tsx | 15 +- .../components/app/save-app/AppAccessStep.tsx | 164 +- .../app/save-app/AppDetailsStep.tsx | 80 +- .../components/app/save-app/AppTagsStep.tsx | 62 +- .../components/app/save-app/AppUploadStep.tsx | 217 +- .../components/app/save-app/SaveAppModal.tsx | 2 +- .../src/components/app/save-app/index.ts | 4 +- .../app/save-app/save-app.constants.ts | 14 +- .../components/app/save-app/save-app.types.ts | 18 +- .../app/templates/AskCSVTemplate.tsx | 729 +- .../app/templates/AskLLMTemplate.ts | 545 +- .../app/templates/BlocksGuideTemplate.ts | 1957 +- .../templates/CreateDiabetesRecordTemplate.ts | 2381 +- .../templates/DeleteDiabetesRecordTemplate.ts | 553 +- .../app/templates/LandingPageTemplate.ts | 2170 +- .../app/templates/MultiPageTemplate.tsx | 594 +- .../templates/ReadDiabetesRecordTemplate.ts | 485 +- .../templates/UpdateDiabetesRecordTemplate.ts | 2599 +- .../app/templates/VisualizeCSVTemplate.tsx | 2 +- .../src/components/app/templates/index.ts | 23 +- .../app/templates/templates.types.ts | 30 +- .../blocks-workspace/BlocksWorkspace.tsx | 585 +- .../BlocksWorkspaceActions.tsx | 502 +- .../blocks-workspace/BlocksWorkspaceDev.tsx | 417 +- .../block-settings/accordion-block/config.tsx | 139 +- .../block-settings/accordion-block/index.ts | 2 +- .../block-settings/audio-block/config.tsx | 149 +- .../block-settings/audio-block/index.ts | 2 +- .../audio-input-block/config.tsx | 269 +- .../block-settings/audio-input-block/index.ts | 2 +- .../block-defaults.constants.tsx | 66 +- .../block-settings/block-defaults.shared.tsx | 1084 +- .../block-settings/button-block/config.tsx | 280 +- .../block-settings/button-block/index.ts | 2 +- .../block-settings/checkbox-block/config.tsx | 80 +- .../block-settings/checkbox-block/index.ts | 2 +- .../block-settings/chip-block/config.tsx | 279 +- .../blocks/block-settings/chip-block/index.ts | 2 +- .../block-settings/container-block/config.tsx | 201 +- .../block-settings/container-block/index.ts | 2 +- .../block-settings/divider-block/config.tsx | 245 +- .../block-settings/divider-block/index.ts | 2 +- .../echart-visualization-block/config.tsx | 15 +- .../echart-visualization-block/index.ts | 2 +- .../block-settings/flip-card-block/config.tsx | 144 +- .../block-settings/flip-card-block/index.ts | 2 +- .../block-settings/grid-block/config.tsx | 15 +- .../blocks/block-settings/grid-block/index.ts | 2 +- .../grid-dynamic-frame-block/config.tsx | 39 +- .../grid-dynamic-frame-block/index.ts | 2 +- .../block-settings/html-block/config.tsx | 14 +- .../blocks/block-settings/html-block/index.ts | 2 +- .../block-settings/icon-block/config.tsx | 115 +- .../blocks/block-settings/icon-block/index.ts | 2 +- .../block-settings/iframe-block/config.tsx | 141 +- .../block-settings/iframe-block/index.ts | 2 +- .../block-settings/image-block/config.tsx | 270 +- .../block-settings/image-block/index.ts | 2 +- .../block-settings/input-block/config.tsx | 259 +- .../block-settings/input-block/index.ts | 2 +- .../block-settings/iteration-block/config.tsx | 73 +- .../block-settings/iteration-block/index.ts | 2 +- .../block-settings/link-block/config.tsx | 88 +- .../blocks/block-settings/link-block/index.ts | 2 +- .../block-settings/logs-block/config.tsx | 67 +- .../blocks/block-settings/logs-block/index.ts | 2 +- .../block-settings/markdown-block/config.tsx | 104 +- .../block-settings/markdown-block/index.ts | 2 +- .../block-settings/mermaid-block/config.tsx | 15 +- .../block-settings/mermaid-block/index.ts | 2 +- .../block-settings/modal-block/config.tsx | 329 +- .../block-settings/modal-block/index.ts | 2 +- .../block-settings/page-block/config.tsx | 163 +- .../blocks/block-settings/page-block/index.ts | 2 +- .../block-settings/pdfViewer-block/config.tsx | 55 +- .../block-settings/pdfViewer-block/index.ts | 2 +- .../block-settings/popover-block/config.tsx | 349 +- .../block-settings/popover-block/index.ts | 2 +- .../block-settings/progress-block/config.tsx | 167 +- .../block-settings/progress-block/index.ts | 2 +- .../block-settings/radio-block/config.tsx | 950 +- .../block-settings/radio-block/index.ts | 2 +- .../block-settings/ratings-block/config.tsx | 177 +- .../block-settings/ratings-block/index.ts | 2 +- .../block-settings/select-block/config.tsx | 2 +- .../block-settings/select-block/index.ts | 2 +- .../blocks/block-settings/settings.types.ts | 70 +- .../block-settings/sidebar-block/config.tsx | 261 +- .../block-settings/sidebar-block/index.ts | 2 +- .../block-settings/slider-block/config.tsx | 340 +- .../block-settings/slider-block/index.ts | 2 +- .../block-settings/switch-block/config.tsx | 301 +- .../block-settings/switch-block/index.ts | 2 +- .../block-settings/text-block/config.tsx | 98 +- .../blocks/block-settings/text-block/index.ts | 2 +- .../block-settings/theme-block/config.tsx | 586 +- .../block-settings/theme-block/index.ts | 2 +- .../time-picker-block/config.tsx | 359 +- .../block-settings/time-picker-block/index.ts | 2 +- .../toggle-button-block/config.tsx | 213 +- .../toggle-button-block/index.ts | 2 +- .../block-settings/upload-block/config.tsx | 225 +- .../block-settings/upload-block/index.ts | 2 +- .../vega-visualization-block/config.tsx | 15 +- .../vega-visualization-block/index.ts | 2 +- .../visualization-filter-block/config.tsx | 15 +- .../visualization-filter-block/index.ts | 2 +- .../blocks-workspace/blocks/constants.ts | 76 +- .../blocks-workspace/blocks/index.ts | 176 +- .../blocks/settings/BaseSettingSection.tsx | 74 +- .../blocks/settings/ListenerActionOverlay.tsx | 246 +- .../blocks/settings/ListenerSettings.tsx | 766 +- .../block-events/ActionFormFields.tsx | 117 +- .../block-events/ActionTypeSelector.tsx | 80 +- .../block-events/BlockEventNameSelector.tsx | 34 +- .../settings/block-events/CellIdSelector.tsx | 69 +- .../settings/block-events/QueryIdSelector.tsx | 54 +- .../RedirectDestinationSelector.tsx | 132 +- .../blocks/settings/block-events/index.ts | 8 +- .../block-events/useEventActionData.tsx | 52 +- .../blocks/settings/block-events/utils.ts | 82 +- .../blocks/settings/custom/BorderSettings.tsx | 556 +- .../blocks/settings/custom/ChipSettings.tsx | 406 +- .../custom/ContainerLayoutSettings.tsx | 1402 +- .../settings/custom/FontSizeSettings.tsx | 306 +- .../settings/custom/IconSelectSettings.tsx | 284 +- .../settings/custom/OptionsSettings.tsx | 655 +- .../settings/custom/QueryInputSettings.tsx | 1754 +- .../custom/QueryNameDropdownSettings.tsx | 222 +- .../custom/QuerySelectionSettings.tsx | 294 +- .../custom/SelectInputOptionsSettings.tsx | 194 +- .../custom/SelectInputValueSettings.tsx | 320 +- .../settings/custom/SizeSpacingSettings.tsx | 972 +- .../dynamic-headers/DynamicGridMenu.tsx | 82 +- .../custom/data-grid/dynamic-headers/index.ts | 2 +- .../blocks/settings/custom/data-grid/index.ts | 2 +- .../settings/custom/e-charts/VisualMap.tsx | 368 +- .../custom/e-charts/VisualMapConstant.tsx | 2395 +- .../e-charts/Visualization.constants.ts | 128 +- .../e-charts/VisualizationBlockMenu.tsx | 465 +- .../custom/e-charts/variant/Constant.tsx | 384 +- .../e-charts/variant/FrameOperations.tsx | 4105 +- .../variant/Gantt/CustomizeSymbol.tsx | 1303 +- .../variant/Gantt/GanttDisplayValueLabels.tsx | 204 +- .../e-charts/variant/Gantt/GanttFiscal.tsx | 585 +- .../variant/Gantt/GanttFrameSection.tsx | 863 +- .../e-charts/variant/Gantt/GanttGroupView.tsx | 196 +- .../e-charts/variant/Gantt/GanttLegend.tsx | 190 +- .../variant/Gantt/GanttTargetLine.tsx | 575 +- .../variant/bar-chart/ChartStyling.tsx | 735 +- .../variant/bar-chart/ColourByValue.tsx | 1304 +- .../bar-chart/CustomizeValueLabels.tsx | 1345 +- .../variant/bar-chart/DataTabStyling.tsx | 1430 +- .../variant/bar-chart/Edit-X-Axis.tsx | 970 +- .../variant/bar-chart/Edit-Y-Axis.tsx | 1021 +- .../e-charts/variant/bar-chart/Legend.tsx | 291 +- .../variant/bar-chart/ToggleTrendline.tsx | 605 +- .../bar-chart/UpgradedVisualizationTool.tsx | 3184 +- .../variant/bar-chart/VisualizationStyles.tsx | 573 +- .../variant/dendrogram/ChangeOrientation.tsx | 230 +- .../dendrogram/CustomizeDendrogramSymbol.tsx | 405 +- .../variant/dendrogram/LabelsDendrogram.tsx | 384 +- .../variant/dendrogram/LegendDendrogram.tsx | 196 +- .../variant/line-chart/LineLegend.tsx | 188 +- .../variant/line-chart/LineStyling.tsx | 503 +- .../e-charts/variant/line-chart/LineTitle.tsx | 763 +- .../variant/line-chart/LineTooltip.tsx | 219 +- .../variant/line-chart/LineValueLabel.tsx | 1347 +- .../variant/line-chart/XAxisStyling.tsx | 612 +- .../variant/line-chart/YAxisStyling.tsx | 635 +- .../map-chart/LegendToggleMapChart.tsx | 164 +- .../variant/map-chart/MapMarkerSize.tsx | 209 +- .../variant/map-chart/TooltipMapChart.tsx | 195 +- .../variant/pie-chart/CustomTooltip.tsx | 170 +- .../e-charts/variant/pie-chart/PieLegend.tsx | 171 +- .../e-charts/variant/pie-chart/PieTitle.tsx | 692 +- .../variant/pie-chart/PieValueLabel.tsx | 718 +- .../variant/pie-chart/ToggleDonut.tsx | 184 +- .../scatter-plot/EditXAxisScatterPlot.tsx | 1076 +- .../scatter-plot/EditYAxisScatterPlot.tsx | 956 +- .../scatter-plot/ScatterPlotChartTitle.tsx | 211 +- .../scatter-plot/ScatterPlotSymbol.tsx | 278 +- .../scatter-plot/TooltipScatterPlot.tsx | 204 +- .../scatter-plot/ValueLabelScatterPlot.tsx | 696 +- .../e-charts/variant/shared/chart-utility.ts | 24 +- .../stack-chart/EditXAxisStackChart.tsx | 1047 +- .../stack-chart/EditYAxisStackChart.tsx | 921 +- .../variant/stack-chart/LegendStackChart.tsx | 194 +- .../stack-chart/StackChartBarStyle.tsx | 286 +- .../stack-chart/ValueLabelStackChart.tsx | 655 +- .../grid-two/GridBlockColumnSettings.tsx | 443 +- .../grid-two/GridBlockColumnSettingsItem.tsx | 122 +- .../custom/grid-two/GridBlockMenu.tsx | 178 +- .../custom/grid-two/GridBlockTool.tsx | 608 +- .../grid-two/operations/CellStyling.tsx | 499 +- .../custom/grid-two/operations/ChartTitle.tsx | 424 +- .../grid-two/operations/ColorByValue.tsx | 816 +- .../operations/GridResizeSettings.tsx | 387 +- .../grid-two/operations/HeaderStyling.tsx | 504 +- .../grid-two/operations/RowSpanning.tsx | 139 +- .../grid-two/operations/WrapTextSettings.tsx | 371 +- .../settings/custom/grid/GridSettings.tsx | 320 +- .../custom/grid/icons/FourByFourIcon.tsx | 42 +- .../custom/grid/icons/OneByThreeIcon.tsx | 34 +- .../custom/grid/icons/OneByTwoIcon.tsx | 60 +- .../custom/grid/icons/ThreeByThreeIcon.tsx | 36 +- .../custom/grid/icons/TwoByTwoIcon.tsx | 34 +- .../settings/custom/grid/icons/index.ts | 10 +- .../blocks/settings/custom/grid/index.ts | 2 +- .../settings/custom/html/HTMLBlockMenu.tsx | 130 +- .../blocks/settings/custom/index.ts | 26 +- .../custom/mermaid/MermaidBlockMenu.tsx | 102 +- .../vega/VegaVisualizationBlockMenu.tsx | 132 +- .../VisualizationFilterMenu.tsx | 1118 +- .../blocks-workspace/blocks/settings/index.ts | 8 +- .../settings/shared/AIGenerationSettings.tsx | 478 +- .../settings/shared/BoxShadowSizeSetting.tsx | 258 +- .../settings/shared/ButtonGroupSettings.tsx | 244 +- .../settings/shared/CodeEditorSettings.tsx | 799 +- .../settings/shared/ColorPalatteSettings.tsx | 2093 +- .../settings/shared/ColorPickerSettings.tsx | 418 +- .../shared/ColorPickerSettingsNew.tsx | 402 +- .../settings/shared/ColorPickerWithSwatch.tsx | 98 +- .../blocks/settings/shared/ColorSettings.tsx | 220 +- .../shared/ConditionalVariationSettings.tsx | 73 +- .../shared/DistinctPathButtonGroupButton.tsx | 271 +- .../DistinctPathButtonGroupSettings.tsx | 98 +- .../settings/shared/IconGeneralSettings.tsx | 168 +- .../settings/shared/InputAudioSettings.tsx | 562 +- .../settings/shared/InputModalSettings.tsx | 352 +- .../blocks/settings/shared/InputSettings.tsx | 340 +- .../blocks/settings/shared/JsonSettings.tsx | 624 +- .../settings/shared/PDFViewerSettings.tsx | 138 +- .../blocks/settings/shared/ResizeSetting.tsx | 349 +- .../settings/shared/SelectInputSettings.tsx | 467 +- .../settings/shared/SelectOptionsSettings.tsx | 488 +- .../blocks/settings/shared/SelectSettings.tsx | 234 +- .../blocks/settings/shared/SizeSettings.tsx | 361 +- .../settings/shared/StandardColorSettings.tsx | 300 +- .../blocks/settings/shared/SwitchSettings.tsx | 306 +- .../blocks/settings/shared/UploadSettings.tsx | 282 +- .../blocks/settings/shared/index.ts | 33 +- .../src/components/blocks-workspace/index.ts | 5 +- .../blocks-workspace/menus/default-menu.ts | 2 +- .../blocks-workspace/menus/menu-types.ts | 98 +- .../panels/BlocksMenuPanel.tsx | 890 +- .../panels/BlocksMenuPanelFilterMenu.tsx | 224 +- .../blocks-workspace/panels/DesignerPanel.tsx | 23 +- .../blocks-workspace/panels/LayersPanel.tsx | 2748 +- .../panels/NotebookExplorerPanel.tsx | 977 +- .../panels/NotebookExplorerPanelItem.tsx | 390 +- .../panels/NotebookViewerPanel.tsx | 27 +- .../panels/SelectedBlockPanel.tsx | 1135 +- .../panels/VariablesPanel.tsx | 565 +- .../blocks-workspace/panels/index.ts | 14 +- .../code-workspace/CodeRenderer.tsx | 34 +- .../code-workspace/CodeWorkspace.tsx | 221 +- .../code-workspace/CodeWorkspaceActions.tsx | 52 +- .../src/components/code-workspace/index.ts | 4 +- .../code-workspace/panels/RendererPanel.tsx | 66 +- .../components/code-workspace/panels/index.ts | 2 +- .../src/components/common/ErrorBoundary.tsx | 156 +- .../components/common/File/AddFileOverlay.tsx | 214 +- .../common/File/CreateFileOverlay.tsx | 252 +- .../common/File/DeleteFileOverlay.tsx | 130 +- .../src/components/common/File/FileEditor.tsx | 895 +- .../components/common/File/FileExplorer.tsx | 292 +- .../common/File/FileExplorerItem.tsx | 372 +- .../src/components/common/File/index.ts | 10 +- .../common/MarkdownEditor/MarkdownEditor.tsx | 150 +- .../components/common/MarkdownEditor/index.ts | 2 +- .../TextEditor/TextEditorCodeGeneration.tsx | 467 +- .../src/components/common/TextEditor/index.ts | 2 +- .../client/src/components/common/index.ts | 8 +- .../src/components/cookies/CookieWrapper.tsx | 231 +- .../cookies/PrivacyPreferenceCenterModal.tsx | 254 +- .../client/src/components/cookies/index.ts | 2 +- .../database/DatabaseStatistics.tsx | 276 +- .../components/designer/AddBlocksMenuCard.tsx | 2 +- .../src/components/designer/BlockAvatar.tsx | 22 +- .../designer/BlockMenuCardContent.tsx | 60 +- .../components/designer/BlockSettingsMask.tsx | 278 +- .../designer/DeleteDuplicateMask.tsx | 844 +- .../src/components/designer/Designer.tsx | 45 +- .../client/src/components/designer/Ghost.tsx | 125 +- .../src/components/designer/HoveredMask.tsx | 238 +- .../src/components/designer/Placeholder.tsx | 129 +- .../src/components/designer/QuickMenu.tsx | 110 +- .../client/src/components/designer/Screen.tsx | 696 +- .../src/components/designer/SelectedMask.tsx | 842 +- .../designer/SelectedMenuSection.tsx | 219 +- .../client/src/components/designer/index.ts | 9 +- .../settings-mask/TextSettingsMask.tsx | 278 +- .../components/engine/EditEngineDetails.tsx | 939 +- .../components/engine/EngineAccessButton.tsx | 533 +- .../src/components/engine/EngineHeader.tsx | 450 +- .../components/engine/GenericEngineCards.tsx | 1177 +- .../client/src/components/engine/index.ts | 8 +- packages/client/src/components/help/Help.tsx | 154 +- packages/client/src/components/help/index.ts | 2 +- .../src/components/import/ImportForm.tsx | 2415 +- .../client/src/components/import/index.ts | 2 +- .../import/refactor/CopyDatabaseForm.tsx | 84 +- .../components/import/refactor/UploadData.tsx | 20 +- .../components/import/refactor/formTypes.d.ts | 38 +- .../src/components/insight/InsightCards.tsx | 130 +- .../client/src/components/insight/index.ts | 2 +- .../src/components/landing/BannerSection.tsx | 139 +- .../components/landing/BusinessUserScreen.tsx | 223 +- .../components/landing/CreateAppSection.tsx | 306 +- .../landing/DeveloperUserScreen.tsx | 236 +- .../landing/FanFavoritesSection.tsx | 177 +- .../client/src/components/landing/index.ts | 4 +- .../src/components/llms/LLMSelectOverlay.tsx | 103 +- packages/client/src/components/llms/index.ts | 2 +- .../src/components/metamodel/FloatingEdge.tsx | 77 +- .../src/components/metamodel/Metamodel.tsx | 510 +- .../components/metamodel/MetamodelNode.tsx | 812 +- .../client/src/components/metamodel/index.ts | 2 +- .../src/components/metamodel/utility.ts | 106 +- .../components/notebook/AddVariableModal.tsx | 205 +- .../notebook/AddVariablePopover.tsx | 6 +- .../notebook/DeleteNotebookOverlay.tsx | 133 +- .../components/notebook/NewQueryOverlay.tsx | 295 +- .../src/components/notebook/Notebook.tsx | 336 +- .../components/notebook/NotebookAddCell.tsx | 1101 +- .../src/components/notebook/NotebookCell.tsx | 1882 +- .../notebook/NotebookCellConsole.tsx | 74 +- .../components/notebook/NotebookVariable.tsx | 711 +- .../components/notebook/VariablePreview.tsx | 364 +- .../client/src/components/notebook/index.ts | 13 +- .../notebook/operations/DefaultOperation.tsx | 58 +- .../notebook/operations/ErrorOperation.tsx | 24 +- .../notebook/operations/FrameOperation.tsx | 145 +- .../notebook/operations/Operations.tsx | 96 +- .../notebook/operations/SuccessOperation.tsx | 52 +- .../notebook/operations/WarningOperation.tsx | 25 +- .../components/notebook/operations/index.ts | 2 +- .../prompt/builder/PromptBuilder.tsx | 2 +- .../src/components/prompt/builder/index.ts | 2 +- .../step/PromptBuilderConstraintsStep.tsx | 384 +- .../builder/step/PromptBuilderContextStep.tsx | 282 +- .../step/PromptBuilderContextTestDialog.tsx | 188 +- .../PromptBuilderContextTestDialogButton.tsx | 112 +- .../builder/step/PromptBuilderInputStep.tsx | 790 +- .../step/PromptBuilderInputTypeSelection.tsx | 336 +- .../step/PromptBuilderInputTypeStep.tsx | 302 +- .../builder/step/PromptBuilderPreviewStep.tsx | 58 +- .../prompt/builder/step/PromptBuilderStep.tsx | 70 +- .../components/prompt/builder/step/index.ts | 2 +- .../builder/summary/PromptBuilderSummary.tsx | 322 +- .../summary/PromptBuilderSummaryProgress.tsx | 50 +- .../prompt/builder/summary/index.ts | 2 +- .../client/src/components/prompt/index.ts | 10 +- .../components/prompt/library/PromptCard.tsx | 186 +- .../prompt/library/PromptLibraryCards.tsx | 104 +- .../prompt/library/PromptLibraryDialog.tsx | 202 +- .../library/PromptLibraryDialogButton.tsx | 110 +- .../prompt/library/PromptLibraryList.tsx | 150 +- .../src/components/prompt/library/examples.ts | 942 +- .../src/components/prompt/prompt.constants.ts | 100 +- .../src/components/prompt/prompt.helpers.ts | 1277 +- .../src/components/prompt/prompt.styled.tsx | 94 +- .../src/components/prompt/prompt.types.ts | 70 +- .../prompt/shared/PromptPreview.tsx | 50 +- .../src/components/prompt/shared/index.ts | 4 +- .../prompt/shared/token/PromptHoverToken.tsx | 75 +- .../shared/token/PromptReadonlyInputToken.tsx | 20 +- .../prompt/shared/token/PromptSetToken.tsx | 230 +- .../prompt/shared/token/PromptTokenChip.tsx | 90 +- .../shared/token/PromptTokenTextButton.tsx | 41 +- .../components/prompt/shared/token/index.ts | 6 +- .../components/settings/EngineQASidebar.tsx | 224 +- .../src/components/settings/FileTable.tsx | 1402 +- .../components/settings/MembersAddOverlay.tsx | 1868 +- .../settings/MembersAddOverlayUser.tsx | 202 +- .../settings/MembersDeleteOverlay.tsx | 270 +- .../src/components/settings/MembersTable.tsx | 2455 +- .../settings/PendingMembersTable.tsx | 1441 +- .../src/components/settings/SettingsTiles.tsx | 1408 +- .../src/components/settings/UpdateSMSS.tsx | 359 +- .../components/settings/UserAddOverlay.tsx | 1634 +- .../src/components/settings/UserPopover.tsx | 242 +- .../src/components/settings/UserTable.tsx | 1584 +- .../client/src/components/settings/index.ts | 16 +- .../src/components/settings/settings.types.ts | 34 +- .../src/components/shared/LogoutPopover.tsx | 3 +- .../client/src/components/shared/Navbar.tsx | 180 +- .../src/components/shared/NavbarHeader.tsx | 6 +- .../src/components/shared/NavbarLeft.tsx | 32 +- .../src/components/shared/NavbarRight.tsx | 32 +- .../client/src/components/shared/Page.tsx | 85 +- .../components/shared/PlatformMessages.tsx | 117 +- .../client/src/components/shared/Search.tsx | 990 +- .../client/src/components/shared/index.ts | 24 +- .../src/components/teams/AddTeamModal.tsx | 838 +- .../src/components/teams/TeamEnginesTable.tsx | 4 +- .../teams/TeamMembersProviderBanner.tsx | 150 +- .../src/components/teams/TeamMembersTable.tsx | 2077 +- .../components/teams/TeamProjectsTable.tsx | 4 +- .../src/components/teams/TeamTileCard.tsx | 1470 +- packages/client/src/components/teams/index.ts | 10 +- .../src/components/ui/Filterbox/Filterbox.tsx | 1030 +- .../src/components/ui/Filterbox/index.ts | 2 +- .../ui/LoadingScreen/LoadingScreen.tsx | 160 +- .../ui/LoadingScreen/LoadingScreenContext.tsx | 29 +- .../ui/LoadingScreen/LoadingScreenTrigger.tsx | 42 +- .../src/components/ui/LoadingScreen/index.ts | 10 +- .../ui/LoadingScreen/useLoadingScreen.tsx | 27 +- .../src/components/ui/Section/Section.tsx | 48 +- .../components/ui/Section/SectionHeader.tsx | 48 +- .../client/src/components/ui/Section/index.ts | 6 +- .../src/components/ui/Share/ShareOverlay.tsx | 256 +- .../client/src/components/ui/Share/index.ts | 2 +- packages/client/src/components/ui/index.ts | 8 +- .../components/workspace/PreviewOverlay.tsx | 63 +- .../src/components/workspace/Workspace.tsx | 11 +- .../components/workspace/WorkspaceLoading.tsx | 17 +- .../components/workspace/WorkspaceOverlay.tsx | 33 +- .../client/src/components/workspace/index.ts | 7 +- .../workspace/panels/EmptyFilePanel.tsx | 101 +- .../workspace/panels/FileEditorPanel.tsx | 303 +- .../workspace/panels/FileExplorerPanel.tsx | 1251 +- .../workspace/panels/GraphPanel.tsx | 33 +- .../src/components/workspace/panels/Panel.tsx | 94 +- .../workspace/panels/SettingsPanel.tsx | 351 +- .../workspace/panels/TerminalPanel.tsx | 447 +- .../src/components/workspace/panels/index.tsx | 13 +- packages/client/src/constants.ts | 74 +- .../client/src/contexts/DesignerContext.tsx | 9 +- .../client/src/contexts/EngineContext.tsx | 43 +- packages/client/src/contexts/LLMContext.tsx | 14 +- .../client/src/contexts/MetamodelContext.tsx | 18 +- packages/client/src/contexts/PageContext.tsx | 11 +- .../client/src/contexts/RootStoreContext.tsx | 5 +- .../client/src/contexts/SettingsContext.tsx | 6 +- .../client/src/contexts/StepperContext.tsx | 88 +- .../client/src/contexts/WorkspaceContext.tsx | 11 +- packages/client/src/contexts/index.ts | 63 +- packages/client/src/global.d.ts | 44 +- packages/client/src/hooks/index.ts | 52 +- packages/client/src/hooks/useAPI.ts | 255 +- .../client/src/hooks/useBlockSettings.tsx | 227 +- packages/client/src/hooks/useCacheState.ts | 74 +- packages/client/src/hooks/useDesigner.ts | 15 +- packages/client/src/hooks/useEngine.tsx | 15 +- packages/client/src/hooks/useLLM.tsx | 15 +- packages/client/src/hooks/useMetamodel.ts | 15 +- packages/client/src/hooks/usePage.ts | 87 +- packages/client/src/hooks/usePixel.ts | 279 +- packages/client/src/hooks/useRootStore.ts | 15 +- packages/client/src/hooks/useSettings.ts | 15 +- packages/client/src/hooks/useStepper.ts | 19 +- packages/client/src/hooks/useWorkspace.ts | 19 +- packages/client/src/main.tsx | 27 +- .../client/src/pages/AuthenticatedLayout.tsx | 29 +- packages/client/src/pages/ErrorPage.tsx | 98 +- packages/client/src/pages/LoginPage.tsx | 2495 +- packages/client/src/pages/PageLayout.tsx | 55 +- packages/client/src/pages/Router.tsx | 137 +- packages/client/src/pages/SharePage.tsx | 211 +- .../client/src/pages/app/AppCatalogPage.tsx | 2 +- .../client/src/pages/app/AppDetailPage.tsx | 1931 +- .../src/pages/app/AppMarketplacePage.tsx | 337 +- .../client/src/pages/app/CreateAppPage.tsx | 272 +- packages/client/src/pages/app/EditAppPage.tsx | 221 +- .../src/pages/app/NewPromptBuilderAppPage.tsx | 29 +- packages/client/src/pages/app/ViewAppPage.tsx | 332 +- .../client/src/pages/app/app.constants.ts | 164 +- packages/client/src/pages/app/index.ts | 28 +- .../src/pages/engine/EngineFilePage.tsx | 60 +- .../src/pages/engine/EngineIndexPage.tsx | 1356 +- .../client/src/pages/engine/EngineLayout.tsx | 445 +- .../src/pages/engine/EngineMetadataPage.tsx | 734 +- .../src/pages/engine/EngineOverviewPage.tsx | 166 +- .../client/src/pages/engine/EngineQAPage.tsx | 484 +- .../client/src/pages/engine/EngineRouter.tsx | 106 +- .../src/pages/engine/EngineSettingsPage.tsx | 77 +- .../src/pages/engine/EngineSmssPage.tsx | 46 +- .../src/pages/engine/EngineUsagePage.tsx | 145 +- .../src/pages/engine/SyncChangesModal.tsx | 365 +- .../src/pages/engine/engine.constants.ts | 472 +- packages/client/src/pages/engine/index.ts | 2 +- .../pages/import/EstablishConnectionPage.tsx | 981 +- .../src/pages/import/ImportConnectionPage.tsx | 578 +- .../client/src/pages/import/ImportLayout.tsx | 135 +- .../client/src/pages/import/ImportPage.tsx | 37 +- .../src/pages/import/ImportPageContent.tsx | 1384 +- .../src/pages/import/import.constants.ts | 31013 ++++++++-------- packages/client/src/pages/import/index.ts | 13 +- packages/client/src/pages/index.ts | 2 +- .../client/src/pages/jobs/DeleteJobModal.tsx | 86 +- packages/client/src/pages/jobs/HistoryRow.tsx | 123 +- .../client/src/pages/jobs/JobBuilderModal.tsx | 808 +- packages/client/src/pages/jobs/JobCard.tsx | 64 +- .../pages/jobs/JobCustomFrequencyBuilder.tsx | 216 +- packages/client/src/pages/jobs/JobHistory.tsx | 202 +- .../jobs/JobStandardFrequencyBuilder.tsx | 388 +- .../client/src/pages/jobs/JobTypesBuilder.tsx | 75 +- .../pages/jobs/JobTypesCustomJobBuilder.tsx | 93 +- .../pages/jobs/JobTypesSendEmailBuilder.tsx | 311 +- packages/client/src/pages/jobs/JobsPage.tsx | 1398 +- packages/client/src/pages/jobs/JobsTable.tsx | 500 +- .../client/src/pages/jobs/job.constants.tsx | 1470 +- packages/client/src/pages/jobs/job.types.ts | 308 +- packages/client/src/pages/jobs/job.utils.ts | 294 +- .../client/src/pages/legal/CookieNotice.tsx | 20 +- .../client/src/pages/legal/PrivacyNotice.tsx | 20 +- .../src/pages/legal/components/legalPage.tsx | 32 +- .../client/src/pages/prompt/PromptModal.tsx | 462 +- .../client/src/pages/prompt/PromptPage.tsx | 336 +- .../client/src/pages/prompt/PromptRouter.tsx | 18 +- packages/client/src/pages/prompt/index.ts | 2 +- .../src/pages/settings/AdminQueryPage.tsx | 562 +- .../pages/settings/AppSettingsDetailPage.tsx | 303 +- .../src/pages/settings/ConfigurationsPage.tsx | 849 +- .../pages/settings/DatabaseSettingsPage.tsx | 992 +- .../settings/EngineSettingsDetailPage.tsx | 307 +- .../settings/EngineSettingsIndexPage.tsx | 1085 +- .../settings/InsightSettingsDetailPage.tsx | 2 +- .../pages/settings/InsightSettingsPage.tsx | 403 +- .../src/pages/settings/MemberSettingsPage.tsx | 16 +- .../src/pages/settings/MyProfilePage.tsx | 2016 +- .../pages/settings/ProjectSettingsPage.tsx | 745 +- .../src/pages/settings/SettingsIndexPage.tsx | 331 +- .../src/pages/settings/SettingsLayout.tsx | 459 +- .../src/pages/settings/SettingsRouter.tsx | 142 +- .../pages/settings/TeamSettingsDetailPage.tsx | 109 +- .../src/pages/settings/TeamsSettingsPage.tsx | 532 +- packages/client/src/pages/settings/index.ts | 4 +- .../src/pages/settings/settings.constants.ts | 388 +- .../client/src/stores/config/config.store.ts | 10 +- packages/client/src/stores/config/index.ts | 2 +- .../src/stores/designer/designer.store.ts | 475 +- .../src/stores/designer/designer.utility.ts | 182 +- packages/client/src/stores/designer/index.ts | 4 +- packages/client/src/stores/index.ts | 12 +- packages/client/src/stores/monolith/index.ts | 2 +- .../src/stores/monolith/monolith.store.ts | 6062 ++- packages/client/src/stores/page/index.ts | 4 +- packages/client/src/stores/page/page.store.ts | 319 +- packages/client/src/stores/page/page.types.ts | 6 +- packages/client/src/stores/root/index.ts | 2 +- packages/client/src/stores/root/root.store.ts | 3 +- packages/client/src/stores/workspace/index.ts | 11 +- .../src/stores/workspace/workspace.store.ts | 686 +- .../src/stores/workspace/workspace.types.ts | 6 +- packages/client/src/testing/AppCards.spec.tsx | 16 +- packages/client/src/testing/test.spec.ts | 12 +- packages/client/src/types/index.ts | 2 +- packages/client/src/types/types.d.ts | 126 +- packages/client/src/utility/general.ts | 302 +- packages/client/src/utility/index.ts | 6 +- packages/client/src/utility/object.ts | 169 +- packages/client/src/utility/promise.ts | 64 +- packages/client/tsconfig.json | 50 +- packages/client/vite.config.ts | 72 +- packages/client/vitest.setup.ts | 54 +- packages/playground/src/App.tsx | 39 +- .../components/common/RightMenu/RightMenu.tsx | 126 +- .../src/components/common/RightMenu/index.ts | 2 +- .../src/components/common/Sidebar/Sidebar.tsx | 621 +- .../components/common/Sidebar/SidebarItem.tsx | 293 +- .../src/components/common/Sidebar/index.ts | 2 +- .../playground/src/components/common/index.ts | 4 +- .../knowledge/ExistingKnowledge.tsx | 4 +- .../components/knowledge/KnowledgeOverlay.tsx | 7 +- .../src/components/options/OptionsMenu.tsx | 2 +- .../src/components/options/OptionsPicker.tsx | 2 +- .../src/components/prompt/PromptLibrary.tsx | 2 +- .../src/components/room/RoomApp.tsx | 2 +- .../src/components/room/RoomControls.tsx | 2 +- .../src/components/room/RoomInput.tsx | 3 +- .../src/components/room/RoomMessage.tsx | 2 +- .../src/components/tools/ToolsOverlay.tsx | 7 +- .../playground/src/contexts/ChatContext.tsx | 11 +- .../playground/src/hooks/useCacheState.ts | 64 +- packages/playground/src/hooks/useChat.ts | 15 +- .../playground/src/hooks/useDebounceValue.ts | 26 +- packages/playground/src/main.tsx | 11 +- .../src/pages/AuthenticatedLayout.tsx | 19 +- .../playground/src/pages/DiscoverPage.tsx | 376 +- packages/playground/src/pages/LoginPage.tsx | 886 +- packages/playground/src/pages/MainLayout.tsx | 105 +- packages/playground/src/pages/NewRoomPage.tsx | 4 +- packages/playground/src/pages/Router.tsx | 121 +- .../playground/src/stores/chat/chat.room.ts | 2 +- .../playground/src/stores/chat/chat.store.ts | 4 +- packages/playground/src/stores/chat/index.ts | 6 +- packages/playground/src/stores/index.ts | 2 +- packages/playground/tsconfig.json | 60 +- .../vscode-extension/.vscode/extensions.json | 6 +- packages/vscode-extension/.vscode/launch.json | 4 +- packages/vscode-extension/extension.js | 871 +- packages/vscode-extension/jsconfig.json | 12 +- .../src/components/Chatbot-ui/script.js | 2755 +- .../ChatbotWebview/ChatbotSeparateManager.js | 121 +- .../ChatbotWebview/ChatbotWebview.js | 1002 +- .../vscode-extension/src/utils/createApp.js | 826 +- packages/vscode-extension/src/utils/deploy.js | 490 +- .../src/utils/githubAssets.js | 602 +- .../src/utils/projectUtils.js | 53 +- .../vscode-extension/src/utils/secrets.js | 390 +- .../vscode-extension/src/utils/statusBar.js | 64 +- packages/vscode-extension/src/utils/zip.js | 324 +- packages/vscode-extension/tasks.json | 28 +- 1205 files changed, 164636 insertions(+), 164259 deletions(-) diff --git a/libs/renderer/rollup.config.js b/libs/renderer/rollup.config.js index 0d2b31737a..afb955c72b 100644 --- a/libs/renderer/rollup.config.js +++ b/libs/renderer/rollup.config.js @@ -1,65 +1,64 @@ -import { defineConfig } from "rollup"; -import resolve from "@rollup/plugin-node-resolve"; import commonjs from "@rollup/plugin-commonjs"; -import typescript from "@rollup/plugin-typescript"; -import terser from "@rollup/plugin-terser"; import image from "@rollup/plugin-image"; import json from "@rollup/plugin-json"; - +import resolve from "@rollup/plugin-node-resolve"; +import terser from "@rollup/plugin-terser"; +import typescript from "@rollup/plugin-typescript"; +import { defineConfig } from "rollup"; import del from "rollup-plugin-delete"; const isProduction = process.env.NODE_ENV === "production"; // Plugin to strip 'use client' directives const stripUseClient = () => ({ - name: 'strip-use-client', - transform(code, id) { - if (id.includes('node_modules') && code.includes("'use client'")) { - return { - code: code.replace(/'use client';\s*/g, ''), - map: null - }; - } - return null; - } + name: "strip-use-client", + transform(code, id) { + if (id.includes("node_modules") && code.includes("'use client'")) { + return { + code: code.replace(/'use client';\s*/g, ""), + map: null, + }; + } + return null; + }, }); export default defineConfig({ - input: { - index: "src/index.ts", - }, - output: { - dir: "dist", - format: "esm", - sourcemap: isProduction, - entryFileNames: "[name].mjs", - }, - plugins: [ - del({ targets: "dist" }), - stripUseClient(), - resolve(), - commonjs(), - image(), - json(), - typescript({ - tsconfig: "./tsconfig.json", - }), - isProduction && terser(), - ], - external: [ - "@emotion/react", - "@emotion/styled", - "@mui/icons-material", - "@mui/material", - /@semoss\/sdk/, - "@semoss/ui", - "mobx", - "mobx-react-lite", - "react", - "react-dom", - "react-router-dom", - ], - watch: { - clearScreen: false, - }, + input: { + index: "src/index.ts", + }, + output: { + dir: "dist", + format: "esm", + sourcemap: isProduction, + entryFileNames: "[name].mjs", + }, + plugins: [ + del({ targets: "dist" }), + stripUseClient(), + resolve(), + commonjs(), + image(), + json(), + typescript({ + tsconfig: "./tsconfig.json", + }), + isProduction && terser(), + ], + external: [ + "@emotion/react", + "@emotion/styled", + "@mui/icons-material", + "@mui/material", + /@semoss\/sdk/, + "@semoss/ui", + "mobx", + "mobx-react-lite", + "react", + "react-dom", + "react-router-dom", + ], + watch: { + clearScreen: false, + }, }); diff --git a/libs/renderer/src/Renderer.tsx b/libs/renderer/src/Renderer.tsx index 2087c0e447..11d135a3f4 100644 --- a/libs/renderer/src/Renderer.tsx +++ b/libs/renderer/src/Renderer.tsx @@ -9,7 +9,7 @@ import { Blocks, RendererEngine } from "./components/blocks"; import { DefaultCells } from "./components/cell-defaults"; import { MigrationManager, - SerializedState, + type SerializedState, STATE_VERSION, StateStore, } from "./store/state"; diff --git a/libs/renderer/src/components/block-defaults/accordion-block/AccordionBlock.tsx b/libs/renderer/src/components/block-defaults/accordion-block/AccordionBlock.tsx index 3a9c6863f6..3e5678854c 100644 --- a/libs/renderer/src/components/block-defaults/accordion-block/AccordionBlock.tsx +++ b/libs/renderer/src/components/block-defaults/accordion-block/AccordionBlock.tsx @@ -1,95 +1,93 @@ -import { CSSProperties, useEffect } from "react"; -import { observer } from "mobx-react-lite"; import { ArrowDropDown } from "@mui/icons-material"; - +import { observer } from "mobx-react-lite"; +import { type CSSProperties, useEffect } from "react"; import { Accordion, Stack, styled } from "@semoss/ui"; - -import { Slot } from "../../blocks"; import { useBlock } from "../../../hooks"; -import { BlockDef, BlockComponent, ListenerActions } from "../../../store"; +import type { BlockComponent, BlockDef, ListenerActions } from "../../../store"; +import { Slot } from "../../blocks"; const StyledAccordion = styled(Accordion)(({ theme }) => ({ - padding: 0, - margin: 0, - borderRadius: "12px", - "&.MuiAccordion-root:before": { - backgroundColor: "white", - }, + padding: 0, + margin: 0, + borderRadius: "12px", + "&.MuiAccordion-root:before": { + backgroundColor: "white", + }, })); const AccordionTrigger = styled(Accordion.Trigger)(({ theme }) => ({ - "& .MuiAccordionSummary-content": { - margin: 0, - }, - minHeight: "fit-content", - margin: 0, - padding: 0, - borderRadius: "inherit", - //if accordion is expanded, then remove the border radius from bottom left and right side of the trigger element - "&.MuiButtonBase-root.Mui-expanded": { - borderBottomLeftRadius: 0, - borderBottomRightRadius: 0, - }, + "& .MuiAccordionSummary-content": { + margin: 0, + }, + minHeight: "fit-content", + margin: 0, + padding: 0, + borderRadius: "inherit", + //if accordion is expanded, then remove the border radius from bottom left and right side of the trigger element + "&.MuiButtonBase-root.Mui-expanded": { + borderBottomLeftRadius: 0, + borderBottomRightRadius: 0, + }, })); const AccordionContent = styled(Accordion.Content)(({ theme }) => ({ - margin: 0, - padding: 0, - borderRadius: "inherit", - borderTopLeftRadius: 0, - borderTopRightRadius: 0, + margin: 0, + padding: 0, + borderRadius: "inherit", + borderTopLeftRadius: 0, + borderTopRightRadius: 0, })); export interface AccordionBlockDef extends BlockDef<"accordion"> { - widget: "accordion"; - data: { - style: CSSProperties; - triggerBgColor: string; - contentBgColor: string; - showExpandIcon: boolean; - show: string; - }; - slots: { - header: true; - content: true; - }; - listeners: { - preProcess: { - type: "sync" | "async"; - order: ListenerActions[]; - }; - }; + widget: "accordion"; + data: { + style: CSSProperties; + triggerBgColor: string; + contentBgColor: string; + showExpandIcon: boolean; + show: string; + }; + slots: { + header: true; + content: true; + }; + listeners: { + preProcess: { + type: "sync" | "async"; + order: ListenerActions[]; + }; + }; } export const AccordionBlock: BlockComponent = observer(({ id }) => { - const { attrs, data, slots, listeners } = useBlock(id); + const { attrs, data, slots, listeners } = useBlock(id); - useEffect(() => { - if (listeners.preProcess) { - listeners.preProcess(); - } - }, []); + useEffect(() => { + if (listeners.preProcess) { + listeners.preProcess(); + } + }, []); - return ( - - : null} - > - - - - - - - - - ); + return ( + + : null} + > + + + + + + + + + ); }); diff --git a/libs/renderer/src/components/block-defaults/accordion-block/config.tsx b/libs/renderer/src/components/block-defaults/accordion-block/config.tsx index 374f6e8aba..57a1dd0125 100644 --- a/libs/renderer/src/components/block-defaults/accordion-block/config.tsx +++ b/libs/renderer/src/components/block-defaults/accordion-block/config.tsx @@ -1,26 +1,26 @@ -import { BlockConfig } from "../../../store"; +import type { BlockConfig } from "../../../store"; import { BLOCK_TYPE_LAYOUT } from "../block-defaults.constants"; -import { AccordionBlock, AccordionBlockDef } from "./AccordionBlock"; +import { AccordionBlock, type AccordionBlockDef } from "./AccordionBlock"; export const config: BlockConfig = { - widget: "accordion", - type: BLOCK_TYPE_LAYOUT, - data: { - style: {}, - triggerBgColor: "", - contentBgColor: "", - showExpandIcon: true, - show: "true", - }, - listeners: { - preProcess: { - type: "sync", - order: [], - }, - }, - slots: { - header: [], - content: [], - }, - render: AccordionBlock, + widget: "accordion", + type: BLOCK_TYPE_LAYOUT, + data: { + style: {}, + triggerBgColor: "", + contentBgColor: "", + showExpandIcon: true, + show: "true", + }, + listeners: { + preProcess: { + type: "sync", + order: [], + }, + }, + slots: { + header: [], + content: [], + }, + render: AccordionBlock, }; diff --git a/libs/renderer/src/components/block-defaults/accordion-block/index.ts b/libs/renderer/src/components/block-defaults/accordion-block/index.ts index 94c9b4f84d..7188c3a341 100644 --- a/libs/renderer/src/components/block-defaults/accordion-block/index.ts +++ b/libs/renderer/src/components/block-defaults/accordion-block/index.ts @@ -1,2 +1,2 @@ -export * from "./config"; export * from "./AccordionBlock"; +export * from "./config"; diff --git a/libs/renderer/src/components/block-defaults/audio-block/AudioBlock.tsx b/libs/renderer/src/components/block-defaults/audio-block/AudioBlock.tsx index 4df9378953..73d167d822 100644 --- a/libs/renderer/src/components/block-defaults/audio-block/AudioBlock.tsx +++ b/libs/renderer/src/components/block-defaults/audio-block/AudioBlock.tsx @@ -1,60 +1,58 @@ -import { useEffect } from "react"; import { observer } from "mobx-react-lite"; - -import { useBlock } from "../../../hooks"; -import { BlockDef, BlockComponent, ListenerActions } from "../../../store"; - +import { useEffect } from "react"; import { styled } from "@semoss/ui"; +import { useBlock } from "../../../hooks"; +import type { BlockComponent, BlockDef, ListenerActions } from "../../../store"; const StyledLabel = styled("span")(({ theme }) => ({ - marginBottom: "4px", - display: "flex", - flexDirection: "column", - alignItems: "flex-start", - justifyContent: "center", - gap: "4px", + marginBottom: "4px", + display: "flex", + flexDirection: "column", + alignItems: "flex-start", + justifyContent: "center", + gap: "4px", })); export interface AudioBlockDef extends BlockDef<"audio-player"> { - widget: "audio-player"; - data: { - label: string; - autoplay: boolean; - controls: boolean; - loop: boolean; - source: string; - show: string; - }; - listeners: { - preProcess: { - type: "sync" | "async"; - order: ListenerActions[]; - }; - }; + widget: "audio-player"; + data: { + label: string; + autoplay: boolean; + controls: boolean; + loop: boolean; + source: string; + show: string; + }; + listeners: { + preProcess: { + type: "sync" | "async"; + order: ListenerActions[]; + }; + }; } const StyledContainer = styled("div")(({ theme }) => ({ - padding: "4px", + padding: "4px", })); export const AudioBlock: BlockComponent = observer(({ id }) => { - const { attrs, data, listeners } = useBlock(id); - - useEffect(() => { - if (listeners.preProcess) { - listeners.preProcess(); - } - }, []); - - return ( - - {data.label} - - - ); + const { attrs, data, listeners } = useBlock(id); + + useEffect(() => { + if (listeners.preProcess) { + listeners.preProcess(); + } + }, []); + + return ( + + {data.label} + + + ); }); diff --git a/libs/renderer/src/components/block-defaults/audio-block/config.tsx b/libs/renderer/src/components/block-defaults/audio-block/config.tsx index b1a66efdfc..86c023a587 100644 --- a/libs/renderer/src/components/block-defaults/audio-block/config.tsx +++ b/libs/renderer/src/components/block-defaults/audio-block/config.tsx @@ -1,27 +1,26 @@ import { CSSProperties } from "react"; -import { BlockConfig } from "../../../store"; - -import { AudioBlockDef, AudioBlock } from "./AudioBlock"; +import type { BlockConfig } from "../../../store"; import { BLOCK_TYPE_ACTION } from "../block-defaults.constants"; +import { AudioBlock, type AudioBlockDef } from "./AudioBlock"; // export the config for the block export const config: BlockConfig = { - widget: "audio-player", - type: BLOCK_TYPE_ACTION, - data: { - label: "Audio Player", - autoplay: false, - controls: true, - loop: false, - source: "", - show: "true", - }, - listeners: { - preProcess: { - type: "sync", - order: [], - }, - }, - slots: {}, - render: AudioBlock, + widget: "audio-player", + type: BLOCK_TYPE_ACTION, + data: { + label: "Audio Player", + autoplay: false, + controls: true, + loop: false, + source: "", + show: "true", + }, + listeners: { + preProcess: { + type: "sync", + order: [], + }, + }, + slots: {}, + render: AudioBlock, }; diff --git a/libs/renderer/src/components/block-defaults/audio-block/index.ts b/libs/renderer/src/components/block-defaults/audio-block/index.ts index f2e79653fa..ef7060f939 100644 --- a/libs/renderer/src/components/block-defaults/audio-block/index.ts +++ b/libs/renderer/src/components/block-defaults/audio-block/index.ts @@ -1,2 +1,2 @@ -export * from "./config"; export * from "./AudioBlock"; +export * from "./config"; diff --git a/libs/renderer/src/components/block-defaults/audio-input-block/AudioInputBlock.tsx b/libs/renderer/src/components/block-defaults/audio-input-block/AudioInputBlock.tsx index 05089ac756..da3c9941ef 100644 --- a/libs/renderer/src/components/block-defaults/audio-input-block/AudioInputBlock.tsx +++ b/libs/renderer/src/components/block-defaults/audio-input-block/AudioInputBlock.tsx @@ -1,216 +1,214 @@ -import { CSSProperties, useState, useRef, useEffect } from "react"; -import { observer } from "mobx-react-lite"; - -import { useBlock } from "../../../hooks"; -import { BlockDef, BlockComponent, ListenerActions } from "../../../store"; - -import { Button, styled } from "@mui/material"; import MicIcon from "@mui/icons-material/Mic"; import MicOffIcon from "@mui/icons-material/MicOff"; +import { Button, styled } from "@mui/material"; +import { observer } from "mobx-react-lite"; +import { type CSSProperties, useEffect, useRef, useState } from "react"; +import { useBlock } from "../../../hooks"; +import type { BlockComponent, BlockDef, ListenerActions } from "../../../store"; const StyledButton = styled(Button)({ - borderRadius: "50%", + borderRadius: "50%", }); export interface AudioInputBlockDef extends BlockDef<"audio-input"> { - widget: "audio-input"; - data: { - style: CSSProperties; - label: string; - loading?: boolean; - disabled?: boolean; - variant: "contained" | "outlined" | "text"; - color: "primary" | "secondary" | "success" | "warning" | "error"; - value: string; - mode: "transcribe" | "record"; - show: string; - }; - listeners: { - preProcess: { - type: "sync" | "async"; - order: ListenerActions[]; - }; - onComplete: { - type: "sync" | "async"; - order: ListenerActions[]; - }; - }; + widget: "audio-input"; + data: { + style: CSSProperties; + label: string; + loading?: boolean; + disabled?: boolean; + variant: "contained" | "outlined" | "text"; + color: "primary" | "secondary" | "success" | "warning" | "error"; + value: string; + mode: "transcribe" | "record"; + show: string; + }; + listeners: { + preProcess: { + type: "sync" | "async"; + order: ListenerActions[]; + }; + onComplete: { + type: "sync" | "async"; + order: ListenerActions[]; + }; + }; } const StyledContainer = styled("div")(() => ({ - padding: "4px", + padding: "4px", })); export const AudioInputBlock: BlockComponent = observer(({ id }) => { - const { attrs, data, setData } = useBlock(id); - const [recording, setRecording] = useState(false); - const [transcript, setTranscript] = useState(""); - const [interimTranscript, setInterimTranscript] = useState(""); - const recognitionRef = useRef(null); - const [primaryBtnColor, setPrimaryBtnColor] = useState(data.color); - const [mediaRecorder, setMediaRecorder] = useState( - null, - ); - const chunks = useRef([]); - const previousValueRef = useRef(data.value); - - useEffect(() => { - if (data.mode === "transcribe") { - const recognition = new (window as any).webkitSpeechRecognition(); - recognition.continuous = true; - recognition.interimResults = true; - recognition.lang = "en-US"; - - recognition.onstart = () => { - setRecording(true); - setData("color", "error"); - setTranscript(""); - }; - recognition.onend = () => { - setRecording(false); - setData("color", primaryBtnColor); - }; - recognition.onresult = (event) => { - let interim = ""; - let final = ""; - for (let i = event.resultIndex; i < event.results.length; ++i) { - if (event.results[i].isFinal) { - final += event.results[i][0].transcript; - } else { - interim += event.results[i][0].transcript; - } - } - setTranscript((prev) => prev + final); - setInterimTranscript(interim); - }; - recognitionRef.current = recognition; - } else { - if (recognitionRef.current) { - recognitionRef.current.stop(); - } - } - }, [data.mode]); - - useEffect(() => { - if (data.mode === "transcribe") { - setData("value", transcript); - } - }, [transcript]); - - const handleRecording = (stopRecording = false) => { - if (data.mode === "transcribe") { - if (recognitionRef.current) { - if (recording || stopRecording) { - recognitionRef.current.stop(); - } else { - recognitionRef.current.start(); - } - } - } else { - if (recording || stopRecording) { - if (mediaRecorder && mediaRecorder.state === "recording") { - mediaRecorder.stop(); - } - setData("color", primaryBtnColor); - setRecording(false); - } else { - chunks.current = []; // Clear chunks before new recording - navigator.mediaDevices - .getUserMedia({ audio: true }) - .then((stream) => { - const recorder = new MediaRecorder(stream); - - recorder.ondataavailable = (e) => { - if (e.data.size > 0) { - chunks.current.push(e.data); - } - }; - - recorder.onstop = () => { - const audioBlob = new Blob(chunks.current, { - type: "audio/webm", - }); - - const reader = new FileReader(); - reader.onloadend = () => { - const base64Audio = reader.result as string; - setData("value", base64Audio); - }; - reader.readAsDataURL(audioBlob); - - // Stop and cleanup tracks - stream.getTracks().forEach((track) => track.stop()); - }; - - setMediaRecorder(recorder); - recorder.start(); - setRecording(true); - setData("color", "error"); - }) - .catch((err) => { - console.error("Error getting media stream:", err); - }); - } - } - }; - - const handleDownload = () => { - if ( - data.mode === "record" && - (data.value as string)?.startsWith("data:audio/") - ) { - const link = document.createElement("a"); - link.href = data.value as string; - link.download = `recording-${new Date().toISOString()}.webm`; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - } - }; - - // Auto-download effect when recording becomes available - useEffect(() => { - if ( - data.mode === "record" && - (data.value as string)?.startsWith("data:audio/") && - (data.value as string) !== previousValueRef.current && - !recording - ) { - handleDownload(); - } - previousValueRef.current = data.value; - }, [data.value, recording]); - - // Cleanup effect - useEffect(() => { - return () => { - if (mediaRecorder && mediaRecorder.state !== "inactive") { - mediaRecorder.stop(); - const tracks = mediaRecorder.stream.getTracks(); - tracks.forEach((track) => track.stop()); - } - if (recognitionRef.current) { - recognitionRef.current.stop(); - } - }; - }, [mediaRecorder]); - - return ( - - { - handleRecording(); - }} - > - {recording ? : } - - - ); + const { attrs, data, setData } = useBlock(id); + const [recording, setRecording] = useState(false); + const [transcript, setTranscript] = useState(""); + const [interimTranscript, setInterimTranscript] = useState(""); + const recognitionRef = useRef(null); + const [primaryBtnColor, setPrimaryBtnColor] = useState(data.color); + const [mediaRecorder, setMediaRecorder] = useState( + null, + ); + const chunks = useRef([]); + const previousValueRef = useRef(data.value); + + useEffect(() => { + if (data.mode === "transcribe") { + const recognition = new (window as any).webkitSpeechRecognition(); + recognition.continuous = true; + recognition.interimResults = true; + recognition.lang = "en-US"; + + recognition.onstart = () => { + setRecording(true); + setData("color", "error"); + setTranscript(""); + }; + recognition.onend = () => { + setRecording(false); + setData("color", primaryBtnColor); + }; + recognition.onresult = (event) => { + let interim = ""; + let final = ""; + for (let i = event.resultIndex; i < event.results.length; ++i) { + if (event.results[i].isFinal) { + final += event.results[i][0].transcript; + } else { + interim += event.results[i][0].transcript; + } + } + setTranscript((prev) => prev + final); + setInterimTranscript(interim); + }; + recognitionRef.current = recognition; + } else { + if (recognitionRef.current) { + recognitionRef.current.stop(); + } + } + }, [data.mode]); + + useEffect(() => { + if (data.mode === "transcribe") { + setData("value", transcript); + } + }, [transcript]); + + const handleRecording = (stopRecording = false) => { + if (data.mode === "transcribe") { + if (recognitionRef.current) { + if (recording || stopRecording) { + recognitionRef.current.stop(); + } else { + recognitionRef.current.start(); + } + } + } else { + if (recording || stopRecording) { + if (mediaRecorder && mediaRecorder.state === "recording") { + mediaRecorder.stop(); + } + setData("color", primaryBtnColor); + setRecording(false); + } else { + chunks.current = []; // Clear chunks before new recording + navigator.mediaDevices + .getUserMedia({ audio: true }) + .then((stream) => { + const recorder = new MediaRecorder(stream); + + recorder.ondataavailable = (e) => { + if (e.data.size > 0) { + chunks.current.push(e.data); + } + }; + + recorder.onstop = () => { + const audioBlob = new Blob(chunks.current, { + type: "audio/webm", + }); + + const reader = new FileReader(); + reader.onloadend = () => { + const base64Audio = reader.result as string; + setData("value", base64Audio); + }; + reader.readAsDataURL(audioBlob); + + // Stop and cleanup tracks + stream.getTracks().forEach((track) => track.stop()); + }; + + setMediaRecorder(recorder); + recorder.start(); + setRecording(true); + setData("color", "error"); + }) + .catch((err) => { + console.error("Error getting media stream:", err); + }); + } + } + }; + + const handleDownload = () => { + if ( + data.mode === "record" && + (data.value as string)?.startsWith("data:audio/") + ) { + const link = document.createElement("a"); + link.href = data.value as string; + link.download = `recording-${new Date().toISOString()}.webm`; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } + }; + + // Auto-download effect when recording becomes available + useEffect(() => { + if ( + data.mode === "record" && + (data.value as string)?.startsWith("data:audio/") && + (data.value as string) !== previousValueRef.current && + !recording + ) { + handleDownload(); + } + previousValueRef.current = data.value; + }, [data.value, recording]); + + // Cleanup effect + useEffect(() => { + return () => { + if (mediaRecorder && mediaRecorder.state !== "inactive") { + mediaRecorder.stop(); + const tracks = mediaRecorder.stream.getTracks(); + tracks.forEach((track) => track.stop()); + } + if (recognitionRef.current) { + recognitionRef.current.stop(); + } + }; + }, [mediaRecorder]); + + return ( + + { + handleRecording(); + }} + > + {recording ? : } + + + ); }); diff --git a/libs/renderer/src/components/block-defaults/audio-input-block/config.tsx b/libs/renderer/src/components/block-defaults/audio-input-block/config.tsx index 134a5108c5..25a9c33ff8 100644 --- a/libs/renderer/src/components/block-defaults/audio-input-block/config.tsx +++ b/libs/renderer/src/components/block-defaults/audio-input-block/config.tsx @@ -1,34 +1,33 @@ import { CSSProperties } from "react"; - -import { AudioInputBlockDef, AudioInputBlock } from "./AudioInputBlock"; +import type { BlockConfig } from "../../../store"; import { BLOCK_TYPE_INPUT } from "../block-defaults.constants"; -import { BlockConfig } from "../../../store"; +import { AudioInputBlock, type AudioInputBlockDef } from "./AudioInputBlock"; // export the config for the block export const config: BlockConfig = { - widget: "audio-input", - type: BLOCK_TYPE_INPUT, - data: { - style: {}, - label: "Submit", - loading: false, - disabled: false, - variant: "contained", - color: "primary", - value: "", - mode: "transcribe", - show: "true", - }, - listeners: { - preProcess: { - type: "sync", - order: [], - }, - onComplete: { - type: "sync", - order: [], - }, - }, - slots: {}, - render: AudioInputBlock, + widget: "audio-input", + type: BLOCK_TYPE_INPUT, + data: { + style: {}, + label: "Submit", + loading: false, + disabled: false, + variant: "contained", + color: "primary", + value: "", + mode: "transcribe", + show: "true", + }, + listeners: { + preProcess: { + type: "sync", + order: [], + }, + onComplete: { + type: "sync", + order: [], + }, + }, + slots: {}, + render: AudioInputBlock, }; diff --git a/libs/renderer/src/components/block-defaults/audio-input-block/index.ts b/libs/renderer/src/components/block-defaults/audio-input-block/index.ts index 08f217742a..a8f771b94e 100644 --- a/libs/renderer/src/components/block-defaults/audio-input-block/index.ts +++ b/libs/renderer/src/components/block-defaults/audio-input-block/index.ts @@ -1,2 +1,2 @@ -export * from "./config"; export * from "./AudioInputBlock"; +export * from "./config"; diff --git a/libs/renderer/src/components/block-defaults/block-defaults.constants.tsx b/libs/renderer/src/components/block-defaults/block-defaults.constants.tsx index 39d1bfbb07..4983e7e031 100644 --- a/libs/renderer/src/components/block-defaults/block-defaults.constants.tsx +++ b/libs/renderer/src/components/block-defaults/block-defaults.constants.tsx @@ -8,34 +8,34 @@ export const BLOCK_TYPE_MERMAID = "mermaid"; export const BLOCK_TYPE_THEME = "theme"; export const BLOCK_TYPES = [ - BLOCK_TYPE_LAYOUT, - BLOCK_TYPE_DISPLAY, - BLOCK_TYPE_INPUT, - BLOCK_TYPE_ACTION, - BLOCK_TYPE_CHART, - BLOCK_TYPE_MERMAID, - BLOCK_TYPE_THEME, + BLOCK_TYPE_LAYOUT, + BLOCK_TYPE_DISPLAY, + BLOCK_TYPE_INPUT, + BLOCK_TYPE_ACTION, + BLOCK_TYPE_CHART, + BLOCK_TYPE_MERMAID, + BLOCK_TYPE_THEME, ]; export const DEFAULT_TRUE_VARIABLE = { - true: { - blockType: "boolean", - display: "True", - id: "true", - path: undefined, - type: "true", - variabilized: true, - groupAlias: "Others", - }, + true: { + blockType: "boolean", + display: "True", + id: "true", + path: undefined, + type: "true", + variabilized: true, + groupAlias: "Others", + }, }; export const DEFAULT_FALSE_VARIABLE = { - false: { - blockType: "boolean", - display: "False", - id: "false", - path: undefined, - type: "false", - variabilized: true, - groupAlias: "Others", - }, + false: { + blockType: "boolean", + display: "False", + id: "false", + path: undefined, + type: "false", + variabilized: true, + groupAlias: "Others", + }, }; diff --git a/libs/renderer/src/components/block-defaults/button-block/ButtonBlock.tsx b/libs/renderer/src/components/block-defaults/button-block/ButtonBlock.tsx index 1f24d728b9..1d2ee99d1d 100644 --- a/libs/renderer/src/components/block-defaults/button-block/ButtonBlock.tsx +++ b/libs/renderer/src/components/block-defaults/button-block/ButtonBlock.tsx @@ -1,92 +1,90 @@ -import { CSSProperties, useEffect } from "react"; +import { Button, CircularProgress, styled } from "@mui/material"; import { observer } from "mobx-react-lite"; - +import { type CSSProperties, useEffect } from "react"; import { useBlock } from "../../../hooks"; -import { BlockDef, BlockComponent, ListenerActions } from "../../../store"; - -import { CircularProgress, Button, styled } from "@mui/material"; +import type { BlockComponent, BlockDef, ListenerActions } from "../../../store"; const StyledButton = styled(Button, { - shouldForwardProp: (prop) => prop !== "loading", + shouldForwardProp: (prop) => prop !== "loading", })<{ loading?: boolean }>(({ loading }) => ({ - "& .MuiButton-endIcon svg": { - visibility: loading === true ? "hidden" : "visible", - }, - "& .MuiButton-startIcon svg": { - visibility: loading === true ? "hidden" : "visible", - }, + "& .MuiButton-endIcon svg": { + visibility: loading === true ? "hidden" : "visible", + }, + "& .MuiButton-startIcon svg": { + visibility: loading === true ? "hidden" : "visible", + }, })); const StyledLabel = styled("span", { - shouldForwardProp: (prop) => prop !== "loading", + shouldForwardProp: (prop) => prop !== "loading", })<{ loading?: boolean }>(({ loading }) => ({ - visibility: loading ? "hidden" : "visible", + visibility: loading ? "hidden" : "visible", })); const StyledCircularProgress = styled(CircularProgress)({ - zIndex: 10, - position: "absolute", + zIndex: 10, + position: "absolute", }); export interface ButtonBlockDef extends BlockDef<"button"> { - widget: "button"; - data: { - style: CSSProperties; - label: string; - loading?: boolean; - disabled?: boolean; - variant: "contained" | "outlined" | "text"; - color: "primary" | "secondary" | "success" | "warning" | "error"; - show: string; - type: "button" | "submit" | "reset"; - }; - listeners: { - onClick: { - type: "sync" | "async"; - order: ListenerActions[]; - }; - preProcess: { - type: "sync" | "async"; - order: ListenerActions[]; - }; - }; + widget: "button"; + data: { + style: CSSProperties; + label: string; + loading?: boolean; + disabled?: boolean; + variant: "contained" | "outlined" | "text"; + color: "primary" | "secondary" | "success" | "warning" | "error"; + show: string; + type: "button" | "submit" | "reset"; + }; + listeners: { + onClick: { + type: "sync" | "async"; + order: ListenerActions[]; + }; + preProcess: { + type: "sync" | "async"; + order: ListenerActions[]; + }; + }; } const StyledContainer = styled("div")(({ theme }) => ({ - padding: "4px", + padding: "4px", })); export const ButtonBlock: BlockComponent = observer(({ id }) => { - const { attrs, data, listeners } = useBlock(id); + const { attrs, data, listeners } = useBlock(id); - useEffect(() => { - if (listeners.preProcess) { - listeners.preProcess(); - } - }, []); - return ( - - { - listeners.onClick(); - }} - > - {data.label} - {data.loading ? ( - - ) : ( - <> - )} - - - ); + useEffect(() => { + if (listeners.preProcess) { + listeners.preProcess(); + } + }, []); + return ( + + { + listeners.onClick(); + }} + > + {data.label} + {data.loading ? ( + + ) : ( + <> + )} + + + ); }); diff --git a/libs/renderer/src/components/block-defaults/button-block/config.tsx b/libs/renderer/src/components/block-defaults/button-block/config.tsx index e03530ce44..c096f27228 100644 --- a/libs/renderer/src/components/block-defaults/button-block/config.tsx +++ b/libs/renderer/src/components/block-defaults/button-block/config.tsx @@ -1,32 +1,31 @@ -import { BlockConfig } from "../../../store"; - -import { ButtonBlockDef, ButtonBlock } from "./ButtonBlock"; +import type { BlockConfig } from "../../../store"; import { BLOCK_TYPE_ACTION } from "../block-defaults.constants"; +import { ButtonBlock, type ButtonBlockDef } from "./ButtonBlock"; // export the config for the block export const config: BlockConfig = { - widget: "button", - type: BLOCK_TYPE_ACTION, - data: { - style: {}, - label: "Submit", - loading: false, - disabled: false, - variant: "contained", - color: "primary", - show: "true", - type: "button" - }, - listeners: { - onClick: { - type: "sync", - order: [], - }, - preProcess: { - type: "sync", - order: [], - }, - }, - slots: {}, - render: ButtonBlock, + widget: "button", + type: BLOCK_TYPE_ACTION, + data: { + style: {}, + label: "Submit", + loading: false, + disabled: false, + variant: "contained", + color: "primary", + show: "true", + type: "button", + }, + listeners: { + onClick: { + type: "sync", + order: [], + }, + preProcess: { + type: "sync", + order: [], + }, + }, + slots: {}, + render: ButtonBlock, }; diff --git a/libs/renderer/src/components/block-defaults/button-block/index.ts b/libs/renderer/src/components/block-defaults/button-block/index.ts index bc84ffad65..2329339797 100644 --- a/libs/renderer/src/components/block-defaults/button-block/index.ts +++ b/libs/renderer/src/components/block-defaults/button-block/index.ts @@ -1,2 +1,2 @@ -export * from "./config"; export * from "./ButtonBlock"; +export * from "./config"; diff --git a/libs/renderer/src/components/block-defaults/checkbox-block/CheckboxBlock.tsx b/libs/renderer/src/components/block-defaults/checkbox-block/CheckboxBlock.tsx index 31aea99981..2812c166df 100644 --- a/libs/renderer/src/components/block-defaults/checkbox-block/CheckboxBlock.tsx +++ b/libs/renderer/src/components/block-defaults/checkbox-block/CheckboxBlock.tsx @@ -1,71 +1,69 @@ -import { CSSProperties, useEffect } from "react"; -import { observer } from "mobx-react-lite"; import { Checkbox, styled } from "@mui/material"; - -import { Box } from "@semoss/ui"; +import { observer } from "mobx-react-lite"; +import { type CSSProperties, useEffect } from "react"; import { debounced } from "@semoss/sdk/react"; - +import { Box } from "@semoss/ui"; import { useBlock } from "../../../hooks"; -import { BlockComponent, BlockDef, ListenerActions } from "../../../store"; +import type { BlockComponent, BlockDef, ListenerActions } from "../../../store"; export interface CheckboxBlockDef extends BlockDef<"checkbox"> { - widget: "checkbox"; - data: { - style: CSSProperties; - value: boolean; - label: string; - required: boolean; - disabled: boolean; - show: string; - }; - listeners: { - onChange: { - type: "sync" | "async"; - order: ListenerActions[]; - }; - preProcess: { - type: "sync" | "async"; - order: ListenerActions[]; - }; - }; + widget: "checkbox"; + data: { + style: CSSProperties; + value: boolean; + label: string; + required: boolean; + disabled: boolean; + show: string; + }; + listeners: { + onChange: { + type: "sync" | "async"; + order: ListenerActions[]; + }; + preProcess: { + type: "sync" | "async"; + order: ListenerActions[]; + }; + }; } const StyledContainer = styled("div")(({ theme }) => ({ - padding: theme.spacing(0.5), + padding: theme.spacing(0.5), })); const StyledCheckbox = styled(Checkbox)(({ theme }) => ({ - padding: theme.spacing(0), + padding: theme.spacing(0), })); export const CheckboxBlock: BlockComponent = observer(({ id }) => { - const { attrs, data, setData, listeners } = useBlock(id); + const { attrs, data, setData, listeners } = useBlock(id); - useEffect(() => { - if (listeners.preProcess) { - listeners.preProcess(); - } - }, []); + useEffect(() => { + if (listeners.preProcess) { + listeners.preProcess(); + } + }, []); - const debouncedCallback = debounced(() => { - listeners.onChange(); - }, 200); + const debouncedCallback = debounced(() => { + listeners.onChange(); + }, 200); - return ( - - - { - const value = e.target.checked; - setData("value", value); - debouncedCallback(); - }} - /> - {data.label} - - - ); + return ( + + + { + const value = e.target.checked; + setData("value", value); + debouncedCallback(); + }} + /> + {data.label} + + + ); }); diff --git a/libs/renderer/src/components/block-defaults/checkbox-block/config.tsx b/libs/renderer/src/components/block-defaults/checkbox-block/config.tsx index 74e094bbe0..dbbc104599 100644 --- a/libs/renderer/src/components/block-defaults/checkbox-block/config.tsx +++ b/libs/renderer/src/components/block-defaults/checkbox-block/config.tsx @@ -1,31 +1,31 @@ -import { BlockConfig } from "../../../store"; -import { CheckboxBlockDef, CheckboxBlock } from "./CheckboxBlock"; +import type { BlockConfig } from "../../../store"; import { BLOCK_TYPE_INPUT } from "../block-defaults.constants"; +import { CheckboxBlock, type CheckboxBlockDef } from "./CheckboxBlock"; // export the config for the block export const config: BlockConfig = { - widget: "checkbox", - type: BLOCK_TYPE_INPUT, - data: { - style: { - padding: "none", - }, - label: "Example Checkbox", - required: false, - disabled: false, - value: false, - show: "true", - }, - listeners: { - onChange: { - type: "sync", - order: [], - }, - preProcess: { - type: "sync", - order: [], - }, - }, - slots: {}, - render: CheckboxBlock, + widget: "checkbox", + type: BLOCK_TYPE_INPUT, + data: { + style: { + padding: "none", + }, + label: "Example Checkbox", + required: false, + disabled: false, + value: false, + show: "true", + }, + listeners: { + onChange: { + type: "sync", + order: [], + }, + preProcess: { + type: "sync", + order: [], + }, + }, + slots: {}, + render: CheckboxBlock, }; diff --git a/libs/renderer/src/components/block-defaults/checkbox-block/index.ts b/libs/renderer/src/components/block-defaults/checkbox-block/index.ts index fb8038bfa8..3f64c63a1f 100644 --- a/libs/renderer/src/components/block-defaults/checkbox-block/index.ts +++ b/libs/renderer/src/components/block-defaults/checkbox-block/index.ts @@ -1,2 +1,2 @@ -export * from "./config"; export * from "./CheckboxBlock"; +export * from "./config"; diff --git a/libs/renderer/src/components/block-defaults/chip-block/ChipBlock.tsx b/libs/renderer/src/components/block-defaults/chip-block/ChipBlock.tsx index 06c605e289..c75fac88c7 100644 --- a/libs/renderer/src/components/block-defaults/chip-block/ChipBlock.tsx +++ b/libs/renderer/src/components/block-defaults/chip-block/ChipBlock.tsx @@ -1,167 +1,165 @@ -import React, { useEffect } from "react"; -import { observer } from "mobx-react-lite"; -import { CSSProperties } from "react"; import { Face } from "@mui/icons-material"; -import { darken } from "@mui/material/styles"; import { Chip, styled } from "@mui/material"; - +import { darken } from "@mui/material/styles"; +import { observer } from "mobx-react-lite"; +import type React from "react"; +import { type CSSProperties, useEffect } from "react"; import { Avatar } from "@semoss/ui"; - -import { useBlock } from "../../../hooks"; -import { BlockDef, BlockComponent, ListenerActions } from "../../../store"; import { iconMap } from "../../../constants"; +import { useBlock } from "../../../hooks"; +import type { BlockComponent, BlockDef, ListenerActions } from "../../../store"; export interface ChipBlockDef extends BlockDef<"chip"> { - widget: "chip"; - data: { - type: string; - label: string; - style: CSSProperties; - variant: "filled" | "outlined"; - disabled?: boolean; - avatar?: React.ReactElement; - size: "small" | "medium"; - clickable?: boolean; - multiSelect?: boolean; - link?: string; - icon?: string; - src: string; - title: string; - show: string; - }; - listeners: { - preProcess: { - type: "sync" | "async"; - order: ListenerActions[]; - }; - }; - slots: never; + widget: "chip"; + data: { + type: string; + label: string; + style: CSSProperties; + variant: "filled" | "outlined"; + disabled?: boolean; + avatar?: React.ReactElement; + size: "small" | "medium"; + clickable?: boolean; + multiSelect?: boolean; + link?: string; + icon?: string; + src: string; + title: string; + show: string; + }; + listeners: { + preProcess: { + type: "sync" | "async"; + order: ListenerActions[]; + }; + }; + slots: never; } export const ChipBlock: BlockComponent = observer(({ id }) => { - const { attrs, data, listeners } = useBlock(id); + const { attrs, data, listeners } = useBlock(id); - useEffect(() => { - if (listeners.preProcess) { - listeners.preProcess(); - } - }, []); + useEffect(() => { + if (listeners.preProcess) { + listeners.preProcess(); + } + }, []); - const getContrastColor = (hexColor: string) => { - hexColor = hexColor.replace("#", ""); + const getContrastColor = (hexColor: string) => { + hexColor = hexColor.replace("#", ""); - // Parse hex values to RGB - const r = parseInt(hexColor.substring(0, 2), 16); - const g = parseInt(hexColor.substring(2, 4), 16); - const b = parseInt(hexColor.substring(4, 6), 16); + // Parse hex values to RGB + const r = parseInt(hexColor.substring(0, 2), 16); + const g = parseInt(hexColor.substring(2, 4), 16); + const b = parseInt(hexColor.substring(4, 6), 16); - const brightness = (r * 299 + g * 587 + b * 114) / 1000; + const brightness = (r * 299 + g * 587 + b * 114) / 1000; - return brightness >= 128 ? "#000000" : "#FFFFFF"; - }; + return brightness >= 128 ? "#000000" : "#FFFFFF"; + }; - const displayChip = (key): React.ReactNode => { - const avatar = data?.avatar; - const link = data?.link || null; - const color = data.style.color || "Default"; - const avatarColor = data.style.color || "rgb(156, 153, 153)"; - const Icon = iconMap[data.icon] || iconMap["Face"]; + const displayChip = (key): React.ReactNode => { + const avatar = data?.avatar; + const link = data?.link || null; + const color = data.style.color || "Default"; + const avatarColor = data.style.color || "rgb(156, 153, 153)"; + const Icon = iconMap[data.icon] || iconMap["Face"]; - const chipProps = { - label: data.label ?? data.type ?? "Chip", - size: data.size, - variant: data.variant, - clickable: data.clickable, - sx: { - backgroundColor: data.variant !== "outlined" && color, - color: - data.variant !== "outlined" - ? data.style.color - ? getContrastColor(data.style.color) - : "black" - : color, - border: - data.variant === "outlined" && - data.style.color && - `solid ${color}`, - }, - }; + const chipProps = { + label: data.label ?? data.type ?? "Chip", + size: data.size, + variant: data.variant, + clickable: data.clickable, + sx: { + backgroundColor: data.variant !== "outlined" && color, + color: + data.variant !== "outlined" + ? data.style.color + ? getContrastColor(data.style.color) + : "black" + : color, + border: + data.variant === "outlined" && + data.style.color && + `solid ${color}`, + }, + }; - switch (key) { - case "Chip": - return ; - case "Avatar": - return ( - - {avatar} - - } - /> - ); - case "Icon": - return ( - - } - /> - ); - case "Link": - return ( - - - - ); - default: - return ; - } - }; + switch (key) { + case "Chip": + return ; + case "Avatar": + return ( + + {avatar} + + } + /> + ); + case "Icon": + return ( + + } + /> + ); + case "Link": + return ( + + + + ); + default: + return ; + } + }; - return ( -
{ - // listeners.onClick(); - // }} - > - {displayChip(data.type)} -
- ); + return ( +
{ + // listeners.onClick(); + // }} + > + {displayChip(data.type)} +
+ ); }); diff --git a/libs/renderer/src/components/block-defaults/chip-block/config.tsx b/libs/renderer/src/components/block-defaults/chip-block/config.tsx index bc0b1c587e..1c70794c74 100644 --- a/libs/renderer/src/components/block-defaults/chip-block/config.tsx +++ b/libs/renderer/src/components/block-defaults/chip-block/config.tsx @@ -1,33 +1,31 @@ import { CSSProperties } from "react"; - import { Avatar } from "@semoss/ui"; - -import { BlockConfig } from "../../../store"; +import type { BlockConfig } from "../../../store"; import { BLOCK_TYPE_DISPLAY } from "../block-defaults.constants"; -import { ChipBlockDef, ChipBlock } from "./ChipBlock"; +import { ChipBlock, type ChipBlockDef } from "./ChipBlock"; export const config: BlockConfig = { - widget: "chip", - type: BLOCK_TYPE_DISPLAY, - data: { - style: { - color: "grey", - }, - size: "small", - avatar: A, - type: "Chip", - variant: "filled", - label: "", - src: "", - title: "", - show: "true", - }, - listeners: { - preProcess: { - type: "sync", - order: [], - }, - }, - slots: {}, - render: ChipBlock, + widget: "chip", + type: BLOCK_TYPE_DISPLAY, + data: { + style: { + color: "grey", + }, + size: "small", + avatar: A, + type: "Chip", + variant: "filled", + label: "", + src: "", + title: "", + show: "true", + }, + listeners: { + preProcess: { + type: "sync", + order: [], + }, + }, + slots: {}, + render: ChipBlock, }; diff --git a/libs/renderer/src/components/block-defaults/chip-block/index.ts b/libs/renderer/src/components/block-defaults/chip-block/index.ts index 7807e82085..a6727d4c23 100644 --- a/libs/renderer/src/components/block-defaults/chip-block/index.ts +++ b/libs/renderer/src/components/block-defaults/chip-block/index.ts @@ -1,2 +1,2 @@ -export * from "./config"; export * from "./ChipBlock"; +export * from "./config"; diff --git a/libs/renderer/src/components/block-defaults/container-block/ContainerBlock.tsx b/libs/renderer/src/components/block-defaults/container-block/ContainerBlock.tsx index c1c0c3c4fd..800bae4e07 100644 --- a/libs/renderer/src/components/block-defaults/container-block/ContainerBlock.tsx +++ b/libs/renderer/src/components/block-defaults/container-block/ContainerBlock.tsx @@ -1,89 +1,89 @@ -import { CSSProperties, useEffect } from "react"; import { observer } from "mobx-react-lite"; +import { type CSSProperties, useEffect } from "react"; import { useBlock } from "../../../hooks"; -import { BlockDef, BlockComponent, ListenerActions } from "../../../store"; +import type { BlockComponent, BlockDef, ListenerActions } from "../../../store"; import { Slot } from "../../blocks"; export type BoxShadowParts = { - offsetX?: string; - offsetY?: string; - blurRadius?: string; - spreadRadius?: string; - color?: string; + offsetX?: string; + offsetY?: string; + blurRadius?: string; + spreadRadius?: string; + color?: string; }; export interface ContainerBlockDef extends BlockDef<"container"> { - widget: "container"; - data: { - style: CSSProperties; - show: string; - type: "custom" | "grid"; - dimension?: null | string; - rowSpacing?: null | string; - boxShadowParts: BoxShadowParts; - }; - slots: { - children: true; - }; - listeners: { - preProcess: { - type: "sync" | "async"; - order: ListenerActions[]; - }; - }; + widget: "container"; + data: { + style: CSSProperties; + show: string; + type: "custom" | "grid"; + dimension?: null | string; + rowSpacing?: null | string; + boxShadowParts: BoxShadowParts; + }; + slots: { + children: true; + }; + listeners: { + preProcess: { + type: "sync" | "async"; + order: ListenerActions[]; + }; + }; } export const ContainerBlock: BlockComponent = observer(({ id }) => { - const { attrs, data, slots, listeners } = useBlock(id); - const buildBoxShadowFromParts = (parts?: BoxShadowParts): string => { - if (!parts) return ""; + const { attrs, data, slots, listeners } = useBlock(id); + const buildBoxShadowFromParts = (parts?: BoxShadowParts): string => { + if (!parts) return ""; - const safe = (value?: string): string => { - // Check if the value is defined. If so, trim whitespace and return it. - // If not, return the default value "0px". - return value?.trim() || "0px"; - }; + const safe = (value?: string): string => { + // Check if the value is defined. If so, trim whitespace and return it. + // If not, return the default value "0px". + return value?.trim() || "0px"; + }; - /** - * The color of the box shadow. If it doesn't exist, default to "rgba(0,0,0,0.2)" - * @type {string} - */ - const color = parts?.color?.trim() || "rgba(0,0,0,0.2)"; + /** + * The color of the box shadow. If it doesn't exist, default to "rgba(0,0,0,0.2)" + * @type {string} + */ + const color = parts?.color?.trim() || "rgba(0,0,0,0.2)"; - /** - * The box shadow string. This is constructed by joining the parts of the box - * shadow with spaces. The resulting string should look like: - * "offset-x offset-y blur-radius spread-radius color" - * @type {string} - */ - const shadow = [ - safe(parts?.offsetX), // offset-x - safe(parts?.offsetY), // offset-y - safe(parts?.blurRadius), // blur-radius - safe(parts?.spreadRadius), // spread-radius - color, // color - ].join(" "); + /** + * The box shadow string. This is constructed by joining the parts of the box + * shadow with spaces. The resulting string should look like: + * "offset-x offset-y blur-radius spread-radius color" + * @type {string} + */ + const shadow = [ + safe(parts?.offsetX), // offset-x + safe(parts?.offsetY), // offset-y + safe(parts?.blurRadius), // blur-radius + safe(parts?.spreadRadius), // spread-radius + color, // color + ].join(" "); - return shadow as string; - }; + return shadow as string; + }; - useEffect(() => { - if (listeners.preProcess) { - listeners.preProcess(); - } - }, []); + useEffect(() => { + if (listeners.preProcess) { + listeners.preProcess(); + } + }, []); - return ( -
- -
- ); + return ( +
+ +
+ ); }); diff --git a/libs/renderer/src/components/block-defaults/container-block/config.tsx b/libs/renderer/src/components/block-defaults/container-block/config.tsx index a4c1364f95..df93c0fd54 100644 --- a/libs/renderer/src/components/block-defaults/container-block/config.tsx +++ b/libs/renderer/src/components/block-defaults/container-block/config.tsx @@ -1,40 +1,39 @@ import { HighlightAlt } from "@mui/icons-material"; - -import { BlockConfig } from "../../../store"; -import { ContainerBlockDef, ContainerBlock } from "./ContainerBlock"; +import type { BlockConfig } from "../../../store"; import { BLOCK_TYPE_LAYOUT } from "../block-defaults.constants"; +import { ContainerBlock, type ContainerBlockDef } from "./ContainerBlock"; // export the config for the block export const config: BlockConfig = { - widget: "container", - type: BLOCK_TYPE_LAYOUT, - data: { - type: "custom", - dimension: null, - show: "true", - style: { - display: "flex", - flexDirection: "column", - padding: "4px", - gap: "8px", - flexWrap: "wrap", - }, - boxShadowParts: { - offsetX: "", - offsetY: "", - blurRadius: "", - spreadRadius: "", - color: "", - }, - }, - listeners: { - preProcess: { - type: "sync", - order: [], - }, - }, - slots: { - children: [], - }, - render: ContainerBlock, + widget: "container", + type: BLOCK_TYPE_LAYOUT, + data: { + type: "custom", + dimension: null, + show: "true", + style: { + display: "flex", + flexDirection: "column", + padding: "4px", + gap: "8px", + flexWrap: "wrap", + }, + boxShadowParts: { + offsetX: "", + offsetY: "", + blurRadius: "", + spreadRadius: "", + color: "", + }, + }, + listeners: { + preProcess: { + type: "sync", + order: [], + }, + }, + slots: { + children: [], + }, + render: ContainerBlock, }; diff --git a/libs/renderer/src/components/block-defaults/container-block/index.ts b/libs/renderer/src/components/block-defaults/container-block/index.ts index 70922a9bac..79cd8a89d0 100644 --- a/libs/renderer/src/components/block-defaults/container-block/index.ts +++ b/libs/renderer/src/components/block-defaults/container-block/index.ts @@ -1,2 +1,2 @@ -export * from "./config"; export * from "./ContainerBlock"; +export * from "./config"; diff --git a/libs/renderer/src/components/block-defaults/divider-block/DividerBlock.tsx b/libs/renderer/src/components/block-defaults/divider-block/DividerBlock.tsx index 7288f8a613..a42419d0be 100644 --- a/libs/renderer/src/components/block-defaults/divider-block/DividerBlock.tsx +++ b/libs/renderer/src/components/block-defaults/divider-block/DividerBlock.tsx @@ -1,84 +1,83 @@ -import { CSSProperties, useEffect } from "react"; -import { observer } from "mobx-react-lite"; import { Divider, styled } from "@mui/material"; - +import { observer } from "mobx-react-lite"; +import { type CSSProperties, useEffect } from "react"; import { useBlock } from "../../../hooks"; -import { BlockDef, BlockComponent, ListenerActions } from "../../../store"; +import type { BlockComponent, BlockDef, ListenerActions } from "../../../store"; const StyledContainer = styled("div")(({ theme }) => ({ - padding: "4px", - display: "flex", - flexDirection: "column", - gap: "8px", + padding: "4px", + display: "flex", + flexDirection: "column", + gap: "8px", })); export interface DividerBlockDef extends BlockDef<"divider"> { - widget: "divider"; - data: { - style: CSSProperties; - variant: "fullWidth" | "inset" | "middle"; - orientation: "horizontal" | "vertical"; - textAlign: "center" | "right" | "left"; - flexItem: boolean; - light: boolean; - text: string; - showText: boolean; - show: string; - }; - slots: never; - listeners: { - preProcess: { - type: "sync" | "async"; - order: ListenerActions[]; - }; - }; + widget: "divider"; + data: { + style: CSSProperties; + variant: "fullWidth" | "inset" | "middle"; + orientation: "horizontal" | "vertical"; + textAlign: "center" | "right" | "left"; + flexItem: boolean; + light: boolean; + text: string; + showText: boolean; + show: string; + }; + slots: never; + listeners: { + preProcess: { + type: "sync" | "async"; + order: ListenerActions[]; + }; + }; } export const DividerBlock: BlockComponent = observer(({ id }) => { - try { - const { attrs, data, listeners } = useBlock(id); + try { + const { attrs, data, listeners } = useBlock(id); - useEffect(() => { - if (listeners.preProcess) { - listeners.preProcess(); - } - }, []); + useEffect(() => { + if (listeners.preProcess) { + listeners.preProcess(); + } + }, []); - // Determine if we should show text - const hasText = data.showText && data.text?.trim().length > 0; + // Determine if we should show text + const hasText = data.showText && data.text?.trim().length > 0; - return ( - - {hasText ? ( - - {data.text} - - ) : ( - - )} - - ); - } catch (error) { - console.error("Error in DividerBlock:", error); - return
Error loading Divider component
; - } + return ( + + {hasText ? ( + + {data.text} + + ) : ( + + )} + + ); + } catch (error) { + console.error("Error in DividerBlock:", error); + return
Error loading Divider component
; + } }); diff --git a/libs/renderer/src/components/block-defaults/divider-block/config.tsx b/libs/renderer/src/components/block-defaults/divider-block/config.tsx index a50b3734a7..c756e170d3 100644 --- a/libs/renderer/src/components/block-defaults/divider-block/config.tsx +++ b/libs/renderer/src/components/block-defaults/divider-block/config.tsx @@ -1,29 +1,29 @@ import { CSSProperties } from "react"; -import { BlockConfig } from "../../../store"; -import { DividerBlockDef, DividerBlock } from "./DividerBlock"; +import type { BlockConfig } from "../../../store"; import { BLOCK_TYPE_DISPLAY } from "../block-defaults.constants"; +import { DividerBlock, type DividerBlockDef } from "./DividerBlock"; // export the config for the block export const config: BlockConfig = { - widget: "divider", - type: BLOCK_TYPE_DISPLAY, - data: { - style: {}, - variant: "fullWidth", - orientation: "horizontal", - textAlign: "center", - flexItem: false, - light: false, - text: "", - showText: false, - show: "true", - }, - listeners: { - preProcess: { - type: "sync", - order: [], - }, - }, - slots: {}, - render: DividerBlock, + widget: "divider", + type: BLOCK_TYPE_DISPLAY, + data: { + style: {}, + variant: "fullWidth", + orientation: "horizontal", + textAlign: "center", + flexItem: false, + light: false, + text: "", + showText: false, + show: "true", + }, + listeners: { + preProcess: { + type: "sync", + order: [], + }, + }, + slots: {}, + render: DividerBlock, }; diff --git a/libs/renderer/src/components/block-defaults/divider-block/index.ts b/libs/renderer/src/components/block-defaults/divider-block/index.ts index f0ee6ad6c7..cb69411802 100644 --- a/libs/renderer/src/components/block-defaults/divider-block/index.ts +++ b/libs/renderer/src/components/block-defaults/divider-block/index.ts @@ -1,2 +1,2 @@ -export * from "./DividerBlock"; export * from "./config"; +export * from "./DividerBlock"; diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/CustomContextMenu.tsx b/libs/renderer/src/components/block-defaults/echart-visualization-block/CustomContextMenu.tsx index 3e681f7a32..16afe11bdb 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/CustomContextMenu.tsx +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/CustomContextMenu.tsx @@ -1,93 +1,91 @@ import { observer } from "mobx-react-lite"; - -import { MenuTwo, MenuItemTwo } from "@semoss/ui"; - -import { useBlock, useFrame } from "../../../hooks"; -import { EchartVisualizationBlockDef } from "./VisualizationBlock"; +import { MenuItemTwo, MenuTwo } from "@semoss/ui"; +import { useBlock, type useFrame } from "../../../hooks"; +import type { EchartVisualizationBlockDef } from "./VisualizationBlock"; export interface VizBlockContextMenuProps { - /** ID of the block */ - id: string; - /** Frame that the user is interacting with */ - frame: ReturnType; - /** Context MenuTwo */ - contextMenu: { - mouseX: number; - mouseY: number; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - value: any; - } | null; - /** Close the context menu */ - onClose: () => void; + /** ID of the block */ + id: string; + /** Frame that the user is interacting with */ + frame: ReturnType; + /** Context MenuTwo */ + contextMenu: { + mouseX: number; + mouseY: number; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + value: any; + } | null; + /** Close the context menu */ + onClose: () => void; } export const CustomContextMenu: React.FC = observer( - ({ id = "", frame = null, contextMenu = null, onClose = () => null }) => { - const { data } = useBlock(id); - return ( - onClose()} - anchorReference="anchorPosition" - anchorPosition={ - contextMenu !== null - ? { - top: contextMenu.mouseY, - left: contextMenu.mouseX, - } - : undefined - } - > - {contextMenu && !data.contextMenu?.hideUnfilter ? ( - { - frame.unfilter(); - onClose(); - }} - > - Unfilter - - ) : null} - {contextMenu && !data.contextMenu?.hideFilter ? ( - { - frame.filter( - `SetFrameFilter(${ - contextMenu.value.label - }==${JSON.stringify(contextMenu.value.value)})`, - ); - onClose(); - }} - > - Filter {contextMenu.value.label} == - {typeof contextMenu.value.value === "string" - ? contextMenu.value.value - : JSON.stringify(contextMenu.value.value)} - - ) : null} - {contextMenu && !data.contextMenu?.hideExclude ? ( - { - frame.filter( - `SetFrameFilter(${ - contextMenu.value.label - }!=${JSON.stringify(contextMenu.value.value)})`, - ); - onClose(); - }} - > - Exclude {contextMenu.value.label} != - {typeof contextMenu.value.value === "string" - ? contextMenu.value.value - : JSON.stringify(contextMenu.value.value)} - - ) : null} - - ); - }, + ({ id = "", frame = null, contextMenu = null, onClose = () => null }) => { + const { data } = useBlock(id); + return ( + onClose()} + anchorReference="anchorPosition" + anchorPosition={ + contextMenu !== null + ? { + top: contextMenu.mouseY, + left: contextMenu.mouseX, + } + : undefined + } + > + {contextMenu && !data.contextMenu?.hideUnfilter ? ( + { + frame.unfilter(); + onClose(); + }} + > + Unfilter + + ) : null} + {contextMenu && !data.contextMenu?.hideFilter ? ( + { + frame.filter( + `SetFrameFilter(${ + contextMenu.value.label + }==${JSON.stringify(contextMenu.value.value)})`, + ); + onClose(); + }} + > + Filter {contextMenu.value.label} == + {typeof contextMenu.value.value === "string" + ? contextMenu.value.value + : JSON.stringify(contextMenu.value.value)} + + ) : null} + {contextMenu && !data.contextMenu?.hideExclude ? ( + { + frame.filter( + `SetFrameFilter(${ + contextMenu.value.label + }!=${JSON.stringify(contextMenu.value.value)})`, + ); + onClose(); + }} + > + Exclude {contextMenu.value.label} != + {typeof contextMenu.value.value === "string" + ? contextMenu.value.value + : JSON.stringify(contextMenu.value.value)} + + ) : null} + + ); + }, ); diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/Visualization.constants.ts b/libs/renderer/src/components/block-defaults/echart-visualization-block/Visualization.constants.ts index d19971c121..a84f677c06 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/Visualization.constants.ts +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/Visualization.constants.ts @@ -1,78 +1,78 @@ export const BAR_CHART_DATA = { - NAME: "Bar Chart", - CODE: "bar-chart", - ECHARTCODE: "bar-e-chart", - JSONVALUE: ["bar"], - HEIGHT: 350, - WEIGHT: 450, + NAME: "Bar Chart", + CODE: "bar-chart", + ECHARTCODE: "bar-e-chart", + JSONVALUE: ["bar"], + HEIGHT: 350, + WEIGHT: 450, }; export const LINE_CHART_DATA = { - NAME: "Line Chart", - CODE: "line-chart", - ECHARTCODE: "line-e-chart", - JSONVALUE: ["line"], + NAME: "Line Chart", + CODE: "line-chart", + ECHARTCODE: "line-e-chart", + JSONVALUE: ["line"], }; export const PIE_CHART_DATA = { - NAME: "Pie Chart", - CODE: "pie-chart", - ECHARTCODE: "pie-e-chart", - JSONVALUE: ["pie"], - HEIGHT: 350, - WEIGHT: 450, + NAME: "Pie Chart", + CODE: "pie-chart", + ECHARTCODE: "pie-e-chart", + JSONVALUE: ["pie"], + HEIGHT: 350, + WEIGHT: 450, }; export const FontFamily = [ - "Arail", - "Arail Black", - "Arail Narrow", - "Calibri", - "Century Gothic", - "Comic Sans MS", - "Courier New", - "Garamond", - "Georgia", - "Helvetica", - "Inter", - "Open Sans", - "Sans-Serif", - "Segoe UI", - "Times New Roman", - "Verdana", + "Arail", + "Arail Black", + "Arail Narrow", + "Calibri", + "Century Gothic", + "Comic Sans MS", + "Courier New", + "Garamond", + "Georgia", + "Helvetica", + "Inter", + "Open Sans", + "Sans-Serif", + "Segoe UI", + "Times New Roman", + "Verdana", ]; export const Pie_Alignment = ["inside", "outside"]; export const FontWeights = [ - "bold", - "normal", - "100", - "200", - "300", - "400", - "500", - "600", - "700", - "800", - "900", + "bold", + "normal", + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", ]; export const Title_Alignment = ["left", "right", "center"]; export const ECHART_BAR_COLOUR = "#5470c6"; export const Line_Alignment = [ - "top", - "bottom", - "left", - "right", - "inside", - "insideTop", - "insideBottom", - "insideLeft", - "insideRight", - "insideTopLeft", - "insideTopRight", - "insideBottomLeft", - "insideBottomRight", + "top", + "bottom", + "left", + "right", + "inside", + "insideTop", + "insideBottom", + "insideLeft", + "insideRight", + "insideTopLeft", + "insideTopRight", + "insideBottomLeft", + "insideBottomRight", ]; export const Line_Curve_Type = ["Smooth", "Exact", "Step"]; export const Line_Type = ["Solid", "Dashed", "Dotted"]; export const GANTT_CHART = { - MILESTONE_COLOR: "#80af6c", - MILESTONE_SYMBOL: "triangle", - MILESTONE_SYMBOL_SIZE: 16, + MILESTONE_COLOR: "#80af6c", + MILESTONE_SYMBOL: "triangle", + MILESTONE_SYMBOL_SIZE: 16, }; diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/VisualizationBlock.tsx b/libs/renderer/src/components/block-defaults/echart-visualization-block/VisualizationBlock.tsx index 19304aeb61..38d7d3d3de 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/VisualizationBlock.tsx +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/VisualizationBlock.tsx @@ -1,11 +1,9 @@ -import { useEffect, useMemo, useRef, useState } from "react"; -import { observer } from "mobx-react-lite"; import { styled } from "@mui/material"; - +import { observer } from "mobx-react-lite"; +import { useEffect, useMemo, useRef, useState } from "react"; import { useBlock, useBlocks } from "../../../hooks"; -import { BlockComponent, BlockDef, ListenerActions } from "../../../store"; -import { PathValue } from "../../../types"; - +import type { BlockComponent, BlockDef, ListenerActions } from "../../../store"; +import type { PathValue } from "../../../types"; import { BAR_CHART_DATA } from "./Visualization.constants"; import { Bar } from "./variant/bar-chart/Bar"; import { Dendrogram } from "./variant/dendrogram/Dendrogram"; @@ -14,214 +12,213 @@ import { Line } from "./variant/line-chart/Line"; import { Map } from "./variant/map-chart/Map"; import { Pie } from "./variant/pie-chart/Pie"; import { ScatterPlotBlock } from "./variant/scatter-plot/ScatterPlot"; - import { StackChart } from "./variant/stack-chart/StackChart"; const StyledNoDataContainer = styled("div", { - shouldForwardProp: (prop) => prop !== "error", + shouldForwardProp: (prop) => prop !== "error", })<{ error?: boolean }>(({ error = false, theme }) => ({ - minHeight: "50%", - minWidth: "50%", - maxWidth: "80%", - maxHeight: "80%", - color: error ? theme.palette.error.main : "unset", + minHeight: "50%", + minWidth: "50%", + maxWidth: "80%", + maxHeight: "80%", + color: error ? theme.palette.error.main : "unset", })); const StyledDataContainer = styled("div", { - shouldForwardProp: (prop) => prop !== "error", + shouldForwardProp: (prop) => prop !== "error", })<{ error?: boolean }>(({ error = false, theme }) => ({ - minHeight: "50%", - minWidth: "50%", + minHeight: "50%", + minWidth: "50%", })); export interface VisualizationColumns { - name: string; - selector: string; - width: string; + name: string; + selector: string; + width: string; } export interface FacetColumns { - name: string; - selector: string; - value: string | number; - isFacet?: boolean; + name: string; + selector: string; + value: string | number; + isFacet?: boolean; } export interface EchartVisualizationBlockDef { - widget: "e-chart"; - data: { - style: { - height: number; - width: number; - display: string | undefined; - // flexDirection: string | undefined; - padding: string | undefined; - gap: string | undefined; - // flexWrap: string | undefined; - }; - option: {}; - frame: { - name: string; - }; - variation: undefined | string; - columns: VisualizationColumns[]; - aggregate: Record; - contextMenu: { - hideUnfilter: boolean; - hideFilter: boolean; - hideExclude: boolean; - }; - show: boolean; - facet: { - facetList: string[] | number[]; - facetSelected: FacetColumns[]; - }; - }; - listeners: { - preProcess: { - type: "sync" | "async"; - order: ListenerActions[]; - }; - }; - slots: never; + widget: "e-chart"; + data: { + style: { + height: number; + width: number; + display: string | undefined; + // flexDirection: string | undefined; + padding: string | undefined; + gap: string | undefined; + // flexWrap: string | undefined; + }; + option: {}; + frame: { + name: string; + }; + variation: undefined | string; + columns: VisualizationColumns[]; + aggregate: Record; + contextMenu: { + hideUnfilter: boolean; + hideFilter: boolean; + hideExclude: boolean; + }; + show: boolean; + facet: { + facetList: string[] | number[]; + facetSelected: FacetColumns[]; + }; + }; + listeners: { + preProcess: { + type: "sync" | "async"; + order: ListenerActions[]; + }; + }; + slots: never; } export const VisualizationBlock: BlockComponent = observer( - ({ id }) => { - const { data, setData, attrs, listeners } = - useBlock(id); - const { state } = useBlocks(); + ({ id }) => { + const { data, setData, attrs, listeners } = + useBlock(id); + const { state } = useBlocks(); - const elementRef = useRef(null); - const timeoutRef = useRef>(null); + const elementRef = useRef(null); + const timeoutRef = useRef>(null); - useEffect(() => { - if (listeners.preProcess) { - listeners.preProcess(); - } - }, []); - /** - * - * @param data - * @param path - * @description update chart json when data is changed - */ - function updateChartJson(data: any, path: any) { - const parsedData = - typeof data === "string" ? JSON.parse(data) : data; - if (timeoutRef.current) { - clearTimeout(timeoutRef.current); - timeoutRef.current = null; - } - timeoutRef.current = setTimeout(() => { - try { - setData( - "option", - parsedData as PathValue, - ); - } catch (e) { - console.log(e); - } - }, 300); - } + useEffect(() => { + if (listeners.preProcess) { + listeners.preProcess(); + } + }, []); + /** + * + * @param data + * @param path + * @description update chart json when data is changed + */ + function updateChartJson(data: any, path: any) { + const parsedData = + typeof data === "string" ? JSON.parse(data) : data; + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + timeoutRef.current = null; + } + timeoutRef.current = setTimeout(() => { + try { + setData( + "option", + parsedData as PathValue, + ); + } catch (e) { + console.log(e); + } + }, 300); + } - /** - * @description get the updated data style when data.style is changed - */ - const updatedDataStyle = useMemo(() => { - const isEm = - data.style.height.toString().endsWith("em") && - data.style.width.toString().endsWith("em"); - const isPx = - data.style.height.toString().endsWith("px") && - data.style.width.toString().endsWith("px"); - if (isEm || isPx) return { ...data.style }; //if values mentioned in em or px, then return same style - const calculatedHeight = data.style.height; - const calculatedWidth = data.style.width; - //return updated style - return { - ...data.style, - height: calculatedHeight, - width: calculatedWidth, - }; - }, [data.style]); + /** + * @description get the updated data style when data.style is changed + */ + const updatedDataStyle = useMemo(() => { + const isEm = + data.style.height.toString().endsWith("em") && + data.style.width.toString().endsWith("em"); + const isPx = + data.style.height.toString().endsWith("px") && + data.style.width.toString().endsWith("px"); + if (isEm || isPx) return { ...data.style }; //if values mentioned in em or px, then return same style + const calculatedHeight = data.style.height; + const calculatedWidth = data.style.width; + //return updated style + return { + ...data.style, + height: calculatedHeight, + width: calculatedWidth, + }; + }, [data.style]); - if (!data.option) { - return ( - - Add JSON to render your visualization - - ); - } + if (!data.option) { + return ( + + Add JSON to render your visualization + + ); + } - if (typeof data.option === "string") { - try { - return ( - - {data.variation === "echart-bar-graph" && ( - - )} - {data.variation === "echart-pie-chart" && ( - - )} - {data.variation === "echart-scatter-plots" && ( - - )} - {data.variation === "echart-world-map-chart" && ( - - )} - {data.variation === "echart-line-graph" && ( - - )} - {data.variation === "echart-stack-chart" && ( - - )} - {data.variation === "echart-gantt-chart" && ( - - )} - {data.variation === "echart-dendrogram-chart" && ( - - )} - - ); - } catch (e) { - return ( - - There was an issue parsing your JSON. - - ); - } - } - return ( - - {data.variation === "echart-bar-graph" && ( - - )} - {data.variation === "echart-pie-chart" && ( - - )} - {data.variation === "echart-scatter-plots" && ( - - )} - {data.variation === "echart-world-map-chart" && ( - - )} - {data.variation === "echart-line-graph" && ( - - )} - {data.variation === "echart-stack-chart" && ( - - )} - {data.variation === "echart-gantt-chart" && ( - - )} - {data.variation === "echart-dendrogram-chart" && ( - - )} - - ); - }, + if (typeof data.option === "string") { + try { + return ( + + {data.variation === "echart-bar-graph" && ( + + )} + {data.variation === "echart-pie-chart" && ( + + )} + {data.variation === "echart-scatter-plots" && ( + + )} + {data.variation === "echart-world-map-chart" && ( + + )} + {data.variation === "echart-line-graph" && ( + + )} + {data.variation === "echart-stack-chart" && ( + + )} + {data.variation === "echart-gantt-chart" && ( + + )} + {data.variation === "echart-dendrogram-chart" && ( + + )} + + ); + } catch (e) { + return ( + + There was an issue parsing your JSON. + + ); + } + } + return ( + + {data.variation === "echart-bar-graph" && ( + + )} + {data.variation === "echart-pie-chart" && ( + + )} + {data.variation === "echart-scatter-plots" && ( + + )} + {data.variation === "echart-world-map-chart" && ( + + )} + {data.variation === "echart-line-graph" && ( + + )} + {data.variation === "echart-stack-chart" && ( + + )} + {data.variation === "echart-gantt-chart" && ( + + )} + {data.variation === "echart-dendrogram-chart" && ( + + )} + + ); + }, ); diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/VizBlockContextMenu.tsx b/libs/renderer/src/components/block-defaults/echart-visualization-block/VizBlockContextMenu.tsx index 9d2a95f342..16b6a8da2c 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/VizBlockContextMenu.tsx +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/VizBlockContextMenu.tsx @@ -1,97 +1,95 @@ import { observer } from "mobx-react-lite"; - -import { MenuTwo, MenuItemTwo } from "@semoss/ui"; - -import { useBlock, useFrame } from "../../../hooks"; -import { EchartVisualizationBlockDef } from "./VisualizationBlock"; +import { MenuItemTwo, MenuTwo } from "@semoss/ui"; +import { useBlock, type useFrame } from "../../../hooks"; +import type { EchartVisualizationBlockDef } from "./VisualizationBlock"; export interface VizBlockContextMenuProps { - /** ID of the block */ - id: string; + /** ID of the block */ + id: string; - /** Frame that the user is interacting with */ - frame: ReturnType; + /** Frame that the user is interacting with */ + frame: ReturnType; - /** Context MenuTwo */ - contextMenu: { - mouseX: number; - mouseY: number; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - value: any; - } | null; + /** Context MenuTwo */ + contextMenu: { + mouseX: number; + mouseY: number; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + value: any; + } | null; - /** Close the context menu */ - onClose: () => void; + /** Close the context menu */ + onClose: () => void; } export const VizBlockContextMenu: React.FC = observer( - ({ id = "", frame = null, contextMenu = null, onClose = () => null }) => { - const { data } = useBlock(id); - return ( - onClose()} - anchorReference="anchorPosition" - anchorPosition={ - contextMenu !== null - ? { - top: contextMenu.mouseY, - left: contextMenu.mouseX, - } - : undefined - } - > - {contextMenu && !data.contextMenu?.hideUnfilter ? ( - { - frame.unfilter(); - onClose(); - }} - > - Unfilter - - ) : null} - {contextMenu && !data.contextMenu?.hideFilter ? ( - { - frame.filter( - `SetFrameFilter(${ - contextMenu.value.label - }==${JSON.stringify(contextMenu.value.value)})`, - ); - onClose(); - }} - > - Filter {contextMenu.value.label} == - {typeof contextMenu.value.value === "string" - ? contextMenu.value.value - : JSON.stringify(contextMenu.value.value)} - - ) : null} - {contextMenu && !data.contextMenu?.hideExclude ? ( - { - frame.filter( - `SetFrameFilter(${ - contextMenu.value.label - }!=${JSON.stringify(contextMenu.value.value)})`, - ); - onClose(); - }} - > - Exclude {contextMenu.value.label} != - {typeof contextMenu.value.value === "string" - ? contextMenu.value.value - : JSON.stringify(contextMenu.value.value)} - - ) : null} - - ); - }, + ({ id = "", frame = null, contextMenu = null, onClose = () => null }) => { + const { data } = useBlock(id); + return ( + onClose()} + anchorReference="anchorPosition" + anchorPosition={ + contextMenu !== null + ? { + top: contextMenu.mouseY, + left: contextMenu.mouseX, + } + : undefined + } + > + {contextMenu && !data.contextMenu?.hideUnfilter ? ( + { + frame.unfilter(); + onClose(); + }} + > + Unfilter + + ) : null} + {contextMenu && !data.contextMenu?.hideFilter ? ( + { + frame.filter( + `SetFrameFilter(${ + contextMenu.value.label + }==${JSON.stringify(contextMenu.value.value)})`, + ); + onClose(); + }} + > + Filter {contextMenu.value.label} == + {typeof contextMenu.value.value === "string" + ? contextMenu.value.value + : JSON.stringify(contextMenu.value.value)} + + ) : null} + {contextMenu && !data.contextMenu?.hideExclude ? ( + { + frame.filter( + `SetFrameFilter(${ + contextMenu.value.label + }!=${JSON.stringify(contextMenu.value.value)})`, + ); + onClose(); + }} + > + Exclude {contextMenu.value.label} != + {typeof contextMenu.value.value === "string" + ? contextMenu.value.value + : JSON.stringify(contextMenu.value.value)} + + ) : null} + + ); + }, ); diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/config.tsx b/libs/renderer/src/components/block-defaults/echart-visualization-block/config.tsx index 5f48a3082e..ede009ac42 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/config.tsx +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/config.tsx @@ -1,47 +1,47 @@ -import { BlockConfig } from "../../../store"; +import type { BlockConfig } from "../../../store"; import { BLOCK_TYPE_CHART } from "../block-defaults.constants"; import { - VisualizationBlock, - EchartVisualizationBlockDef, + type EchartVisualizationBlockDef, + VisualizationBlock, } from "./VisualizationBlock"; export const config: BlockConfig = { - widget: "e-chart", - type: BLOCK_TYPE_CHART, - data: { - style: { - display: "flex", - // flexDirection: 'column', - padding: "4px", - gap: "8px", - // flexWrap: 'wrap', - width: 450, - height: 350, - }, - option: {}, - variation: "", - frame: { - name: "", - }, - columns: [], - aggregate: {}, - contextMenu: { - hideFilter: false, - hideUnfilter: false, - hideExclude: false, - }, - show: true, - facet: { - facetList: [], - facetSelected: [], - }, - }, - listeners: { - preProcess: { - type: "sync", - order: [], - }, - }, - slots: {}, - render: VisualizationBlock, + widget: "e-chart", + type: BLOCK_TYPE_CHART, + data: { + style: { + display: "flex", + // flexDirection: 'column', + padding: "4px", + gap: "8px", + // flexWrap: 'wrap', + width: 450, + height: 350, + }, + option: {}, + variation: "", + frame: { + name: "", + }, + columns: [], + aggregate: {}, + contextMenu: { + hideFilter: false, + hideUnfilter: false, + hideExclude: false, + }, + show: true, + facet: { + facetList: [], + facetSelected: [], + }, + }, + listeners: { + preProcess: { + type: "sync", + order: [], + }, + }, + slots: {}, + render: VisualizationBlock, }; diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/Gantt/Gantt.tsx b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/Gantt/Gantt.tsx index 85ecc0d4f5..6dc1e8ebaa 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/Gantt/Gantt.tsx +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/Gantt/Gantt.tsx @@ -1,900 +1,898 @@ -import { useEffect, useMemo, useRef, useState } from "react"; +import ReactECharts from "echarts-for-react"; import { computed } from "mobx"; import { observer } from "mobx-react-lite"; -import ReactECharts from "echarts-for-react"; - +import { useEffect, useMemo, useRef, useState } from "react"; import { - TableTwo, - TableHeadTwo, - TableRowTwo, - TableCellTwo, - TableBodyTwo, - styled, + styled, + TableBodyTwo, + TableCellTwo, + TableHeadTwo, + TableRowTwo, + TableTwo, } from "@semoss/ui"; - import { useBlock, useFrame } from "../../../../../hooks"; -import { BlockDef } from "../../../../../store"; +import type { BlockDef } from "../../../../../store"; import { getValueByPath } from "../../../../../utility"; -import { EchartVisualizationBlockDef } from "../../VisualizationBlock"; - import { GANTT_CHART } from "../../Visualization.constants"; +import type { EchartVisualizationBlockDef } from "../../VisualizationBlock"; import { VizBlockContextMenu } from "../../VizBlockContextMenu"; //Main container where gantt chart will render const StyledMainContainer = styled("div")(({ theme }) => ({ - width: "100%", - height: "100%", + width: "100%", + height: "100%", })); //sub styled container to manage fiscal axis with chart const StyledContainer = styled("div")(() => ({ - display: "flex", - justifyContent: "flex-start", - width: "100%", - height: "20%", - maxHeight: "25%", - overflow: "auto", + display: "flex", + justifyContent: "flex-start", + width: "100%", + height: "20%", + maxHeight: "25%", + overflow: "auto", })); //styled span to render series name const StyledDataSpan = styled("span")(({}) => ({})); //styled table cell to have background color const StyledTableCell = styled(TableCellTwo)<{ backgroundColor?: string }>( - ({ backgroundColor }) => ({ - backgroundColor: backgroundColor ?? "#fff", - border: "1px solid #e6e6e6", - }), + ({ backgroundColor }) => ({ + backgroundColor: backgroundColor ?? "#fff", + border: "1px solid #e6e6e6", + }), ); //Gantt chart props interface GanttProps { - id: string; - updateChart: (dataOption, path) => void; + id: string; + updateChart: (dataOption, path) => void; } //Gantt chart main component export const Gantt = observer( - ({ id, updateChart }: GanttProps) => { - const { data } = useBlock(id); + ({ id, updateChart }: GanttProps) => { + const { data } = useBlock(id); - //computed value to hold the most recent data - const computedValue = useMemo(() => { - return computed(() => { - if (!data) { - return ""; - } - const v = getValueByPath(data, "option"); - if (typeof v === "undefined") { - return ""; - } else if (typeof v === "string") { - return v; - } - return JSON.stringify(v, null, 2); - }); - }, [data, "option"]).get(); - //custom context menu to show when user right clicks - const [contextMenu, setContextMenu] = useState<{ - mouseX: number; //x axis position for the click/brush event - mouseY: number; //y axis position for the click/brush event - value: unknown; //value can be of object or string or number type - } | null>(null); - const chartRef = useRef(null); - //table reference variable to align series name with fiscal axis - const tableRef = useRef(null); - const [seriesNameCol, setSeriesNameCol] = useState(70); + //computed value to hold the most recent data + const computedValue = useMemo(() => { + return computed(() => { + if (!data) { + return ""; + } + const v = getValueByPath(data, "option"); + if (typeof v === "undefined") { + return ""; + } else if (typeof v === "string") { + return v; + } + return JSON.stringify(v, null, 2); + }); + }, [data, "option"]).get(); + //custom context menu to show when user right clicks + const [contextMenu, setContextMenu] = useState<{ + mouseX: number; //x axis position for the click/brush event + mouseY: number; //y axis position for the click/brush event + value: unknown; //value can be of object or string or number type + } | null>(null); + const chartRef = useRef(null); + //table reference variable to align series name with fiscal axis + const tableRef = useRef(null); + const [seriesNameCol, setSeriesNameCol] = useState(70); - /** - * Builds a dynamic query string based on the provided input data. - * @param inputData - An array of tuples where each tuple contains a string and an object mapping field names to aggregation methods. - * @returns A query string that selects and groups by the specified fields with appropriate aggregations. - */ - const buildDynamicQuery = ( - inputData: [string, Record][], - ): string => { - const selectParts: string[] = []; - const aliasParts: string[] = []; - const groupByParts: string[] = []; + /** + * Builds a dynamic query string based on the provided input data. + * @param inputData - An array of tuples where each tuple contains a string and an object mapping field names to aggregation methods. + * @returns A query string that selects and groups by the specified fields with appropriate aggregations. + */ + const buildDynamicQuery = ( + inputData: [string, Record][], + ): string => { + const selectParts: string[] = []; + const aliasParts: string[] = []; + const groupByParts: string[] = []; - inputData.forEach(([_, fields]) => { - for (const field in fields) { - const rawAgg = fields[field]; - aliasParts.push(field); + inputData.forEach(([_, fields]) => { + for (const field in fields) { + const rawAgg = fields[field]; + aliasParts.push(field); - if (rawAgg) { - const cleanedAgg = rawAgg.split(" ").join(""); // Remove spaces (e.g., "Unique Count" → "UniqueCount") - selectParts.push(`${cleanedAgg}(${field})`); - } else { - selectParts.push(field); - groupByParts.push(field); // Only unaggregated fields are grouped - } - } - }); + if (rawAgg) { + const cleanedAgg = rawAgg.split(" ").join(""); // Remove spaces (e.g., "Unique Count" → "UniqueCount") + selectParts.push(`${cleanedAgg}(${field})`); + } else { + selectParts.push(field); + groupByParts.push(field); // Only unaggregated fields are grouped + } + } + }); - return `Select(${selectParts.join(", ")}).as([${aliasParts.join( - ", ", - )}]) | Group(${groupByParts.join(", ")})`; - }; - //selector to fetch data from the frame - const selector = buildDynamicQuery( - Object.entries(data?.aggregate ?? {}), - ); - //frame object to get the data from the frame - const frame = useFrame(data.frame?.name, { - selector: selector, - }); - // custom variable to hold the chart data to render - const dataOption = useMemo(() => { - let option = JSON.parse(computedValue); - let resourceRows = []; // Stores resource related details - let seriesData = []; // series data to be used for rendering chart - let yAxisName = ""; - const toolTipSelected = []; - let toolTipSelectedIndex = []; - const mileStoneIndex = ""; - let milestoneData = []; - //detect task progress column is selected or not - const taskProgressSelected = Object.keys( - option["customSettings"]["columnDetails"], - ).some((item) => item === "taskprogress"); - //default properties for milestone display - const mileStoneProperties = { - symbol: GANTT_CHART.MILESTONE_SYMBOL, - color: GANTT_CHART.MILESTONE_COLOR, - symbolSize: GANTT_CHART.MILESTONE_SYMBOL_SIZE, - }; - // symbol value, size, color based on the milestone selected - const symbolValue = []; - const symbolSize = []; - const symbolColor = []; - //show legend or not - let legendShow = false; - //show group view or not - let groupViewShow = false; - //column details selected in the data section - const columnIndexDetails = - option["customSettings"]["columnIndexDetails"]; - //frame data values - if (frame.data.values.length) { - frame.data.values.forEach((item, index) => { - const itemIndex = parseInt(columnIndexDetails["milestone"]); - const mileStoneDate = new Date( - item[itemIndex] as Date, - ).getTime(); + return `Select(${selectParts.join(", ")}).as([${aliasParts.join( + ", ", + )}]) | Group(${groupByParts.join(", ")})`; + }; + //selector to fetch data from the frame + const selector = buildDynamicQuery( + Object.entries(data?.aggregate ?? {}), + ); + //frame object to get the data from the frame + const frame = useFrame(data.frame?.name, { + selector: selector, + }); + // custom variable to hold the chart data to render + const dataOption = useMemo(() => { + let option = JSON.parse(computedValue); + let resourceRows = []; // Stores resource related details + let seriesData = []; // series data to be used for rendering chart + let yAxisName = ""; + const toolTipSelected = []; + let toolTipSelectedIndex = []; + const mileStoneIndex = ""; + let milestoneData = []; + //detect task progress column is selected or not + const taskProgressSelected = Object.keys( + option["customSettings"]["columnDetails"], + ).some((item) => item === "taskprogress"); + //default properties for milestone display + const mileStoneProperties = { + symbol: GANTT_CHART.MILESTONE_SYMBOL, + color: GANTT_CHART.MILESTONE_COLOR, + symbolSize: GANTT_CHART.MILESTONE_SYMBOL_SIZE, + }; + // symbol value, size, color based on the milestone selected + const symbolValue = []; + const symbolSize = []; + const symbolColor = []; + //show legend or not + let legendShow = false; + //show group view or not + let groupViewShow = false; + //column details selected in the data section + const columnIndexDetails = + option["customSettings"]["columnIndexDetails"]; + //frame data values + if (frame.data.values.length) { + frame.data.values.forEach((item, index) => { + const itemIndex = parseInt(columnIndexDetails["milestone"]); + const mileStoneDate = new Date( + item[itemIndex] as Date, + ).getTime(); - const ganttToolsLength = - option["customSettings"]?.["gantttools"]?.[ - "customizeSymbol" - ]?.length; - const ganttToolsSelected = - ganttToolsLength > -1 - ? option["customSettings"]?.["gantttools"]?.[ - "customizeSymbol" - ]?.[ganttToolsLength - 1] - : {}; + const ganttToolsLength = + option["customSettings"]?.["gantttools"]?.[ + "customizeSymbol" + ]?.length; + const ganttToolsSelected = + ganttToolsLength > -1 + ? option["customSettings"]?.["gantttools"]?.[ + "customizeSymbol" + ]?.[ganttToolsLength - 1] + : {}; - const ganttToolsDimensionValues = - ganttToolsSelected?.dimensionValues?.map( - (item, index) => new Date(item).getTime(), - ) || []; + const ganttToolsDimensionValues = + ganttToolsSelected?.dimensionValues?.map( + (item, index) => new Date(item).getTime(), + ) || []; - if ( - ganttToolsSelected?.dimensionSelected === "milestone" && - ganttToolsDimensionValues?.includes(mileStoneDate) - ) { - symbolValue.push(ganttToolsSelected.symbol); - symbolSize.push(ganttToolsSelected.symbolSize); - symbolColor.push(ganttToolsSelected.symbolColor); - } else { - symbolValue.push(mileStoneProperties.symbol); - symbolSize.push(mileStoneProperties.symbolSize); - symbolColor.push(mileStoneProperties.color); - } - }); - } - if (frame.data.values.length) { - // Step 1: Group tasks by resource - const groupedData = {}; - const dataGrouped = Object.keys( - option["customSettings"]["columnDetails"], - ).some((item) => item === "taskgroup"); - const taskGroupIndex = - option["customSettings"]["columnIndexDetails"][ - "taskgroup" - ] || -1; - const toolTipData = Object.keys( - option["customSettings"]["columnDetails"], - ).filter((item) => item === "tooltip"); - // toolTipData.forEach((item, index) => { - // option["customSettings"]["columnDetails"][item].forEach( - // (item) => { - // toolTipSelected.push(item.name); - // }, - // ); - // }); - legendShow = - option["customSettings"]?.["gantttools"]?.["showLegend"] || - false; - groupViewShow = - option["customSettings"]?.["gantttools"]?.[ - "showGroupView" - ] || false; - toolTipSelectedIndex = - option["customSettings"]["columnIndexDetails"]["tooltip"] || - []; + if ( + ganttToolsSelected?.dimensionSelected === "milestone" && + ganttToolsDimensionValues?.includes(mileStoneDate) + ) { + symbolValue.push(ganttToolsSelected.symbol); + symbolSize.push(ganttToolsSelected.symbolSize); + symbolColor.push(ganttToolsSelected.symbolColor); + } else { + symbolValue.push(mileStoneProperties.symbol); + symbolSize.push(mileStoneProperties.symbolSize); + symbolColor.push(mileStoneProperties.color); + } + }); + } + if (frame.data.values.length) { + // Step 1: Group tasks by resource + const groupedData = {}; + const dataGrouped = Object.keys( + option["customSettings"]["columnDetails"], + ).some((item) => item === "taskgroup"); + const taskGroupIndex = + option["customSettings"]["columnIndexDetails"][ + "taskgroup" + ] || -1; + const toolTipData = Object.keys( + option["customSettings"]["columnDetails"], + ).filter((item) => item === "tooltip"); + // toolTipData.forEach((item, index) => { + // option["customSettings"]["columnDetails"][item].forEach( + // (item) => { + // toolTipSelected.push(item.name); + // }, + // ); + // }); + legendShow = + option["customSettings"]?.["gantttools"]?.["showLegend"] || + false; + groupViewShow = + option["customSettings"]?.["gantttools"]?.[ + "showGroupView" + ] || false; + toolTipSelectedIndex = + option["customSettings"]["columnIndexDetails"]["tooltip"] || + []; - if (dataGrouped && groupViewShow) { - yAxisName = - taskGroupIndex > -1 - ? option["customSettings"]["columnDetails"][ - "taskgroup" - ]["name"] - : ""; - frame.data.values.forEach((d: string[], index) => { - if (!groupedData[d[taskGroupIndex]]) - groupedData[d[taskGroupIndex]] = []; - groupedData[d[taskGroupIndex]].push(d); - }); + if (dataGrouped && groupViewShow) { + yAxisName = + taskGroupIndex > -1 + ? option["customSettings"]["columnDetails"][ + "taskgroup" + ]["name"] + : ""; + frame.data.values.forEach((d: string[], index) => { + if (!groupedData[d[taskGroupIndex]]) + groupedData[d[taskGroupIndex]] = []; + groupedData[d[taskGroupIndex]].push(d); + }); - Object.keys(groupedData).forEach((resource) => { - const tasks = groupedData[resource]; - tasks.sort( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (a: any, b: any) => - new Date(a[1]).getTime() - - new Date(b[1]).getTime(), - ); // Sort by start date + Object.keys(groupedData).forEach((resource) => { + const tasks = groupedData[resource]; + tasks.sort( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (a: any, b: any) => + new Date(a[1]).getTime() - + new Date(b[1]).getTime(), + ); // Sort by start date - const rowIndexes = []; // Tracks task end times per row - resourceRows.push(resource); // First row for the resource + const rowIndexes = []; // Tracks task end times per row + resourceRows.push(resource); // First row for the resource - tasks.forEach((task) => { - const taskStart = new Date(task[1]).getTime(); - const taskEnd = new Date(task[2]).getTime(); - // Find an available row (avoid overlap) - let rowIndex = rowIndexes.findIndex( - (endTime) => taskStart >= endTime, - ); - if (rowIndex === -1) { - rowIndex = rowIndexes.length; - resourceRows.push(""); // Add an empty row for stacking - } - rowIndexes[rowIndex] = taskEnd; // Update row availability - // Push formatted task data - seriesData.push({ - name: task[0], - resource: resource, - taskprogress: - task[columnIndexDetails["taskprogress"]], - value: [ - taskStart, - resourceRows.length - 1, - taskEnd, - ...toolTipSelectedIndex.map( - (item) => task[item], - ), - ], - }); - }); - }); - } else { - yAxisName = - option["customSettings"]["columnDetails"]["task"][ - "name" - ]; - // Convert data to proper format - seriesData = frame.data.values.map( - (d: string[], index) => ({ - name: d[columnIndexDetails["task"]], - taskprogress: d[columnIndexDetails["taskprogress"]], - value: [ - new Date( - d[columnIndexDetails["startdate"]], - ).getTime(), - index, - new Date( - d[columnIndexDetails["enddate"]], - ).getTime(), - ...toolTipSelectedIndex.map((item) => d[item]), - ], - }), - ); - resourceRows = frame.data.values.map((d, index) => d[0]); - } - if ( - columnIndexDetails.hasOwnProperty("milestone") && - columnIndexDetails["milestone"] - ) { - const gantttools = option["customSettings"]["gantttools"]; - milestoneData = frame.data.values.map( - (d: string[], index) => { - const mileStoneSymbol = mileStoneProperties.symbol; - const symbolSize = mileStoneProperties.symbolSize; - const mileStoneDate = new Date( - d[columnIndexDetails["milestone"]], - ).getTime(); - const endDate = new Date( - d[columnIndexDetails["enddate"]], - ).getTime(); - return { - name: `MileStone ${index + 1}`, - value: [ - mileStoneDate, - d[columnIndexDetails["task"]], - endDate, - ], - mileStoneOriginalDate: - d[columnIndexDetails["milestone"]], - symbol: symbolValue[index], - symbolSize: symbolSize[index], - itemStyle: { - color: symbolColor[index], - }, - }; - }, - ); - } - } + tasks.forEach((task) => { + const taskStart = new Date(task[1]).getTime(); + const taskEnd = new Date(task[2]).getTime(); + // Find an available row (avoid overlap) + let rowIndex = rowIndexes.findIndex( + (endTime) => taskStart >= endTime, + ); + if (rowIndex === -1) { + rowIndex = rowIndexes.length; + resourceRows.push(""); // Add an empty row for stacking + } + rowIndexes[rowIndex] = taskEnd; // Update row availability + // Push formatted task data + seriesData.push({ + name: task[0], + resource: resource, + taskprogress: + task[columnIndexDetails["taskprogress"]], + value: [ + taskStart, + resourceRows.length - 1, + taskEnd, + ...toolTipSelectedIndex.map( + (item) => task[item], + ), + ], + }); + }); + }); + } else { + yAxisName = + option["customSettings"]["columnDetails"]["task"][ + "name" + ]; + // Convert data to proper format + seriesData = frame.data.values.map( + (d: string[], index) => ({ + name: d[columnIndexDetails["task"]], + taskprogress: d[columnIndexDetails["taskprogress"]], + value: [ + new Date( + d[columnIndexDetails["startdate"]], + ).getTime(), + index, + new Date( + d[columnIndexDetails["enddate"]], + ).getTime(), + ...toolTipSelectedIndex.map((item) => d[item]), + ], + }), + ); + resourceRows = frame.data.values.map((d, index) => d[0]); + } + if ( + Object.hasOwn(columnIndexDetails, "milestone") && + columnIndexDetails["milestone"] + ) { + const gantttools = option["customSettings"]["gantttools"]; + milestoneData = frame.data.values.map( + (d: string[], index) => { + const mileStoneSymbol = mileStoneProperties.symbol; + const symbolSize = mileStoneProperties.symbolSize; + const mileStoneDate = new Date( + d[columnIndexDetails["milestone"]], + ).getTime(); + const endDate = new Date( + d[columnIndexDetails["enddate"]], + ).getTime(); + return { + name: `MileStone ${index + 1}`, + value: [ + mileStoneDate, + d[columnIndexDetails["task"]], + endDate, + ], + mileStoneOriginalDate: + d[columnIndexDetails["milestone"]], + symbol: symbolValue[index], + symbolSize: symbolSize[index], + itemStyle: { + color: symbolColor[index], + }, + }; + }, + ); + } + } - let lineData = []; - const showDisplayValueLabels = - option["customSettings"]?.["gantttools"]?.[ - "showDisplayValueLabels" - ] || false; - const mainSeriesName = - option["customSettings"]?.["columnDetails"]?.["task"]?.["name"]; - const mainSeriesFrameName = - option["customSettings"]?.["columnDetails"]?.["task"]?.[ - "selector" - ]; - if ( - option["series"].some( - (series) => series.name === "targetDateSegment", - ) - ) { - const targetDateSegment = option["series"].filter( - (item) => item.name === "targetDateSegment", - ); - targetDateSegment[0] = { - ...targetDateSegment[0], - targetDateSegment: true, - // name: targetDateSegment[0]?.["data"]?.length - // ? "Target Data Segment" - // : "", - renderItem: (params, api) => { - const x = api.coord([api.value(0), 0])[0]; - const targetText = - option["customSettings"]?.["gantttools"]?.[ - "targetLineName" - ] || ""; - const targetColor = - option["customSettings"]?.["gantttools"]?.[ - "targetLineColor" - ] || "#FF0000"; - // Convert date to x-axis position - const height = params.coordSys.height; // Full chart height return - const yBottom = - params.coordSys.y + params.coordSys.height; - const yTop = params.coordSys.y; - //if targetdate is not empty then show the target date line - if ( - option["customSettings"]?.["gantttools"]?.[ - "targetDate" - ] != "" - ) { - return { - type: "group", - children: [ - { - type: "line", - originX: 0, - originY: 0, - shape: { - x1: x, - y1: yBottom, - x2: x, - y2: yTop, - }, - style: { - stroke: targetColor, // Line color - lineWidth: 2, // Line thickness - type: "dashed", // Line style - }, - }, - { - type: "text", - style: { - x: x, - y: yTop - 10, - text: targetText, - textAlign: "center", - textVerticalAlign: "bottom", - }, - }, - ], - }; - } - return {}; - }, - }; - //line data setting if target date is not empty - if ( - option["customSettings"]?.["gantttools"]?.["targetDate"] != - "" - ) { - lineData = targetDateSegment; - } else { - lineData = []; - } - } - //final data option to set to chart - option = { - ...option, - tooltip: { - trigger: "item", - // eslint-disable-next-line @typescript-eslint/no-explicit-any - formatter: (params: any) => - chartFormatter( - params, - toolTipSelectedIndex, - frame.data.headers, - frame.data.values, - ), - }, - xAxis: { - type: "time", - // name: 'Date', - axisLabel: { - formatter: (value) => - new Date(value).toLocaleDateString(), - }, - splitLine: { show: true }, - axisLine: { - show: true, - }, - axisTick: { - show: true, - }, - }, - yAxis: { - type: "category", - data: resourceRows, - inverse: true, - }, - legend: { - show: legendShow, - }, - series: [ - ...lineData, - { - type: "custom", - chartrendered: true, - name: mainSeriesName, - frameName: mainSeriesFrameName, - renderItem: function (params, api) { - const categoryIndex = api.value(1); - const start = api.coord([ - api.value(0), - categoryIndex, - ]); - const end = api.coord([ - api.value(2), - categoryIndex, - ]); - const height = api.size([0, 1])[1] * 0.6; - const tooltipName = seriesData[params.dataIndex] - .name - ? seriesData[params.dataIndex].name - : ""; - if (taskProgressSelected) { - const partialWidth = seriesData[ - params.dataIndex - ].taskprogress - ? (end[0] - start[0]) * - (seriesData[params.dataIndex] - .taskprogress / - 100) - : end[0] - start[0]; + let lineData = []; + const showDisplayValueLabels = + option["customSettings"]?.["gantttools"]?.[ + "showDisplayValueLabels" + ] || false; + const mainSeriesName = + option["customSettings"]?.["columnDetails"]?.["task"]?.["name"]; + const mainSeriesFrameName = + option["customSettings"]?.["columnDetails"]?.["task"]?.[ + "selector" + ]; + if ( + option["series"].some( + (series) => series.name === "targetDateSegment", + ) + ) { + const targetDateSegment = option["series"].filter( + (item) => item.name === "targetDateSegment", + ); + targetDateSegment[0] = { + ...targetDateSegment[0], + targetDateSegment: true, + // name: targetDateSegment[0]?.["data"]?.length + // ? "Target Data Segment" + // : "", + renderItem: (params, api) => { + const x = api.coord([api.value(0), 0])[0]; + const targetText = + option["customSettings"]?.["gantttools"]?.[ + "targetLineName" + ] || ""; + const targetColor = + option["customSettings"]?.["gantttools"]?.[ + "targetLineColor" + ] || "#FF0000"; + // Convert date to x-axis position + const height = params.coordSys.height; // Full chart height return + const yBottom = + params.coordSys.y + params.coordSys.height; + const yTop = params.coordSys.y; + //if targetdate is not empty then show the target date line + if ( + option["customSettings"]?.["gantttools"]?.[ + "targetDate" + ] != "" + ) { + return { + type: "group", + children: [ + { + type: "line", + originX: 0, + originY: 0, + shape: { + x1: x, + y1: yBottom, + x2: x, + y2: yTop, + }, + style: { + stroke: targetColor, // Line color + lineWidth: 2, // Line thickness + type: "dashed", // Line style + }, + }, + { + type: "text", + style: { + x: x, + y: yTop - 10, + text: targetText, + textAlign: "center", + textVerticalAlign: "bottom", + }, + }, + ], + }; + } + return {}; + }, + }; + //line data setting if target date is not empty + if ( + option["customSettings"]?.["gantttools"]?.["targetDate"] != + "" + ) { + lineData = targetDateSegment; + } else { + lineData = []; + } + } + //final data option to set to chart + option = { + ...option, + tooltip: { + trigger: "item", + // eslint-disable-next-line @typescript-eslint/no-explicit-any + formatter: (params: any) => + chartFormatter( + params, + toolTipSelectedIndex, + frame.data.headers, + frame.data.values, + ), + }, + xAxis: { + type: "time", + // name: 'Date', + axisLabel: { + formatter: (value) => + new Date(value).toLocaleDateString(), + }, + splitLine: { show: true }, + axisLine: { + show: true, + }, + axisTick: { + show: true, + }, + }, + yAxis: { + type: "category", + data: resourceRows, + inverse: true, + }, + legend: { + show: legendShow, + }, + series: [ + ...lineData, + { + type: "custom", + chartrendered: true, + name: mainSeriesName, + frameName: mainSeriesFrameName, + renderItem: (params, api) => { + const categoryIndex = api.value(1); + const start = api.coord([ + api.value(0), + categoryIndex, + ]); + const end = api.coord([ + api.value(2), + categoryIndex, + ]); + const height = api.size([0, 1])[1] * 0.6; + const tooltipName = seriesData[params.dataIndex] + .name + ? seriesData[params.dataIndex].name + : ""; + if (taskProgressSelected) { + const partialWidth = seriesData[ + params.dataIndex + ].taskprogress + ? (end[0] - start[0]) * + (seriesData[params.dataIndex] + .taskprogress / + 100) + : end[0] - start[0]; - return { - type: "group", - children: [ - { - type: "rect", - shape: { - x: start[0], - y: start[1] - height / 2, - width: end[0] - start[0], - height: height, - }, - style: { - fill: "lightgrey", - stroke: "#333", - }, - }, - { - type: "rect", - shape: { - x: start[0], - y: start[1] - height / 2, - width: partialWidth, - height: height, - }, - style: { - fill: "#6495ED", - stroke: "#333", - }, - }, - { - type: "text", - style: { - text: tooltipName, - x: start[0], - y: start[1] - height / 2, - textVerticalAlign: "middle", - textAlign: "center", - fontSize: 15, - opacity: showDisplayValueLabels - ? 1 - : 0, - }, - }, - ], - }; - } - return { - type: "group", - children: [ - { - type: "rect", - chartrendered: true, - shape: { - x: start[0], - y: start[1] - height / 2, - width: end[0] - start[0], - height: height, - }, - style: { - fill: "#6495ED", - stroke: "#333", - }, - }, - { - type: "text", - style: { - text: tooltipName, - x: start[0], - y: start[1] - height / 2, - textVerticalAlign: "middle", - textAlign: "center", - fontSize: 15, - opacity: showDisplayValueLabels - ? 1 - : 0, - }, - }, - ], - }; - }, - encode: { x: [0, 2], y: 1 }, - data: seriesData, - }, - { - type: "scatter", - name: milestoneData.length ? "Milestones" : "", - milestonerendered: true, - label: { - show: showDisplayValueLabels ? true : false, - position: "top", - formatter: "{b}", - }, - data: milestoneData, - }, - ], - }; - return option; - }, [frame.data.values, data.columns, computedValue]); - //get quarter and month list with fiscal year details - function getQuarterAndMonthList(startFiscalMonth) { - const startMonth = startFiscalMonth; - const month = [ - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", - ]; - const startIndex = month.indexOf(startMonth); - let startIndexTemp = startIndex; - const quarterObject = {}; - //create quarter object - [1, 2, 3, 4].forEach((item) => { - quarterObject["Q" + item] = []; - const countsPerQuarter = 3; - for (let i = 0; i < countsPerQuarter; i++) { - if (startIndexTemp == month.length) { - startIndexTemp = month.length % 12; - } - quarterObject["Q" + item][i] = month[startIndexTemp]; - startIndexTemp++; - } - }); - //month based on quarter from Jan to Dec based on fiscal year start - let monthBasedQuarter = []; - let lastMonthInQuarter = ""; - month.forEach((item, index) => { - let monthExistsInQuarter = ""; - for (let i = 0; i < 4; i++) { - if ( - quarterObject["Q" + (i + 1)].some( - (qoItem) => item === qoItem, - ) - ) { - monthExistsInQuarter = "Q" + (i + 1); - } - } - const quarterExistsInArray = monthBasedQuarter - .reverse() - .findIndex( - (mbitem, mbindex) => - monthExistsInQuarter === mbitem.name, - ); - if ( - quarterExistsInArray >= 0 && - lastMonthInQuarter == monthExistsInQuarter - ) { - monthBasedQuarter[quarterExistsInArray]["month"] = [ - ...monthBasedQuarter[quarterExistsInArray]["month"], - item, - ]; - } else { - monthBasedQuarter = [ - ...monthBasedQuarter, - { - name: monthExistsInQuarter, - month: [item], - order: monthBasedQuarter.length + 1, - }, - ]; - } - lastMonthInQuarter = monthExistsInQuarter; - }); - //set initial fiscal year based on current month selection, if month data is not available, then first record of seriesdata is selected - const FYYear = - parseInt( - dataOption["customSettings"]?.["gantttools"]?.[ - "fiscalYearValue" - ]?.substring(2), - ) + 1; - monthBasedQuarter = monthBasedQuarter.map((item, index) => { - return { - ...item, - ["colSpan"]: item.month.length, - }; - }); - //sorting records based on date - monthBasedQuarter = monthBasedQuarter.sort( - (item, item1) => item.order - item1.order, - ); - const monthSelected = - dataOption["customSettings"]?.["gantttools"]?.[ - "fiscalYearStart" - ]; - const yearQuarterIndex = monthBasedQuarter.findIndex((item) => - item.month.includes(monthSelected), - ); - monthBasedQuarter = monthBasedQuarter.map((item, index) => { - return { - ...item, - ["fiscalYear"]: isNaN(FYYear) - ? "" - : index < yearQuarterIndex - ? "FY" + (FYYear - 1) - : "FY" + FYYear, - }; - }); - return monthBasedQuarter; - } - //enable or disable fiscal axis - const enableFiscalAxis = - dataOption["customSettings"]?.["gantttools"]?.[ - "enableFiscalAxis" - ] || false; - //update chart data when frame values are changed - useEffect(() => { - if (!frame.isLoading && frame.data.values.length > 0) { - updateChart(dataOption, "option"); - } - }, [frame.data.values]); - //update chart data when data is updated - useEffect(() => { - const echartsInstance = chartRef.current?.getEchartsInstance(); - if (echartsInstance) { - echartsInstance.setOption(dataOption, { notMerge: true }); - } - }, [dataOption]); - //update height series name section based on table height - useEffect(() => { - const table = tableRef.current; + return { + type: "group", + children: [ + { + type: "rect", + shape: { + x: start[0], + y: start[1] - height / 2, + width: end[0] - start[0], + height: height, + }, + style: { + fill: "lightgrey", + stroke: "#333", + }, + }, + { + type: "rect", + shape: { + x: start[0], + y: start[1] - height / 2, + width: partialWidth, + height: height, + }, + style: { + fill: "#6495ED", + stroke: "#333", + }, + }, + { + type: "text", + style: { + text: tooltipName, + x: start[0], + y: start[1] - height / 2, + textVerticalAlign: "middle", + textAlign: "center", + fontSize: 15, + opacity: showDisplayValueLabels + ? 1 + : 0, + }, + }, + ], + }; + } + return { + type: "group", + children: [ + { + type: "rect", + chartrendered: true, + shape: { + x: start[0], + y: start[1] - height / 2, + width: end[0] - start[0], + height: height, + }, + style: { + fill: "#6495ED", + stroke: "#333", + }, + }, + { + type: "text", + style: { + text: tooltipName, + x: start[0], + y: start[1] - height / 2, + textVerticalAlign: "middle", + textAlign: "center", + fontSize: 15, + opacity: showDisplayValueLabels + ? 1 + : 0, + }, + }, + ], + }; + }, + encode: { x: [0, 2], y: 1 }, + data: seriesData, + }, + { + type: "scatter", + name: milestoneData.length ? "Milestones" : "", + milestonerendered: true, + label: { + show: showDisplayValueLabels ? true : false, + position: "top", + formatter: "{b}", + }, + data: milestoneData, + }, + ], + }; + return option; + }, [frame.data.values, data.columns, computedValue]); + //get quarter and month list with fiscal year details + function getQuarterAndMonthList(startFiscalMonth) { + const startMonth = startFiscalMonth; + const month = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + ]; + const startIndex = month.indexOf(startMonth); + let startIndexTemp = startIndex; + const quarterObject = {}; + //create quarter object + [1, 2, 3, 4].forEach((item) => { + quarterObject["Q" + item] = []; + const countsPerQuarter = 3; + for (let i = 0; i < countsPerQuarter; i++) { + if (startIndexTemp == month.length) { + startIndexTemp = month.length % 12; + } + quarterObject["Q" + item][i] = month[startIndexTemp]; + startIndexTemp++; + } + }); + //month based on quarter from Jan to Dec based on fiscal year start + let monthBasedQuarter = []; + let lastMonthInQuarter = ""; + month.forEach((item, index) => { + let monthExistsInQuarter = ""; + for (let i = 0; i < 4; i++) { + if ( + quarterObject["Q" + (i + 1)].some( + (qoItem) => item === qoItem, + ) + ) { + monthExistsInQuarter = "Q" + (i + 1); + } + } + const quarterExistsInArray = monthBasedQuarter + .reverse() + .findIndex( + (mbitem, mbindex) => + monthExistsInQuarter === mbitem.name, + ); + if ( + quarterExistsInArray >= 0 && + lastMonthInQuarter == monthExistsInQuarter + ) { + monthBasedQuarter[quarterExistsInArray]["month"] = [ + ...monthBasedQuarter[quarterExistsInArray]["month"], + item, + ]; + } else { + monthBasedQuarter = [ + ...monthBasedQuarter, + { + name: monthExistsInQuarter, + month: [item], + order: monthBasedQuarter.length + 1, + }, + ]; + } + lastMonthInQuarter = monthExistsInQuarter; + }); + //set initial fiscal year based on current month selection, if month data is not available, then first record of seriesdata is selected + const FYYear = + parseInt( + dataOption["customSettings"]?.["gantttools"]?.[ + "fiscalYearValue" + ]?.substring(2), + ) + 1; + monthBasedQuarter = monthBasedQuarter.map((item, index) => { + return { + ...item, + ["colSpan"]: item.month.length, + }; + }); + //sorting records based on date + monthBasedQuarter = monthBasedQuarter.sort( + (item, item1) => item.order - item1.order, + ); + const monthSelected = + dataOption["customSettings"]?.["gantttools"]?.[ + "fiscalYearStart" + ]; + const yearQuarterIndex = monthBasedQuarter.findIndex((item) => + item.month.includes(monthSelected), + ); + monthBasedQuarter = monthBasedQuarter.map((item, index) => { + return { + ...item, + ["fiscalYear"]: isNaN(FYYear) + ? "" + : index < yearQuarterIndex + ? "FY" + (FYYear - 1) + : "FY" + FYYear, + }; + }); + return monthBasedQuarter; + } + //enable or disable fiscal axis + const enableFiscalAxis = + dataOption["customSettings"]?.["gantttools"]?.[ + "enableFiscalAxis" + ] || false; + //update chart data when frame values are changed + useEffect(() => { + if (!frame.isLoading && frame.data.values.length > 0) { + updateChart(dataOption, "option"); + } + }, [frame.data.values]); + //update chart data when data is updated + useEffect(() => { + const echartsInstance = chartRef.current?.getEchartsInstance(); + if (echartsInstance) { + echartsInstance.setOption(dataOption, { notMerge: true }); + } + }, [dataOption]); + //update height series name section based on table height + useEffect(() => { + const table = tableRef.current; - if (!table) return; + if (!table) return; - // Create a ResizeObserver instance - const resizeObserver = new ResizeObserver((entries) => { - for (const entry of entries) { - const { height } = entry.contentRect; - setSeriesNameCol(height); - } - }); + // Create a ResizeObserver instance + const resizeObserver = new ResizeObserver((entries) => { + for (const entry of entries) { + const { height } = entry.contentRect; + setSeriesNameCol(height); + } + }); - // Observe the table element - resizeObserver.observe(table); + // Observe the table element + resizeObserver.observe(table); - // Clean up the observer on unmount - return () => { - resizeObserver.disconnect(); - }; - }, [enableFiscalAxis]); - //tooltip function to render tooltip based on options provided - function chartFormatter( - params, - tooltipData, - frameHeaders, - frameValues, - ) { - let chartToolTip = `${params.name}
+ // Clean up the observer on unmount + return () => { + resizeObserver.disconnect(); + }; + }, [enableFiscalAxis]); + //tooltip function to render tooltip based on options provided + function chartFormatter( + params, + tooltipData, + frameHeaders, + frameValues, + ) { + let chartToolTip = `${params.name}
Start: ${new Date(params.value[0]).toLocaleDateString()}
End: ${new Date(params.value[2]).toLocaleDateString()}
`; - tooltipData.forEach((item, index) => { - chartToolTip += `${frameHeaders[item]}: ${ - frameValues[params.dataIndex][item] - }
`; - }); - return chartToolTip; - } - //fiscal start month - const fiscalStartMonth = - dataOption["customSettings"]?.["gantttools"]?.["fiscalYearStart"] || - "Jan"; - //fiscal axis background color - const fiscalAxisBackgroundColor = - dataOption["customSettings"]?.["gantttools"]?.[ - "fiscalAxisBackgroundColor" - ] || "#0471f0"; - //getquarter and month list with fiscal year - const quarterAndMonth = getQuarterAndMonthList(fiscalStartMonth); - //get the series name for chart side heading - const seriesName = - dataOption["customSettings"]?.["columnDetails"]?.["task"]?.name || - ""; - const onClickChart = { - //when contextmenu event is raised, default context menu made hidden, and custom component is shown - contextmenu: (params) => { - if (params.data) { - const taskColumn = params.data.name; - const parsedJson = JSON.parse(computedValue); - const taskName = - parsedJson["series"][params.seriesIndex]["frameName"]; - setContextMenu( - contextMenu === null - ? { - mouseX: params.event.event.clientX, - mouseY: params.event.event.clientY, - value: { - label: taskName, - value: taskColumn, - }, - } - : // repeated contextmenu when it is already open closes it with Chrome 84 on Ubuntu - // Other native context menus might behave different. - // With this behavior we prevent contextmenu from the backdrop to re-locale existing context menus. - null, - ); - params.event.event.preventDefault(); - } else { - params.event.event.preventDefault(); - } - }, - }; - return ( - <> - - {enableFiscalAxis && ( - - - {seriesName} - - (tableRef.current = e)} - > - - - {quarterAndMonth.length && - quarterAndMonth.map((item, i) => ( - - {item.name}{" "} - {item.hasOwnProperty( - "fiscalYear", - ) && - item["fiscalYear"] != "" - ? `(${item["fiscalYear"]})` - : ""} - - ))} - - - - - {quarterAndMonth.length && - quarterAndMonth.map((item, i) => - item["month"].map( - (monthItem) => ( - - {monthItem} - - ), - ), - )} - - - - - )} + tooltipData.forEach((item, index) => { + chartToolTip += `${frameHeaders[item]}: ${ + frameValues[params.dataIndex][item] + }
`; + }); + return chartToolTip; + } + //fiscal start month + const fiscalStartMonth = + dataOption["customSettings"]?.["gantttools"]?.["fiscalYearStart"] || + "Jan"; + //fiscal axis background color + const fiscalAxisBackgroundColor = + dataOption["customSettings"]?.["gantttools"]?.[ + "fiscalAxisBackgroundColor" + ] || "#0471f0"; + //getquarter and month list with fiscal year + const quarterAndMonth = getQuarterAndMonthList(fiscalStartMonth); + //get the series name for chart side heading + const seriesName = + dataOption["customSettings"]?.["columnDetails"]?.["task"]?.name || + ""; + const onClickChart = { + //when contextmenu event is raised, default context menu made hidden, and custom component is shown + contextmenu: (params) => { + if (params.data) { + const taskColumn = params.data.name; + const parsedJson = JSON.parse(computedValue); + const taskName = + parsedJson["series"][params.seriesIndex]["frameName"]; + setContextMenu( + contextMenu === null + ? { + mouseX: params.event.event.clientX, + mouseY: params.event.event.clientY, + value: { + label: taskName, + value: taskColumn, + }, + } + : // repeated contextmenu when it is already open closes it with Chrome 84 on Ubuntu + // Other native context menus might behave different. + // With this behavior we prevent contextmenu from the backdrop to re-locale existing context menus. + null, + ); + params.event.event.preventDefault(); + } else { + params.event.event.preventDefault(); + } + }, + }; + return ( + <> + + {enableFiscalAxis && ( + + + {seriesName} + + (tableRef.current = e)} + > + + + {quarterAndMonth.length && + quarterAndMonth.map((item, i) => ( + + {item.name}{" "} + {Object.hasOwn( + item, + "fiscalYear", + ) && + item["fiscalYear"] != "" + ? `(${item["fiscalYear"]})` + : ""} + + ))} + + + + + {quarterAndMonth.length && + quarterAndMonth.map((item, i) => + item["month"].map( + (monthItem) => ( + + {monthItem} + + ), + ), + )} + + + + + )} - (chartRef.current = e)} - style={{ - width: "inherit", - height: enableFiscalAxis ? "75%" : "100%", - maxHeight: enableFiscalAxis ? "75%" : "100%", - }} - /> - setContextMenu(null)} - /> - - - ); - }, + (chartRef.current = e)} + style={{ + width: "inherit", + height: enableFiscalAxis ? "75%" : "100%", + maxHeight: enableFiscalAxis ? "75%" : "100%", + }} + /> + setContextMenu(null)} + /> +
+ + ); + }, ); diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/bar-chart/Bar.tsx b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/bar-chart/Bar.tsx index ca1dfadeb1..e5ae2f260d 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/bar-chart/Bar.tsx +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/bar-chart/Bar.tsx @@ -1,304 +1,304 @@ -import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import type { EChartsOption } from "echarts"; +import EChartsReact from "echarts-for-react"; import { computed } from "mobx"; import { observer } from "mobx-react-lite"; -import EChartsReact from "echarts-for-react"; -import { EChartsOption } from "echarts"; - +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { styled } from "@semoss/ui"; - import { useBlock, useFrame } from "../../../../../hooks"; import { getValueByPath } from "../../../../../utility"; -import { EchartVisualizationBlockDef } from "../../VisualizationBlock"; - +import type { EchartVisualizationBlockDef } from "../../VisualizationBlock"; import { ChartContextMenu } from "./ChartContextMenu"; //Main Container for displaying Bar chart const StyledMainContainer = styled("div")(({ theme }) => ({ - height: "100%", - width: "100%", + height: "100%", + width: "100%", })); //container for displaying invalid or no data const StyledNoDataContainer = styled("div", { - shouldForwardProp: (prop) => prop !== "error", + shouldForwardProp: (prop) => prop !== "error", })<{ error?: boolean }>(({ error = false, theme }) => ({ - height: "inherit", - width: "inherit", - maxHeight: "30vh", - maxWidth: "80vh", - display: "flex", - flexWrap: "wrap", - alignContent: "flex-start", - color: error ? theme.palette.error.main : "unset", + height: "inherit", + width: "inherit", + maxHeight: "30vh", + maxWidth: "80vh", + display: "flex", + flexWrap: "wrap", + alignContent: "flex-start", + color: error ? theme.palette.error.main : "unset", })); //echart field structure export interface EChartColumns { - name: string; - selector: string; - width: string; + name: string; + selector: string; + width: string; } //bar component properties interface BarProps { - id: string; - updateJson: (data: any, path: any) => void; + id: string; + updateJson: (data: any, path: any) => void; } export const Bar = observer(({ id, updateJson }: BarProps) => { - const { data } = useBlock(id); + const { data } = useBlock(id); - const [contextMenu, setContextMenu] = useState<{ - mouseX: number; //x axis position for the click/brush event - mouseY: number; //y axis position for the click/brush event - value: unknown; //value can be of object or string or number type - } | null>(null); - let resultData: unknown = {}; + const [contextMenu, setContextMenu] = useState<{ + mouseX: number; //x axis position for the click/brush event + mouseY: number; //y axis position for the click/brush event + value: unknown; //value can be of object or string or number type + } | null>(null); + let resultData: unknown = {}; - /** - * Builds a dynamic query string based on the provided input data. - * @param inputData - An array of tuples where each tuple contains a string and an object mapping field names to aggregation methods. - * @returns A query string that selects and groups by the specified fields with appropriate aggregations. - */ - const buildDynamicQuery = ( - inputData: [string, Record][], - ): string => { - const selectParts: string[] = []; - const aliasParts: string[] = []; - const groupByParts: string[] = []; + /** + * Builds a dynamic query string based on the provided input data. + * @param inputData - An array of tuples where each tuple contains a string and an object mapping field names to aggregation methods. + * @returns A query string that selects and groups by the specified fields with appropriate aggregations. + */ + const buildDynamicQuery = ( + inputData: [string, Record][], + ): string => { + const selectParts: string[] = []; + const aliasParts: string[] = []; + const groupByParts: string[] = []; - inputData.forEach(([_, fields]) => { - for (const field in fields) { - const rawAgg = fields[field]; - aliasParts.push(field); + inputData.forEach(([_, fields]) => { + for (const field in fields) { + const rawAgg = fields[field]; + aliasParts.push(field); - if (rawAgg) { - const cleanedAgg = rawAgg.split(" ").join(""); // Remove spaces (e.g., "Unique Count" → "UniqueCount") - selectParts.push(`${cleanedAgg}(${field})`); - } else { - selectParts.push(field); - groupByParts.push(field); // Only unaggregated fields are grouped - } - } - }); + if (rawAgg) { + const cleanedAgg = rawAgg.split(" ").join(""); // Remove spaces (e.g., "Unique Count" → "UniqueCount") + selectParts.push(`${cleanedAgg}(${field})`); + } else { + selectParts.push(field); + groupByParts.push(field); // Only unaggregated fields are grouped + } + } + }); - return `Select(${selectParts.join(", ")}).as([${aliasParts.join( - ", ", - )}]) | Group(${groupByParts.join(", ")})`; - }; + return `Select(${selectParts.join(", ")}).as([${aliasParts.join( + ", ", + )}]) | Group(${groupByParts.join(", ")})`; + }; - const selector = buildDynamicQuery(Object.entries(data?.aggregate ?? {})); - //frame object - const frameData = useFrame(data.frame.name, { - selector: selector, - }); - const chartOperationData = useRef({ - brushSelected: [], - contextMenu: null, - yAxisColumn: { name: "", selector: "", width: undefined }, - chartInstance: { setOption: null }, - }); + const selector = buildDynamicQuery(Object.entries(data?.aggregate ?? {})); + //frame object + const frameData = useFrame(data.frame.name, { + selector: selector, + }); + const chartOperationData = useRef({ + brushSelected: [], + contextMenu: null, + yAxisColumn: { name: "", selector: "", width: undefined }, + chartInstance: { setOption: null }, + }); - const computedValue = useMemo(() => { - return computed(() => { - if (!data) { - return ""; - } - const v = getValueByPath(data, "option"); - if (typeof v === "undefined") { - return ""; - } else if (typeof v === "string") { - return v; - } - return JSON.stringify(v, null, 2); - }); - }, [data, "option"]).get(); + const computedValue = useMemo(() => { + return computed(() => { + if (!data) { + return ""; + } + const v = getValueByPath(data, "option"); + if (typeof v === "undefined") { + return ""; + } else if (typeof v === "string") { + return v; + } + return JSON.stringify(v, null, 2); + }); + }, [data, "option"]).get(); - const parsedOption = useMemo(() => { - return typeof computedValue === "string" - ? JSON.parse(computedValue) - : computedValue; - }, [computedValue]); + const parsedOption = useMemo(() => { + return typeof computedValue === "string" + ? JSON.parse(computedValue) + : computedValue; + }, [computedValue]); - useEffect(() => { - const toolsUpdated = - parsedOption.hasOwnProperty("customSettings") && - parsedOption["customSettings"].hasOwnProperty("toolsUpdated") - ? parsedOption["customSettings"]["toolsUpdated"] - : false; - if ( - data.frame.name && - frameData.data.values.length > 0 && - frameData.isLoading === false && - !toolsUpdated - ) { - updateJson(resultData, "option"); - } - }, [frameData.data.values]); + useEffect(() => { + const toolsUpdated = + Object.hasOwn(parsedOption, "customSettings") && + Object.hasOwn(parsedOption["customSettings"], "toolsUpdated") + ? parsedOption["customSettings"]["toolsUpdated"] + : false; + if ( + data.frame.name && + frameData.data.values.length > 0 && + frameData.isLoading === false && + !toolsUpdated + ) { + updateJson(resultData, "option"); + } + }, [frameData.data.values]); - //update frame values to the series data when frame values are changed - const receiveValueswithCorrections = useCallback( - (resultData: unknown) => { - let frameDataIndex = 0; - //setting xaxis data - resultData["xAxis"]["data"] = frameData.data?.values?.map( - (item, index) => { - return { value: item[frameDataIndex] }; - }, - ); - const optionSeriesLength = frameData.data.headers.length; - frameDataIndex++; - //setting all values to all existing series to null, to restore the chart to initial state so new values will be updated - for ( - let seriesIdx = 0; - seriesIdx < resultData["series"].length; - seriesIdx++ - ) { - if ( - resultData["series"][seriesIdx] !== undefined && - resultData["series"][seriesIdx].hasOwnProperty("data") && - !resultData["series"][seriesIdx].hasOwnProperty( - "toggleTrendLineObject", - ) - ) { - resultData["series"][seriesIdx]["data"] = - frameData.data?.values?.map((item, index) => { - return { value: null }; - }); - } - } - //setting new values to series - let i; - for (i = frameDataIndex; i < optionSeriesLength; i++) { - if ( - resultData["series"][i - 1] !== undefined && - resultData["series"][i - 1].hasOwnProperty("data") && - !resultData["series"][i - 1].hasOwnProperty( - "toggleTrendLineObject", - ) - ) { - resultData["series"][i - 1]["data"] = - frameData.data?.values?.map((item, index) => { - return { value: item[i] ?? null }; - }); - } - } - return resultData; //returning updated values to chart - }, - [frameData.data.values], - ); + //update frame values to the series data when frame values are changed + const receiveValueswithCorrections = useCallback( + (resultData: unknown) => { + let frameDataIndex = 0; + //setting xaxis data + resultData["xAxis"]["data"] = frameData.data?.values?.map( + (item, index) => { + return { value: item[frameDataIndex] }; + }, + ); + const optionSeriesLength = frameData.data.headers.length; + frameDataIndex++; + //setting all values to all existing series to null, to restore the chart to initial state so new values will be updated + for ( + let seriesIdx = 0; + seriesIdx < resultData["series"].length; + seriesIdx++ + ) { + if ( + resultData["series"][seriesIdx] !== undefined && + Object.hasOwn(resultData["series"][seriesIdx], "data") && + !Object.hasOwn( + resultData["series"][seriesIdx], + "toggleTrendLineObject", + ) + ) { + resultData["series"][seriesIdx]["data"] = + frameData.data?.values?.map((item, index) => { + return { value: null }; + }); + } + } + //setting new values to series + let i; + for (i = frameDataIndex; i < optionSeriesLength; i++) { + if ( + resultData["series"][i - 1] !== undefined && + Object.hasOwn(resultData["series"][i - 1], "data") && + !Object.hasOwn( + resultData["series"][i - 1], + "toggleTrendLineObject", + ) + ) { + resultData["series"][i - 1]["data"] = + frameData.data?.values?.map((item, index) => { + return { value: item[i] ?? null }; + }); + } + } + return resultData; //returning updated values to chart + }, + [frameData.data.values], + ); - //on events object for getting and processing events with chart - const onClickChart = { - //when contextmenu event is raised, default context menu made hidden, and custom component is shown - contextmenu: (params) => { - if (params.data) { - const xAxisName = data.option["xAxis"]["pixelvalue"][0]; - const xAxisValue = - typeof data.option["xAxis"]["data"][params.dataIndex] == - "object" && - data.option["xAxis"]["data"][ - params.dataIndex - ].hasOwnProperty("value") - ? data.option["xAxis"]["data"][params.dataIndex][ - "value" - ] - : data.option["xAxis"]["data"][params.dataIndex]; - setContextMenu( - contextMenu === null - ? { - mouseX: params.event.event.clientX, - mouseY: params.event.event.clientY, - value: { - name: xAxisName, - value: xAxisValue, - }, - } - : // repeated contextmenu when it is already open closes it with Chrome 84 on Ubuntu - // Other native context menus might behave different. - // With this behavior we prevent contextmenu from the backdrop to re-locale existing context menus. - null, - ); - params.event.event.preventDefault(); - } else { - params.event.event.preventDefault(); - } - }, - //After brushing in bar chart, this event will be triggered to filter the selected data - brushend: (params) => { - const batch = params.batch; - const xAxisName = data.option["xAxis"]["pixelvalue"][0]; - const xAxisValue = chartOperationData.current.brushSelected.map( - (item) => - typeof item === "object" && item.hasOwnProperty("value") - ? item["value"] - : item, - ); - frameData.filter( - `SetFrameFilter(${xAxisName}==${JSON.stringify(xAxisValue)})`, - ); - }, - //this event will be triggered when bar data is being selected - brushselected: (params) => { - const batch = params.batch; - if (batch.length) { - const firstBatch = batch[0]; - const selectedData = firstBatch.selected; - const firstSelectedData = selectedData[0] || []; - const xAxisData = data.option["xAxis"]["data"].filter( - (item, index) => - firstSelectedData.dataIndex.includes(index), - ); - chartOperationData.current.brushSelected = xAxisData; - } - }, - }; + //on events object for getting and processing events with chart + const onClickChart = { + //when contextmenu event is raised, default context menu made hidden, and custom component is shown + contextmenu: (params) => { + if (params.data) { + const xAxisName = data.option["xAxis"]["pixelvalue"][0]; + const xAxisValue = + typeof data.option["xAxis"]["data"][params.dataIndex] == + "object" && + Object.hasOwn( + data.option["xAxis"]["data"][params.dataIndex], + "value", + ) + ? data.option["xAxis"]["data"][params.dataIndex][ + "value" + ] + : data.option["xAxis"]["data"][params.dataIndex]; + setContextMenu( + contextMenu === null + ? { + mouseX: params.event.event.clientX, + mouseY: params.event.event.clientY, + value: { + name: xAxisName, + value: xAxisValue, + }, + } + : // repeated contextmenu when it is already open closes it with Chrome 84 on Ubuntu + // Other native context menus might behave different. + // With this behavior we prevent contextmenu from the backdrop to re-locale existing context menus. + null, + ); + params.event.event.preventDefault(); + } else { + params.event.event.preventDefault(); + } + }, + //After brushing in bar chart, this event will be triggered to filter the selected data + brushend: (params) => { + const batch = params.batch; + const xAxisName = data.option["xAxis"]["pixelvalue"][0]; + const xAxisValue = chartOperationData.current.brushSelected.map( + (item) => + typeof item === "object" && Object.hasOwn(item, "value") + ? item["value"] + : item, + ); + frameData.filter( + `SetFrameFilter(${xAxisName}==${JSON.stringify(xAxisValue)})`, + ); + }, + //this event will be triggered when bar data is being selected + brushselected: (params) => { + const batch = params.batch; + if (batch.length) { + const firstBatch = batch[0]; + const selectedData = firstBatch.selected; + const firstSelectedData = selectedData[0] || []; + const xAxisData = data.option["xAxis"]["data"].filter( + (item, index) => + firstSelectedData.dataIndex.includes(index), + ); + chartOperationData.current.brushSelected = xAxisData; + } + }, + }; - //validating the received data.option is in string format and parse it and then assign the same to chart - if (typeof data.option === "string") { - try { - const options = JSON.parse(data.option); - return ( - - - - ); - } catch (e) { - return ( - - There is an issue parsing your JSON. - - ); - } - } else { - //assign the data from frame to exising object based on frame is selected or not - resultData = - data.frame.name && - frameData.data.values.length > 0 && - frameData.isLoading === false - ? receiveValueswithCorrections(parsedOption) - : parsedOption; - return ( - - - { - chartOperationData.current.contextMenu = null; - chartOperationData.current.yAxisColumn = null; - chartOperationData.current.brushSelected = null; - setContextMenu(null); - }} - /> - - ); - } + //validating the received data.option is in string format and parse it and then assign the same to chart + if (typeof data.option === "string") { + try { + const options = JSON.parse(data.option); + return ( + + + + ); + } catch (e) { + return ( + + There is an issue parsing your JSON. + + ); + } + } else { + //assign the data from frame to exising object based on frame is selected or not + resultData = + data.frame.name && + frameData.data.values.length > 0 && + frameData.isLoading === false + ? receiveValueswithCorrections(parsedOption) + : parsedOption; + return ( + + + { + chartOperationData.current.contextMenu = null; + chartOperationData.current.yAxisColumn = null; + chartOperationData.current.brushSelected = null; + setContextMenu(null); + }} + /> + + ); + } }); diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/bar-chart/ChartContextMenu.tsx b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/bar-chart/ChartContextMenu.tsx index a84bbbd654..f1087ad4bd 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/bar-chart/ChartContextMenu.tsx +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/bar-chart/ChartContextMenu.tsx @@ -1,210 +1,209 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { useEffect, useRef } from "react"; -import { observer } from "mobx-react-lite"; -import { PathValue } from "react-hook-form"; - -import { MenuTwo, MenuItemTwo } from "@semoss/ui"; -import { useBlock, useFrame } from "../../../../../hooks"; -import { EchartVisualizationBlockDef } from "../../VisualizationBlock"; +import { observer } from "mobx-react-lite"; +import { useEffect, useRef } from "react"; +import type { PathValue } from "react-hook-form"; +import { MenuItemTwo, MenuTwo } from "@semoss/ui"; +import { useBlock, type useFrame } from "../../../../../hooks"; +import type { EchartVisualizationBlockDef } from "../../VisualizationBlock"; export interface ChartContextMenuProps { - id: string; - frame: ReturnType; - contextMenu: { - mouseX: number; - mouseY: number; - value: any; - } | null; - chartInstance: any; - onClose: () => void; + id: string; + frame: ReturnType; + contextMenu: { + mouseX: number; + mouseY: number; + value: any; + } | null; + chartInstance: any; + onClose: () => void; } //Open this contextmenu when right click event is triggered export const ChartContextMenu: React.FC = observer( - ({ id, frame, contextMenu, chartInstance, onClose }) => { - const { data, setData } = useBlock(id); - const currentOperation = useRef({ - unfilterActive: false, - filterActive: false, - excludeActive: false, - }); - //Checking the current action state for filtering and unfiltering to set and update the data to chart using setoption and setData - useEffect(() => { - if (frame.isLoading === false && frame.error === undefined) { - //in contextmenu, when the unfilter is made active - if (currentOperation.current.unfilterActive) { - try { - const optionDataProcessed = processReceivedData( - frame.data, - ); - data.option["xAxis"]["data"] = - optionDataProcessed["xAxis"]; - data.option["series"][0]["data"] = - optionDataProcessed["yAxis"]; - setData("option", data.option as PathValue); - if (chartInstance.setOption !== null) { - chartInstance.setOption(data.option); - currentOperation.current.unfilterActive = false; - } - } catch (e) {} - } - //in contextmenu, when the filter is made active - if (currentOperation.current.filterActive) { - try { - const optionDataProcessed = processReceivedData( - frame.data, - ); - data.option["xAxis"]["data"] = - optionDataProcessed["xAxis"]; - data.option["series"][0]["data"] = - optionDataProcessed["yAxis"]; - setData("option", data.option as PathValue); - if (chartInstance.setOption !== null) { - chartInstance.setOption(data.option); - currentOperation.current.filterActive = false; - contextMenu = { - ...contextMenu, - ["value"]: null, - }; - disableSelection(); - } - } catch (e) {} - } - //in contextmenu, when the exclude is made active - if (currentOperation.current.excludeActive) { - try { - const optionDataProcessed = processReceivedData( - frame.data, - ); - data.option["xAxis"]["data"] = - optionDataProcessed["xAxis"]; - data.option["series"][0]["data"] = - optionDataProcessed["yAxis"]; - setData("option", data.option as PathValue); - if (chartInstance.setOption !== null) { - chartInstance.setOption(data.option); - currentOperation.current.excludeActive = false; - contextMenu = { - ...contextMenu, - ["value"]: null, - }; - disableSelection(); - } - } catch (e) {} - } - } - }, [frame.data]); - //run disable selection in a delay after filter action is completed - function disableSelection() { - setTimeout(() => { - chartInstance.dispatchAction({ - type: "brush", - areas: [], - }); - }, 500); - } - //convert the received data from frame and update the data in the format for setting to chart - function processReceivedData(frameResult) { - return { - xAxis: frameResult.values.map((item) => { - return item[0]; - }), - yAxis: frameResult.values.map((item) => { - return item[1]; - }), - }; - } - return ( - onClose()} - anchorReference="anchorPosition" - anchorPosition={ - contextMenu !== null - ? { - top: contextMenu.mouseY, - left: contextMenu.mouseX, - } - : undefined - } - > - {contextMenu && !data.contextMenu?.hideUnfilter ? ( - { - frame.unfilter(); - let optionUp = data.option; - const reUpdate = data.option["series"]; - optionUp = { - ...optionUp, - ["series"]: null, - }; - try { - setData( - "option", - optionUp as PathValue, - ); - currentOperation.current.unfilterActive = true; - } catch (e) {} + ({ id, frame, contextMenu, chartInstance, onClose }) => { + const { data, setData } = useBlock(id); + const currentOperation = useRef({ + unfilterActive: false, + filterActive: false, + excludeActive: false, + }); + //Checking the current action state for filtering and unfiltering to set and update the data to chart using setoption and setData + useEffect(() => { + if (frame.isLoading === false && frame.error === undefined) { + //in contextmenu, when the unfilter is made active + if (currentOperation.current.unfilterActive) { + try { + const optionDataProcessed = processReceivedData( + frame.data, + ); + data.option["xAxis"]["data"] = + optionDataProcessed["xAxis"]; + data.option["series"][0]["data"] = + optionDataProcessed["yAxis"]; + setData("option", data.option as PathValue); + if (chartInstance.setOption !== null) { + chartInstance.setOption(data.option); + currentOperation.current.unfilterActive = false; + } + } catch (e) {} + } + //in contextmenu, when the filter is made active + if (currentOperation.current.filterActive) { + try { + const optionDataProcessed = processReceivedData( + frame.data, + ); + data.option["xAxis"]["data"] = + optionDataProcessed["xAxis"]; + data.option["series"][0]["data"] = + optionDataProcessed["yAxis"]; + setData("option", data.option as PathValue); + if (chartInstance.setOption !== null) { + chartInstance.setOption(data.option); + currentOperation.current.filterActive = false; + contextMenu = { + ...contextMenu, + ["value"]: null, + }; + disableSelection(); + } + } catch (e) {} + } + //in contextmenu, when the exclude is made active + if (currentOperation.current.excludeActive) { + try { + const optionDataProcessed = processReceivedData( + frame.data, + ); + data.option["xAxis"]["data"] = + optionDataProcessed["xAxis"]; + data.option["series"][0]["data"] = + optionDataProcessed["yAxis"]; + setData("option", data.option as PathValue); + if (chartInstance.setOption !== null) { + chartInstance.setOption(data.option); + currentOperation.current.excludeActive = false; + contextMenu = { + ...contextMenu, + ["value"]: null, + }; + disableSelection(); + } + } catch (e) {} + } + } + }, [frame.data]); + //run disable selection in a delay after filter action is completed + function disableSelection() { + setTimeout(() => { + chartInstance.dispatchAction({ + type: "brush", + areas: [], + }); + }, 500); + } + //convert the received data from frame and update the data in the format for setting to chart + function processReceivedData(frameResult) { + return { + xAxis: frameResult.values.map((item) => { + return item[0]; + }), + yAxis: frameResult.values.map((item) => { + return item[1]; + }), + }; + } + return ( + onClose()} + anchorReference="anchorPosition" + anchorPosition={ + contextMenu !== null + ? { + top: contextMenu.mouseY, + left: contextMenu.mouseX, + } + : undefined + } + > + {contextMenu && !data.contextMenu?.hideUnfilter ? ( + { + frame.unfilter(); + let optionUp = data.option; + const reUpdate = data.option["series"]; + optionUp = { + ...optionUp, + ["series"]: null, + }; + try { + setData( + "option", + optionUp as PathValue, + ); + currentOperation.current.unfilterActive = true; + } catch (e) {} - onClose(); - }} - > - Unfilter - - ) : null} - {contextMenu && !data.contextMenu?.hideFilter ? ( - { - frame.filter( - `SetFrameFilter(${ - contextMenu.value.name - }==${JSON.stringify(contextMenu.value.value)})`, - ); - let optionUp = data.option; - const reUpdate = data.option["series"]; - optionUp = { - ...optionUp, - ["series"]: null, - }; - setData("option", optionUp as PathValue); - currentOperation.current.filterActive = true; - onClose(); - }} - > - Filter {contextMenu.value.name} == - {typeof contextMenu.value === "string" - ? contextMenu.value - : JSON.stringify(contextMenu.value.value)} - - ) : null} - {contextMenu && !data.contextMenu?.hideExclude ? ( - { - frame.filter( - `SetFrameFilter(${contextMenu.value.name}!="${contextMenu.value.value}")`, - ); - let optionUp = data.option; - const reUpdate = data.option["series"]; - optionUp = { - ...optionUp, - ["series"]: null, - }; - setData("option", optionUp as PathValue); - currentOperation.current.excludeActive = true; - onClose(); - }} - > - Exclude {contextMenu.value.name} !={" "} - {contextMenu?.value?.value} - - ) : null} - - ); - }, + onClose(); + }} + > + Unfilter + + ) : null} + {contextMenu && !data.contextMenu?.hideFilter ? ( + { + frame.filter( + `SetFrameFilter(${ + contextMenu.value.name + }==${JSON.stringify(contextMenu.value.value)})`, + ); + let optionUp = data.option; + const reUpdate = data.option["series"]; + optionUp = { + ...optionUp, + ["series"]: null, + }; + setData("option", optionUp as PathValue); + currentOperation.current.filterActive = true; + onClose(); + }} + > + Filter {contextMenu.value.name} == + {typeof contextMenu.value === "string" + ? contextMenu.value + : JSON.stringify(contextMenu.value.value)} + + ) : null} + {contextMenu && !data.contextMenu?.hideExclude ? ( + { + frame.filter( + `SetFrameFilter(${contextMenu.value.name}!="${contextMenu.value.value}")`, + ); + let optionUp = data.option; + const reUpdate = data.option["series"]; + optionUp = { + ...optionUp, + ["series"]: null, + }; + setData("option", optionUp as PathValue); + currentOperation.current.excludeActive = true; + onClose(); + }} + > + Exclude {contextMenu.value.name} !={" "} + {contextMenu?.value?.value} + + ) : null} + + ); + }, ); diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/dendrogram/Dendrogram.tsx b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/dendrogram/Dendrogram.tsx index f6d4442730..cd67651470 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/dendrogram/Dendrogram.tsx +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/dendrogram/Dendrogram.tsx @@ -1,343 +1,341 @@ -import { useEffect, useMemo, useState } from "react"; +import type { EChartsOption } from "echarts"; +import EChartsReact from "echarts-for-react"; import { computed } from "mobx"; import { observer } from "mobx-react-lite"; -import EChartsReact from "echarts-for-react"; -import { EChartsOption } from "echarts"; - +import { useEffect, useMemo, useState } from "react"; import { styled } from "@semoss/ui"; - -import { getValueByPath } from "../../../../../utility"; import { useBlock, useFrame } from "../../../../../hooks"; -import { EchartVisualizationBlockDef } from "../../VisualizationBlock"; - +import { getValueByPath } from "../../../../../utility"; +import type { EchartVisualizationBlockDef } from "../../VisualizationBlock"; import { VizBlockContextMenu } from "../../VizBlockContextMenu"; import { DendrogramChartField } from "./DendrogramChartField"; //Main Container for displaying Bar chart const StyledMainContainer = styled("div")(({ theme }) => ({ - height: "100%", - width: "100%", + height: "100%", + width: "100%", })); //container for displaying invalid or no data const StyledNoDataContainer = styled("div", { - shouldForwardProp: (prop) => prop !== "error", + shouldForwardProp: (prop) => prop !== "error", })<{ error?: boolean }>(({ error = false, theme }) => ({ - height: "inherit", - width: "inherit", - maxHeight: "30vh", - maxWidth: "80vh", - display: "flex", - flexWrap: "wrap", - alignContent: "flex-start", - color: error ? theme.palette.error.main : "unset", + height: "inherit", + width: "inherit", + maxHeight: "30vh", + maxWidth: "80vh", + display: "flex", + flexWrap: "wrap", + alignContent: "flex-start", + color: error ? theme.palette.error.main : "unset", })); //sub styled container to manage facet field with chart const StyledContainer = styled("div")(() => ({ - display: "flex", - justifyContent: "flex-start", - width: "100%", - height: "12%", - maxHeight: "12%", - overflow: "auto", + display: "flex", + justifyContent: "flex-start", + width: "100%", + height: "12%", + maxHeight: "12%", + overflow: "auto", })); //bar component properties interface DendrogramProps { - id: string; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - updateJson: (data: any, path: any) => void; + id: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + updateJson: (data: any, path: any) => void; } export const Dendrogram = observer(({ id, updateJson }: DendrogramProps) => { - const { data, setData } = useBlock(id); + const { data, setData } = useBlock(id); - const [contextMenu, setContextMenu] = useState<{ - mouseX: number; //x axis position for the click/brush event - mouseY: number; //y axis position for the click/brush event - value: unknown; //value can be of object or string or number type - } | null>(null); - const computedValue = useMemo(() => { - return computed(() => { - if (!data) { - return ""; - } - const v = getValueByPath(data, "option"); - if (typeof v === "undefined") { - return ""; - } else if (typeof v === "string") { - return v; - } - return JSON.stringify(v, null, 2); - }); - }, [data, "option"]).get(); - const facetcomputedValue = useMemo(() => { - return computed(() => { - if (!data) { - return ""; - } - const v = getValueByPath(data, "facet.facetList"); - if (typeof v === "undefined") { - return ""; - } else if (typeof v === "string") { - return v; - } - return JSON.stringify(v, null, 2); - }); - }, [data, "facet.facetList"]).get(); + const [contextMenu, setContextMenu] = useState<{ + mouseX: number; //x axis position for the click/brush event + mouseY: number; //y axis position for the click/brush event + value: unknown; //value can be of object or string or number type + } | null>(null); + const computedValue = useMemo(() => { + return computed(() => { + if (!data) { + return ""; + } + const v = getValueByPath(data, "option"); + if (typeof v === "undefined") { + return ""; + } else if (typeof v === "string") { + return v; + } + return JSON.stringify(v, null, 2); + }); + }, [data, "option"]).get(); + const facetcomputedValue = useMemo(() => { + return computed(() => { + if (!data) { + return ""; + } + const v = getValueByPath(data, "facet.facetList"); + if (typeof v === "undefined") { + return ""; + } else if (typeof v === "string") { + return v; + } + return JSON.stringify(v, null, 2); + }); + }, [data, "facet.facetList"]).get(); - const parsedJson = useMemo(() => { - try { - return JSON.parse(computedValue); - } catch (e) { - return null; - } - }, [computedValue]); - //Select (bp_1d) | Sort(columns=["bp_1d"], sort=["asc"]) | Collect(-1) - const facetSelector = useMemo(() => { - return `Select (${data.facet?.facetSelected?.map((c, index) => { - return c.selector; - })}).as([${data.facet?.facetSelected?.map((c, index) => { - return c.name; - })}]) | Sort(columns=["${data.facet?.facetSelected?.map( - (c) => c.name, - )}"], sort=["asc"]) `; - }, [data.facet.facetSelected]); + const parsedJson = useMemo(() => { + try { + return JSON.parse(computedValue); + } catch (e) { + return null; + } + }, [computedValue]); + //Select (bp_1d) | Sort(columns=["bp_1d"], sort=["asc"]) | Collect(-1) + const facetSelector = useMemo(() => { + return `Select (${data.facet?.facetSelected?.map((c, index) => { + return c.selector; + })}).as([${data.facet?.facetSelected?.map((c, index) => { + return c.name; + })}]) | Sort(columns=["${data.facet?.facetSelected?.map( + (c) => c.name, + )}"], sort=["asc"]) `; + }, [data.facet.facetSelected]); - const facetFrame = useFrame(data.frame.name, { - selector: facetSelector, - }); - const facetAndDimensionSelector = useMemo(() => { - let valueToCheck = - data.facet?.facetSelected?.[0]?.value == 0 - ? facetFrame.data.values[0]?.[0] - : data.facet?.facetSelected?.[0]?.value; - valueToCheck = isNaN(parseInt(valueToCheck?.toString())) - ? `"${valueToCheck}"` - : valueToCheck; - return `Select(${data.columns - ?.map((c, index) => { - //Converting Y axis columns to Average by default - return c.selector; - }) - .join(", ")}).as([${data.columns - ?.map((c, index) => { - return c.name; - }) - .join(", ")}]) | Filter(${ - data.facet?.facetSelected?.[0]?.name - } == ${valueToCheck})`; - }, [data.facet.facetSelected, facetFrame.data.values]); + const facetFrame = useFrame(data.frame.name, { + selector: facetSelector, + }); + const facetAndDimensionSelector = useMemo(() => { + let valueToCheck = + data.facet?.facetSelected?.[0]?.value == 0 + ? facetFrame.data.values[0]?.[0] + : data.facet?.facetSelected?.[0]?.value; + valueToCheck = isNaN(parseInt(valueToCheck?.toString())) + ? `"${valueToCheck}"` + : valueToCheck; + return `Select(${data.columns + ?.map((c, index) => { + //Converting Y axis columns to Average by default + return c.selector; + }) + .join(", ")}).as([${data.columns + ?.map((c, index) => { + return c.name; + }) + .join(", ")}]) | Filter(${ + data.facet?.facetSelected?.[0]?.name + } == ${valueToCheck})`; + }, [data.facet.facetSelected, facetFrame.data.values]); - const selector = useMemo(() => { - if ( - data.facet?.facetSelected?.length && - data.facet?.facetSelected?.[0]?.selector != "" - ) { - return facetAndDimensionSelector; - } - return `Select(${data.columns - ?.map((c, index) => { - //Converting Y axis columns to Average by default - return c.selector; - }) - .join(", ")}).as([${data.columns - ?.map((c, index) => { - return c.name; - }) - .join(", ")}])`; - }, [data.columns, data.facet.facetSelected, facetFrame.data.values]); + const selector = useMemo(() => { + if ( + data.facet?.facetSelected?.length && + data.facet?.facetSelected?.[0]?.selector != "" + ) { + return facetAndDimensionSelector; + } + return `Select(${data.columns + ?.map((c, index) => { + //Converting Y axis columns to Average by default + return c.selector; + }) + .join(", ")}).as([${data.columns + ?.map((c, index) => { + return c.name; + }) + .join(", ")}])`; + }, [data.columns, data.facet.facetSelected, facetFrame.data.values]); - useEffect(() => { - if ( - facetFrame.isLoading === false && - facetFrame.data.values.length > 0 - ) { - setData( - "facet.facetList", - facetFrame.data.values.map((item: string[] | number[]) => - item[0].toString(), - ), - ); - setData("facet.facetSelected", [ - { - name: data.facet.facetSelected[0].name, - selector: data.facet.facetSelected[0].selector, - value: facetFrame.data.values?.[0]?.[0]?.toString(), - }, - ]); - } - }, [facetFrame.data.values]); + useEffect(() => { + if ( + facetFrame.isLoading === false && + facetFrame.data.values.length > 0 + ) { + setData( + "facet.facetList", + facetFrame.data.values.map((item: string[] | number[]) => + item[0].toString(), + ), + ); + setData("facet.facetSelected", [ + { + name: data.facet.facetSelected[0].name, + selector: data.facet.facetSelected[0].selector, + value: facetFrame.data.values?.[0]?.[0]?.toString(), + }, + ]); + } + }, [facetFrame.data.values]); - const frame = useFrame(data.frame.name, { - selector: selector, - }); - function getSelectorData(header) { - const headerDataList = - data.columns.find((item) => item.name == header)?.selector || ""; - return headerDataList; - } - function getColorData(currentIndex) { - const colorList = parsedJson?.color || []; - return colorList[currentIndex % colorList.length] || "#b0c4de"; - } - const dataOption = useMemo(() => { - let option = JSON.parse(computedValue); + const frame = useFrame(data.frame.name, { + selector: selector, + }); + function getSelectorData(header) { + const headerDataList = + data.columns.find((item) => item.name == header)?.selector || ""; + return headerDataList; + } + function getColorData(currentIndex) { + const colorList = parsedJson?.color || []; + return colorList[currentIndex % colorList.length] || "#b0c4de"; + } + const dataOption = useMemo(() => { + let option = JSON.parse(computedValue); - const seriesIndex = option["series"].findIndex( - (item) => item.type === "tree" && item.data.length, - ); - const dataColumns = - data.columns?.find((item) => item.hasOwnProperty("isFacet")) || {}; - if (seriesIndex > -1) { - const data = option["series"][seriesIndex]["data"]; - // let updatedDataListres = getDataValuesUpdate(0,frame.data.headers.length, [{name: 'Root', children: [], childrenIndex: 0, itemStyle: {color: getColorData(0)}}], -1); - const updatedDataListresLoop = [ - { - name: "Root", - children: [], - childrenIndex: 0, - itemStyle: { color: getColorData(0) }, - }, - ]; - for (let i = 0; i < frame.data.values.length; i++) { - let currentParent = updatedDataListresLoop[0]; // Start from Root for each row - for (let j = 0; j < frame.data.values[i].length; j++) { - if ( - dataColumns.hasOwnProperty("name") && - j + 1 == frame.data.values[i].length - ) - continue; - const childNode = { - name: frame.data.headers[j], - value: frame.data.values[i][j], - category: frame.data.headers[j], - selector: getSelectorData(frame.data.headers[j]), - children: [], - childrenIndex: j + 1, - itemStyle: { - color: getColorData(j + 1), - }, - }; - currentParent.children.push(childNode); - currentParent = childNode; // Move deeper for the next child - } - } - option["series"][seriesIndex]["data"] = updatedDataListresLoop; - option["series"][seriesIndex] = { - ...option["series"][seriesIndex], - label: { - ...option["series"][seriesIndex].label, - formatter: (params) => { - if ( - params.data.name === "Root" && - params.seriesIndex === 0 - ) { - return ""; - } - return params.data.value; - }, - }, - }; - } - const legendData = ["Root", ...frame.data.headers]; - if (option["legend"]?.["show"]) { - const legendSeries = legendData.map((item, index) => { - return { - name: item, - type: "tree", - data: [], - }; - }); - option["series"] = [...option["series"], ...legendSeries]; - } - option = { - ...option, - ["legend"]: { - ...option["legend"], - ["orient"]: "horizontal", - ["left"]: "center", - ["data"]: ["Root", ...frame.data.headers].map((item, index) => { - return { - name: item, - icon: option["series"][seriesIndex].hasOwnProperty( - "symbol", - ) - ? option["series"][seriesIndex]["symbol"] - : "circle", - itemStyle: { - color: getColorData(index), - }, - }; - }), - }, - }; - return option; - }, [frame.data.values, computedValue]); + const seriesIndex = option["series"].findIndex( + (item) => item.type === "tree" && item.data.length, + ); + const dataColumns = + data.columns?.find((item) => Object.hasOwn(item, "isFacet")) || {}; + if (seriesIndex > -1) { + const data = option["series"][seriesIndex]["data"]; + // let updatedDataListres = getDataValuesUpdate(0,frame.data.headers.length, [{name: 'Root', children: [], childrenIndex: 0, itemStyle: {color: getColorData(0)}}], -1); + const updatedDataListresLoop = [ + { + name: "Root", + children: [], + childrenIndex: 0, + itemStyle: { color: getColorData(0) }, + }, + ]; + for (let i = 0; i < frame.data.values.length; i++) { + let currentParent = updatedDataListresLoop[0]; // Start from Root for each row + for (let j = 0; j < frame.data.values[i].length; j++) { + if ( + Object.hasOwn(dataColumns, "name") && + j + 1 == frame.data.values[i].length + ) + continue; + const childNode = { + name: frame.data.headers[j], + value: frame.data.values[i][j], + category: frame.data.headers[j], + selector: getSelectorData(frame.data.headers[j]), + children: [], + childrenIndex: j + 1, + itemStyle: { + color: getColorData(j + 1), + }, + }; + currentParent.children.push(childNode); + currentParent = childNode; // Move deeper for the next child + } + } + option["series"][seriesIndex]["data"] = updatedDataListresLoop; + option["series"][seriesIndex] = { + ...option["series"][seriesIndex], + label: { + ...option["series"][seriesIndex].label, + formatter: (params) => { + if ( + params.data.name === "Root" && + params.seriesIndex === 0 + ) { + return ""; + } + return params.data.value; + }, + }, + }; + } + const legendData = ["Root", ...frame.data.headers]; + if (option["legend"]?.["show"]) { + const legendSeries = legendData.map((item, index) => { + return { + name: item, + type: "tree", + data: [], + }; + }); + option["series"] = [...option["series"], ...legendSeries]; + } + option = { + ...option, + ["legend"]: { + ...option["legend"], + ["orient"]: "horizontal", + ["left"]: "center", + ["data"]: ["Root", ...frame.data.headers].map((item, index) => { + return { + name: item, + icon: Object.hasOwn( + option["series"][seriesIndex], + "symbol", + ) + ? option["series"][seriesIndex]["symbol"] + : "circle", + itemStyle: { + color: getColorData(index), + }, + }; + }), + }, + }; + return option; + }, [frame.data.values, computedValue]); - useEffect(() => { - if (frame.isLoading === false && frame.data.values.length > 0) { - updateJson(dataOption, "option"); - } - }, [frame.data.values]); + useEffect(() => { + if (frame.isLoading === false && frame.data.values.length > 0) { + updateJson(dataOption, "option"); + } + }, [frame.data.values]); - //on events object for getting and processing events with chart - const onClickChart = { - //when contextmenu event is raised, default context menu made hidden, and custom component is shown - contextmenu: (params) => { - if (params.data) { - const selector = params.data.selector; - const value = params.data.value; - setContextMenu( - contextMenu === null - ? { - mouseX: params.event.event.clientX, - mouseY: params.event.event.clientY, - value: { - label: selector, - value: value, - }, - } - : // repeated contextmenu when it is already open closes it with Chrome 84 on Ubuntu - // Other native context menus might behave different. - // With this behavior we prevent contextmenu from the backdrop to re-locale existing context menus. - null, - ); - params.event.event.preventDefault(); - } else { - params.event.event.preventDefault(); - } - }, - }; - const showDendrogramChartField = data.facet.facetSelected.length - ? true - : false; - return ( - - - - {showDendrogramChartField && ( - - )} - - { - setContextMenu(null); - }} - /> - - ); + //on events object for getting and processing events with chart + const onClickChart = { + //when contextmenu event is raised, default context menu made hidden, and custom component is shown + contextmenu: (params) => { + if (params.data) { + const selector = params.data.selector; + const value = params.data.value; + setContextMenu( + contextMenu === null + ? { + mouseX: params.event.event.clientX, + mouseY: params.event.event.clientY, + value: { + label: selector, + value: value, + }, + } + : // repeated contextmenu when it is already open closes it with Chrome 84 on Ubuntu + // Other native context menus might behave different. + // With this behavior we prevent contextmenu from the backdrop to re-locale existing context menus. + null, + ); + params.event.event.preventDefault(); + } else { + params.event.event.preventDefault(); + } + }, + }; + const showDendrogramChartField = data.facet.facetSelected.length + ? true + : false; + return ( + + + + {showDendrogramChartField && ( + + )} + + { + setContextMenu(null); + }} + /> + + ); }); diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/dendrogram/DendrogramChartField.tsx b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/dendrogram/DendrogramChartField.tsx index 3f9d20d7f5..3faa62d2a2 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/dendrogram/DendrogramChartField.tsx +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/dendrogram/DendrogramChartField.tsx @@ -1,181 +1,179 @@ -import { useState, useEffect, useMemo } from "react"; -import { observer } from "mobx-react-lite"; -import { computed } from "mobx"; import ChevronLeftIcon from "@mui/icons-material/ChevronLeft"; import ChevronRightIcon from "@mui/icons-material/ChevronRight"; - +import { computed } from "mobx"; +import { observer } from "mobx-react-lite"; +import { useEffect, useMemo, useState } from "react"; import { IconButton, MenuItem, Select, styled } from "@semoss/ui"; - -import { useBlock } from "../../../../../hooks"; -import { BlockDef } from "../../../../../store"; -import { EchartVisualizationBlockDef } from "../../VisualizationBlock"; import { getValueByPath } from "@/utility"; +import { useBlock } from "../../../../../hooks"; +import type { BlockDef } from "../../../../../store"; +import type { EchartVisualizationBlockDef } from "../../VisualizationBlock"; const StyledMainContainer = styled("div")(({ theme }) => ({ - display: "flex", - flexDirection: "row", - alignItems: "center", - width: "100%", - backgroundColor: theme.palette.background.paper, + display: "flex", + flexDirection: "row", + alignItems: "center", + width: "100%", + backgroundColor: theme.palette.background.paper, })); const StyledSection = styled("div")<{ justifyContent: string }>( - ({ theme, justifyContent }) => ({ - display: "flex", - justifyContent: justifyContent ?? "center", - width: "100%", - }), + ({ theme, justifyContent }) => ({ + display: "flex", + justifyContent: justifyContent ?? "center", + width: "100%", + }), ); export const DendrogramChartField = observer( - ({ id, facetListData }) => { - const { data, setData } = useBlock(id); + ({ id, facetListData }) => { + const { data, setData } = useBlock(id); - const [dropDownValue, setDropDownValue] = useState(""); - const [facetList, setFacetList] = useState([]); - const [navigationDetails, setNavigationDetails] = useState({ - prev: "", - next: "", - }); - const [dendrogramFacetUpdated, setDendrogramFacetUpdated] = - useState(false); - const computedValue = useMemo(() => { - return computed(() => { - if (!data) { - return ""; - } - const v = getValueByPath(data, "facet.facetSelected"); - if (typeof v === "undefined") { - return ""; - } else if (typeof v === "string") { - return v; - } - return JSON.stringify(v, null, 2); - }); - }, [data, "facet.facetSelected"]).get(); - useEffect(() => { - setFacetList((prevList: string[]) => - facetListData.map((item) => - item instanceof Array ? item[0] : item, - ), - ); - setDendrogramFacetUpdated(false); - }, [facetListData]); - useEffect(() => { - if (dendrogramFacetUpdated) return; - try { - const facetSelected = JSON.parse(computedValue); - if (facetSelected.length > 0) { - if ( - facetSelected[0] != undefined && - facetSelected[0]?.value !== undefined && - facetSelected[0]?.value !== dropDownValue - ) { - findAndUpdateNavigationDetails(facetSelected[0].value); - setDropDownValue(facetSelected[0].value); - } - } else { - setDropDownValue(""); - setNavigationDetails({ prev: null, next: null }); - } - } catch (e) { - console.log(e); - } - }, [computedValue, facetListData]); + const [dropDownValue, setDropDownValue] = useState(""); + const [facetList, setFacetList] = useState([]); + const [navigationDetails, setNavigationDetails] = useState({ + prev: "", + next: "", + }); + const [dendrogramFacetUpdated, setDendrogramFacetUpdated] = + useState(false); + const computedValue = useMemo(() => { + return computed(() => { + if (!data) { + return ""; + } + const v = getValueByPath(data, "facet.facetSelected"); + if (typeof v === "undefined") { + return ""; + } else if (typeof v === "string") { + return v; + } + return JSON.stringify(v, null, 2); + }); + }, [data, "facet.facetSelected"]).get(); + useEffect(() => { + setFacetList((prevList: string[]) => + facetListData.map((item) => + item instanceof Array ? item[0] : item, + ), + ); + setDendrogramFacetUpdated(false); + }, [facetListData]); + useEffect(() => { + if (dendrogramFacetUpdated) return; + try { + const facetSelected = JSON.parse(computedValue); + if (facetSelected.length > 0) { + if ( + facetSelected[0] != undefined && + facetSelected[0]?.value !== undefined && + facetSelected[0]?.value !== dropDownValue + ) { + findAndUpdateNavigationDetails(facetSelected[0].value); + setDropDownValue(facetSelected[0].value); + } + } else { + setDropDownValue(""); + setNavigationDetails({ prev: null, next: null }); + } + } catch (e) { + console.log(e); + } + }, [computedValue, facetListData]); - function findAndUpdateNavigationDetails(value) { - const index = facetList.findIndex((item) => - isNaN(parseInt(value)) - ? item == value - : parseInt(item) == parseInt(value), - ); - if (index !== -1) { - const prev = index - 1 >= 0 ? facetList[index - 1] : null; - const next = - index + 1 < facetList.length ? facetList[index + 1] : null; - setNavigationDetails({ prev: prev, next: next }); - } else { - setNavigationDetails({ prev: null, next: null }); - } - } + function findAndUpdateNavigationDetails(value) { + const index = facetList.findIndex((item) => + isNaN(parseInt(value)) + ? item == value + : parseInt(item) == parseInt(value), + ); + if (index !== -1) { + const prev = index - 1 >= 0 ? facetList[index - 1] : null; + const next = + index + 1 < facetList.length ? facetList[index + 1] : null; + setNavigationDetails({ prev: prev, next: next }); + } else { + setNavigationDetails({ prev: null, next: null }); + } + } - function updateField(e) { - setDendrogramFacetUpdated(true); - const newvalue = - e.target.value instanceof Array - ? e.target.value[0] - : e.target.value; - if (e.target.value == "" || e.target.value == null) return; - const prevValue = dropDownValue; - try { - let facetData = JSON.parse(computedValue); - facetData = [ - { - ...facetData[0], - value: newvalue, - }, - ]; - setData("facet.facetSelected", facetData); - setDropDownValue((prevValue) => - e.target.value instanceof Array - ? e.target.value[0] - : e.target.value, - ); - findAndUpdateNavigationDetails( - e.target.value instanceof Array - ? e.target.value[0] - : e.target.value, - ); - } catch (e) { - setDropDownValue(prevValue); - console.log(e); - } - } - console.log(facetList, "facetList"); - return ( - - - - updateField({ - target: { value: navigationDetails.prev }, - }) - } - size="small" - > - - {navigationDetails.prev} - - - - - - - - updateField({ - target: { value: navigationDetails.next }, - }) - } - size="small" - > - {navigationDetails.next} - - - - - ); - }, + function updateField(e) { + setDendrogramFacetUpdated(true); + const newvalue = + e.target.value instanceof Array + ? e.target.value[0] + : e.target.value; + if (e.target.value == "" || e.target.value == null) return; + const prevValue = dropDownValue; + try { + let facetData = JSON.parse(computedValue); + facetData = [ + { + ...facetData[0], + value: newvalue, + }, + ]; + setData("facet.facetSelected", facetData); + setDropDownValue((prevValue) => + e.target.value instanceof Array + ? e.target.value[0] + : e.target.value, + ); + findAndUpdateNavigationDetails( + e.target.value instanceof Array + ? e.target.value[0] + : e.target.value, + ); + } catch (e) { + setDropDownValue(prevValue); + console.log(e); + } + } + console.log(facetList, "facetList"); + return ( + + + + updateField({ + target: { value: navigationDetails.prev }, + }) + } + size="small" + > + + {navigationDetails.prev} + + + + + + + + updateField({ + target: { value: navigationDetails.next }, + }) + } + size="small" + > + {navigationDetails.next} + + + + + ); + }, ); diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/line-chart/Line.tsx b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/line-chart/Line.tsx index f93a58ce70..b1e279462f 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/line-chart/Line.tsx +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/line-chart/Line.tsx @@ -1,330 +1,328 @@ -import { useCallback, useEffect, useMemo, useState } from "react"; +import ReactECharts, { type EChartsOption } from "echarts-for-react"; import { computed } from "mobx"; import { observer } from "mobx-react-lite"; -import ReactECharts, { EChartsOption } from "echarts-for-react"; - +import { useCallback, useEffect, useMemo, useState } from "react"; import { styled } from "@semoss/ui"; - -import { useFrame, useBlock } from "../../../../../hooks"; +import { useBlock, useFrame } from "../../../../../hooks"; import { getValueByPath } from "../../../../../utility"; -import { EchartVisualizationBlockDef } from "../../VisualizationBlock"; import { CustomContextMenu } from "../../CustomContextMenu"; +import type { EchartVisualizationBlockDef } from "../../VisualizationBlock"; const StyledChartContainer = styled("div")(() => ({ - height: "100%", + height: "100%", })); const StyledNoDataContainer = styled("div", { - shouldForwardProp: (prop) => prop !== "error", + shouldForwardProp: (prop) => prop !== "error", })<{ error?: boolean }>(({ error = false, theme }) => ({ - height: "30vh", - width: "80vh", - color: error ? theme.palette.error.main : "unset", + height: "30vh", + width: "80vh", + color: error ? theme.palette.error.main : "unset", })); interface LineProps { - id: string; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - updateJson: (data: any, path: any) => void; + id: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + updateJson: (data: any, path: any) => void; } export const Line = observer(({ id, updateJson }: LineProps) => { - const { data } = useBlock(id); - const [contextMenu, setContextMenu] = useState<{ - mouseX: number; - mouseY: number; - value: unknown; - } | null>(null); - let resultData: unknown = {}; - // get the frame - function getVisualizationBlockSelector(id: string) { - if (id) { - //get the options JSON of the selected block - const blockJSON = data.option; - //initialize the selector string - let selector = "Select("; - //if there are no fields, return null - if (!blockJSON["_state"]) return null; - //get the fields - const selectorFields = blockJSON["_state"]["fields"]; - // get the value and tooltip properties - const dynamicYAndTooltipSet = Array.from( - new Set([ - ...selectorFields["yAxis"], - ...selectorFields["tooltip"], - ]), - ); - // let dynamicYAndTooltipSet = [ - // ...new Set([ - // ...selectorFields["yAxis"], - // ...selectorFields["tooltip"], - // ]), - // ]; - // start forming the selector string - selector += `${selectorFields["xAxis"][0]}`; - // add dynamic y axis and tooltip fields to the selector string - let averageCollection = ""; - for (let i = 0; i < dynamicYAndTooltipSet.length; i++) { - averageCollection += `, Average(${dynamicYAndTooltipSet[i]})`; - selector += `, Average(${dynamicYAndTooltipSet[i]})`; - } - selector += `).as([${selectorFields["xAxis"][0]}${averageCollection}])|Group(${selectorFields["xAxis"][0]})|Sort(${selectorFields["xAxis"][0]})`; - return selector; - } - return null; - } + const { data } = useBlock(id); + const [contextMenu, setContextMenu] = useState<{ + mouseX: number; + mouseY: number; + value: unknown; + } | null>(null); + let resultData: unknown = {}; + // get the frame + function getVisualizationBlockSelector(id: string) { + if (id) { + //get the options JSON of the selected block + const blockJSON = data.option; + //initialize the selector string + let selector = "Select("; + //if there are no fields, return null + if (!blockJSON["_state"]) return null; + //get the fields + const selectorFields = blockJSON["_state"]["fields"]; + // get the value and tooltip properties + const dynamicYAndTooltipSet = Array.from( + new Set([ + ...selectorFields["yAxis"], + ...selectorFields["tooltip"], + ]), + ); + // let dynamicYAndTooltipSet = [ + // ...new Set([ + // ...selectorFields["yAxis"], + // ...selectorFields["tooltip"], + // ]), + // ]; + // start forming the selector string + selector += `${selectorFields["xAxis"][0]}`; + // add dynamic y axis and tooltip fields to the selector string + let averageCollection = ""; + for (let i = 0; i < dynamicYAndTooltipSet.length; i++) { + averageCollection += `, Average(${dynamicYAndTooltipSet[i]})`; + selector += `, Average(${dynamicYAndTooltipSet[i]})`; + } + selector += `).as([${selectorFields["xAxis"][0]}${averageCollection}])|Group(${selectorFields["xAxis"][0]})|Sort(${selectorFields["xAxis"][0]})`; + return selector; + } + return null; + } - /** - * Builds a dynamic query string based on the provided input data. - * @param inputData - An array of tuples where each tuple contains a string and an object mapping field names to aggregation methods. - * @returns A query string that selects and groups by the specified fields with appropriate aggregations. - */ - const buildDynamicQuery = (inputData): string => { - const blockJSON = data.option; - if (!blockJSON["_state"]) return null; - const selectParts: string[] = []; - const aliasParts: string[] = []; - const groupByParts: string[] = []; + /** + * Builds a dynamic query string based on the provided input data. + * @param inputData - An array of tuples where each tuple contains a string and an object mapping field names to aggregation methods. + * @returns A query string that selects and groups by the specified fields with appropriate aggregations. + */ + const buildDynamicQuery = (inputData): string => { + const blockJSON = data.option; + if (!blockJSON["_state"]) return null; + const selectParts: string[] = []; + const aliasParts: string[] = []; + const groupByParts: string[] = []; - inputData.forEach(([_, fields]) => { - for (const field in fields) { - const rawAgg = fields[field]; - aliasParts.push(field); + inputData.forEach(([_, fields]) => { + for (const field in fields) { + const rawAgg = fields[field]; + aliasParts.push(field); - if (rawAgg) { - const cleanedAgg = rawAgg.split(" ").join(""); // Remove spaces (e.g., "Unique Count" → "UniqueCount") - selectParts.push(`${cleanedAgg}(${field})`); - } else { - selectParts.push(field); - groupByParts.push(field); // Only unaggregated fields are grouped - } - } - }); + if (rawAgg) { + const cleanedAgg = rawAgg.split(" ").join(""); // Remove spaces (e.g., "Unique Count" → "UniqueCount") + selectParts.push(`${cleanedAgg}(${field})`); + } else { + selectParts.push(field); + groupByParts.push(field); // Only unaggregated fields are grouped + } + } + }); - return `Select(${selectParts.join(", ")}).as([${aliasParts.join( - ", ", - )}]) | Group(${groupByParts.join(", ")})`; - }; + return `Select(${selectParts.join(", ")}).as([${aliasParts.join( + ", ", + )}]) | Group(${groupByParts.join(", ")})`; + }; - const frame = useFrame(data.frame.name, { - selector: buildDynamicQuery(Object.entries(data?.aggregate ?? {})), - }); - const computedValue = useMemo(() => { - return computed(() => { - if (!data) { - return ""; - } - const v = getValueByPath(data, "option"); - if (typeof v === "undefined") { - return ""; - } else if (typeof v === "string") { - return v; - } - return JSON.stringify(v, null, 2); - }); - }, [data, "option"]).get(); - useEffect(() => { - if ( - data?.frame?.name && - frame?.data?.values.length > 0 && - frame?.isLoading === false - ) { - updateJson(resultData, "option"); - } - }, [frame.data.values]); - //format the frame option data for echart - const formatDataPoints = useCallback( - (resultData: unknown) => { - if (frame.data.values.length > 0) { - const valuesDataSet = JSON.parse( - JSON.stringify(frame.data.values), - ); - let headersDataSet: string[] = JSON.parse( - JSON.stringify(frame.data.headers), - ); - headersDataSet = headersDataSet.map((header: string) => - header.replace("Average_", ""), - ); - //format the data points to match the echart specification - resultData["xAxis"]["data"] = valuesDataSet.map((x) => x[0]); - valuesDataSet.map((x) => x.shift()); - headersDataSet.shift(); - const yAxisListLength = - resultData["_state"]?.["fields"]?.["yAxis"].length; - for (let index = 0; index < yAxisListLength; index++) { - resultData["series"][index]["data"] = valuesDataSet.map( - (x) => { - return x[index]; - }, - ); - resultData["series"][index]["name"] = headersDataSet[index]; - } - // resultData["series"].length = yAxisListLength; - resultData["series"].slice(0, yAxisListLength); - valuesDataSet.map((x) => x.splice(0, yAxisListLength)); - headersDataSet.splice(0, yAxisListLength); - const customTooltipData = []; - data.option["_state"]?.["fields"]["tooltip"].map((x, index) => { - customTooltipData.push({ - name: x, - data: valuesDataSet.map((y) => y[index]), - }); - }); - if (!resultData["tooltip"].hasOwnProperty("formatter")) { - const customTooltipData = []; - data.option["_state"]?.["fields"]["tooltip"].map( - (x, index) => { - customTooltipData.push({ - name: x, - data: valuesDataSet.map((y) => y[index]), - }); - }, - ); - resultData["tooltip"] = { - ...resultData["tooltip"], - formatter: ((customTooltipData) => (params) => { - const formatterStringArr = ["
"]; - const dataIndex = params[0]?.dataIndex; - formatterStringArr.push( - `${params[0].name}
`, - ); - params.forEach((param) => { - let { value, seriesName, color } = param; - if (!isNaN(value) && value !== undefined) { - value = value.toFixed(1); - } - formatterStringArr.push( - `\u25CF Average of ${seriesName}: ${value}
`, - ); - }); - customTooltipData.forEach((data) => { - formatterStringArr.push( - `\u25CF ${data.name}: ${data.data[dataIndex]}
`, - ); - }); - formatterStringArr.push(`
`); - return formatterStringArr.join(" "); - })(customTooltipData), - }; - } else { - delete resultData["tooltip"]["formatter"]; - } - } - return resultData; - }, - [frame.data.values], - ); - function debounce(fn, delay) { - let timer; - return (...args) => { - clearTimeout(timer); - timer = setTimeout(() => fn(...args), delay); - }; - } + const frame = useFrame(data.frame.name, { + selector: buildDynamicQuery(Object.entries(data?.aggregate ?? {})), + }); + const computedValue = useMemo(() => { + return computed(() => { + if (!data) { + return ""; + } + const v = getValueByPath(data, "option"); + if (typeof v === "undefined") { + return ""; + } else if (typeof v === "string") { + return v; + } + return JSON.stringify(v, null, 2); + }); + }, [data, "option"]).get(); + useEffect(() => { + if ( + data?.frame?.name && + frame?.data?.values.length > 0 && + frame?.isLoading === false + ) { + updateJson(resultData, "option"); + } + }, [frame.data.values]); + //format the frame option data for echart + const formatDataPoints = useCallback( + (resultData: unknown) => { + if (frame.data.values.length > 0) { + const valuesDataSet = JSON.parse( + JSON.stringify(frame.data.values), + ); + let headersDataSet: string[] = JSON.parse( + JSON.stringify(frame.data.headers), + ); + headersDataSet = headersDataSet.map((header: string) => + header.replace("Average_", ""), + ); + //format the data points to match the echart specification + resultData["xAxis"]["data"] = valuesDataSet.map((x) => x[0]); + valuesDataSet.map((x) => x.shift()); + headersDataSet.shift(); + const yAxisListLength = + resultData["_state"]?.["fields"]?.["yAxis"].length; + for (let index = 0; index < yAxisListLength; index++) { + resultData["series"][index]["data"] = valuesDataSet.map( + (x) => { + return x[index]; + }, + ); + resultData["series"][index]["name"] = headersDataSet[index]; + } + // resultData["series"].length = yAxisListLength; + resultData["series"].slice(0, yAxisListLength); + valuesDataSet.map((x) => x.splice(0, yAxisListLength)); + headersDataSet.splice(0, yAxisListLength); + const customTooltipData = []; + data.option["_state"]?.["fields"]["tooltip"].map((x, index) => { + customTooltipData.push({ + name: x, + data: valuesDataSet.map((y) => y[index]), + }); + }); + if (!Object.hasOwn(resultData["tooltip"], "formatter")) { + const customTooltipData = []; + data.option["_state"]?.["fields"]["tooltip"].map( + (x, index) => { + customTooltipData.push({ + name: x, + data: valuesDataSet.map((y) => y[index]), + }); + }, + ); + resultData["tooltip"] = { + ...resultData["tooltip"], + formatter: ((customTooltipData) => (params) => { + const formatterStringArr = ["
"]; + const dataIndex = params[0]?.dataIndex; + formatterStringArr.push( + `${params[0].name}
`, + ); + params.forEach((param) => { + let { value, seriesName, color } = param; + if (!isNaN(value) && value !== undefined) { + value = value.toFixed(1); + } + formatterStringArr.push( + `\u25CF Average of ${seriesName}: ${value}
`, + ); + }); + customTooltipData.forEach((data) => { + formatterStringArr.push( + `\u25CF ${data.name}: ${data.data[dataIndex]}
`, + ); + }); + formatterStringArr.push(`
`); + return formatterStringArr.join(" "); + })(customTooltipData), + }; + } else { + delete resultData["tooltip"]["formatter"]; + } + } + return resultData; + }, + [frame.data.values], + ); + function debounce(fn, delay) { + let timer; + return (...args) => { + clearTimeout(timer); + timer = setTimeout(() => fn(...args), delay); + }; + } - const echartsLoaded = debounce((chart) => { - // Fires only once when brush is released - chart.on("brushEnd", (params) => { - if (!params.areas || !params.areas.length) return; - const area = params.areas[0]; - // Get xAxis data - const currentOption = chart.getOption(); - const labelData = currentOption.series[0].data || []; - const xAxisData = currentOption.xAxis?.[0]?.data || []; - let indices = []; - if (area.coordRange && area.coordRange.length === 2) { - const [xRange, yRange] = area.coordRange; - const xIndices = []; - for (let i = xRange[0]; i <= xRange[1]; i++) xIndices.push(i); - const yIndices = []; - for (let i = 0; i < labelData.length; i++) { - const val = labelData[i]; - if (val >= yRange[0] && val <= yRange[1]) yIndices.push(i); - } - indices = xIndices.filter((i) => yIndices.includes(i)); + const echartsLoaded = debounce((chart) => { + // Fires only once when brush is released + chart.on("brushEnd", (params) => { + if (!params.areas || !params.areas.length) return; + const area = params.areas[0]; + // Get xAxis data + const currentOption = chart.getOption(); + const labelData = currentOption.series[0].data || []; + const xAxisData = currentOption.xAxis?.[0]?.data || []; + let indices = []; + if (area.coordRange && area.coordRange.length === 2) { + const [xRange, yRange] = area.coordRange; + const xIndices = []; + for (let i = xRange[0]; i <= xRange[1]; i++) xIndices.push(i); + const yIndices = []; + for (let i = 0; i < labelData.length; i++) { + const val = labelData[i]; + if (val >= yRange[0] && val <= yRange[1]) yIndices.push(i); + } + indices = xIndices.filter((i) => yIndices.includes(i)); - const filteredLabels = indices.map((i) => xAxisData[i]); - const filteredValues = indices.map((i) => labelData[i]); + const filteredLabels = indices.map((i) => xAxisData[i]); + const filteredValues = indices.map((i) => labelData[i]); - if (filteredValues.length > 0) { - frame.filter( - `SetFrameFilter(((${currentOption.series[0]?.name}==[${filteredValues}]) AND (${currentOption.xAxis?.[0]?.name}==[${filteredLabels}])))`, - ); - } - } - }); - }, 2000); - const onClickChart = { - contextmenu: (params) => { - if (params.data) { - const labelName = params.seriesName; - setContextMenu( - contextMenu === null - ? { - mouseX: params.event.event.clientX, - mouseY: params.event.event.clientY, - value: { - label: labelName, - value: params.data, - }, - } - : // repeated contextmenu when it is already open closes it with Chrome 84 on Ubuntu - // Other native context menus might behave different. - // With this behavior we prevent contextmenu from the backdrop to re-locale existing context menus. - null, - ); - params.event.event.preventDefault(); - } else { - params.event.event.preventDefault(); - } - }, - }; - if (typeof data.option === "string") { - // if it's a string, it's either invalid json or a query output that needs to be parsed - // try to parse, and show error otherwise - try { - const lineOptions = JSON.parse(data.option); - return ( - - { - echartsLoaded(chart); - }} - /> - - ); - } catch (e) { - return ( - - There was an issue parsing your JSON. - - ); - } - } else { - resultData = - data?.frame?.name && - frame.data.values.length > 0 && - frame.isLoading === false - ? formatDataPoints(JSON.parse(computedValue)) - : JSON.parse(computedValue); - return ( - - { - echartsLoaded(chart); - }} - style={{ - height: "inherit", - }} - /> - setContextMenu(null)} - /> - - ); - } + if (filteredValues.length > 0) { + frame.filter( + `SetFrameFilter(((${currentOption.series[0]?.name}==[${filteredValues}]) AND (${currentOption.xAxis?.[0]?.name}==[${filteredLabels}])))`, + ); + } + } + }); + }, 2000); + const onClickChart = { + contextmenu: (params) => { + if (params.data) { + const labelName = params.seriesName; + setContextMenu( + contextMenu === null + ? { + mouseX: params.event.event.clientX, + mouseY: params.event.event.clientY, + value: { + label: labelName, + value: params.data, + }, + } + : // repeated contextmenu when it is already open closes it with Chrome 84 on Ubuntu + // Other native context menus might behave different. + // With this behavior we prevent contextmenu from the backdrop to re-locale existing context menus. + null, + ); + params.event.event.preventDefault(); + } else { + params.event.event.preventDefault(); + } + }, + }; + if (typeof data.option === "string") { + // if it's a string, it's either invalid json or a query output that needs to be parsed + // try to parse, and show error otherwise + try { + const lineOptions = JSON.parse(data.option); + return ( + + { + echartsLoaded(chart); + }} + /> + + ); + } catch (e) { + return ( + + There was an issue parsing your JSON. + + ); + } + } else { + resultData = + data?.frame?.name && + frame.data.values.length > 0 && + frame.isLoading === false + ? formatDataPoints(JSON.parse(computedValue)) + : JSON.parse(computedValue); + return ( + + { + echartsLoaded(chart); + }} + style={{ + height: "inherit", + }} + /> + setContextMenu(null)} + /> + + ); + } }); diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/map-chart/Map.tsx b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/map-chart/Map.tsx index bba35e0708..11714ad020 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/map-chart/Map.tsx +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/map-chart/Map.tsx @@ -1,291 +1,289 @@ -import { useCallback, useEffect, useRef, useState } from "react"; -import { observer } from "mobx-react-lite"; -import EChartsReact from "echarts-for-react"; -import * as echarts from "echarts/core"; import { BarChart } from "echarts/charts"; -import { CanvasRenderer } from "echarts/renderers"; import { TooltipComponent } from "echarts/components"; - +import * as echarts from "echarts/core"; +import { CanvasRenderer } from "echarts/renderers"; +import EChartsReact from "echarts-for-react"; +import { observer } from "mobx-react-lite"; +import { useCallback, useEffect, useRef, useState } from "react"; import { styled } from "@semoss/ui"; - import { useBlock, useFrame } from "../../../../../hooks"; -import { BlockComponent } from "../../../../../store"; - -import fetchWorldMap from "./map-utility"; -import { getSelector } from "./MapSelector"; +import type { BlockComponent } from "../../../../../store"; +import { VizBlockContextMenu } from "../../VizBlockContextMenu"; import { processData } from "./MapChartProcessData"; import { formatdatapoints } from "./MapChartTooltipData"; -import { VizBlockContextMenu } from "../../VizBlockContextMenu"; +import { getSelector } from "./MapSelector"; +import fetchWorldMap from "./map-utility"; const StyledNoDataContainer = styled("div", { - shouldForwardProp: (prop) => prop !== "error", + shouldForwardProp: (prop) => prop !== "error", })<{ error?: boolean }>(({ error = false, theme }) => ({ - height: "100%", - width: "100%", - color: error ? theme.palette.error.main : "unset", + height: "100%", + width: "100%", + color: error ? theme.palette.error.main : "unset", })); export interface EChartColumns { - name: string; - selector: string; - width: string; + name: string; + selector: string; + width: string; } export interface EchartVisualizationBlockDef { - widget: "e-chart"; - data: { - option: {}; - frame: { - name: string; - }; - variation: undefined | string; - columns: EChartColumns[]; - aggregate: Record; - contextMenu: { - hideUnfilter: boolean; - hideFilter: boolean; - hideExclude: boolean; - }; - }; - listeners: {}; - slots: never; + widget: "e-chart"; + data: { + option: {}; + frame: { + name: string; + }; + variation: undefined | string; + columns: EChartColumns[]; + aggregate: Record; + contextMenu: { + hideUnfilter: boolean; + hideFilter: boolean; + hideExclude: boolean; + }; + }; + listeners: {}; + slots: never; } export const Map: BlockComponent = observer(({ id }) => { - const { data } = useBlock(id); - const mapRef: any = useRef({}); - echarts.use([BarChart, CanvasRenderer, TooltipComponent]); - const [contextMenu, setContextMenu] = useState<{ - mouseX: number; - mouseY: number; - value: unknown; - } | null>(null); - const frame = useFrame(data?.frame?.name, { - selector: getSelector(data, data?.aggregate), - }); - const updatedOption = - mapRef.current && typeof mapRef.current.getOption === "function" - ? mapRef.current.getOption() - : {}; - - function debounce(fn, delay) { - let timer; - return (...args) => { - clearTimeout(timer); - timer = setTimeout(() => fn(...args), delay); - }; - } - - const handleSelection = debounce(async (value: any, name: any, chart) => { - // update the frame - await frame.filter(`SetFrameFilter(${name}==[${value}])`); - disabledBrush(chart); - }, 1000); - - const echartsLoaded = debounce((chart) => { - mapRef.current = chart; - const option = data.option; - data.option = option; - - chart.setOption(option); - chart.resize(); - chart.on("contextmenu", (params) => { - onClickChart(chart, params); - }); - chart.on("brushselected", (params) => { - const selectedData = params.batch[0]?.selected[0]?.dataIndex; - const currentOption = chart.getOption(); - const labelData = currentOption.series[0]?.data; - const filteredLabels = selectedData?.map( - (index) => labelData[index]?.label?.formatter, - ); - if (filteredLabels?.length > 0) { - handleSelection( - filteredLabels, - currentOption["_state"]["fields"]["label"], - chart, - ); - } - }); - }, 2000); - - const disabledBrush = (chart) => { - chart.dispatchAction({ - type: "brush", - areas: [], - }); - - chart.setOption({ - brush: { - toolbox: [], - brushMode: false, - }, - }); - }; - - const worldJson: any = fetchWorldMap(""); - - useEffect(() => { - let option = data.option; - echarts.registerMap("world", worldJson); - option = { - geo: { - map: "world", - roam: true, - zoom: 1, - center: [0, 0], - }, - series: [ - { - type: "scatter", - // name: 'Scatters Plot', - coordinateSystem: "geo", - }, - ], - }; - - data.option = option; - // mapRef.current?.setOption(option); - }, []); - - const processedFrameData = processData(frame.data, data); - if (processedFrameData && processedFrameData.length > 0) { - data.option["series"][0]["data"] = processedFrameData; - } - - if (!data.option["tooltip"].hasOwnProperty("formatter")) { - data.option["tooltip"] = { - ...data.option["tooltip"], - formatter: formatdatapoints(frame.data, data), - }; - } - - // Calculate bounding box - const lats = data.option["series"][0]["data"].map((d) => d.value[0]); - const lons = data.option["series"][0]["data"].map((d) => d.value[1]); - const minLat = Math.min(...lats); - const maxLat = Math.max(...lats); - const minLon = Math.min(...lons); - const maxLon = Math.max(...lons); - - // Compute center - const centerLat = (minLat + maxLat) / 2; - const centerLon = (minLon + maxLon) / 2; - - // Adjust zoom level based on spread - const latDiff = maxLat - minLat; - const lonDiff = maxLon - minLon; - const maxDiff = Math.max(latDiff, lonDiff); - let zoomLevel = 4; - - // Default zoom - if (maxDiff < 1) zoomLevel = 8; - else if (maxDiff < 5) zoomLevel = 6; - else if (maxDiff < 10) zoomLevel = 5; - else if (maxDiff < 20) zoomLevel = 4; - else zoomLevel = 1; - - if (frame.data.values.length > 0) { - updatedOption["geo"][0]["center"] = [ - centerLat ? centerLat : 0, - centerLon ? centerLon : 0, - ]; - updatedOption["geo"][0]["zoom"] = zoomLevel ? zoomLevel : 4; - } - - if (frame.data.values.length > 0) { - if (data.option.hasOwnProperty("_state")) { - if (data.option["_state"].hasOwnProperty("fields")) { - if (data.option["_state"]["fields"].hasOwnProperty("label")) { - const seriesData = data.option["series"][0]["data"]; - - if ( - data.option["_state"]["fields"].hasOwnProperty("color") - ) { - const n = data.option["_state"][ - "fields" - ].hasOwnProperty("size") - ? 4 - : 3; - const test = frame.data.values - .map((item: any) => item[n]) - .map(String); - - data.option["series"] = []; - - data.option["series"] = test.map((name, index) => ({ - name: String(name), - data: seriesData, - coordinateSystem: "geo", - type: "scatter", - label: { - show: false, - rotate: 0, - name: "", - position: "top", - fontFamily: "sans-serif", - fontSize: 12, - color: "#000000", - }, - symbolSize: data.option["symbolSize"], - symbol: "circle", - })); - - data.option["legend"]["data"] = test; - } else { - mapRef.current.clear(); - - updatedOption["series"] = updatedOption["series"][0]; - mapRef.current.setOption(updatedOption); - - data.option["series"][0]["name"] = - data.option["_state"]["fields"]["label"]; - data.option["legend"]["data"] = [ - data.option["_state"]["fields"]["label"], - ]; - } - } - } - } - } - - const onClickChart = (chart, params) => { - if (params.data) { - const currentOption = chart.getOption(); - const labelName = currentOption["_state"]["fields"]["label"]; - setContextMenu( - contextMenu === null - ? { - mouseX: params.event.event.clientX, - mouseY: params.event.event.clientY, - value: { - label: labelName, - value: params.data.label.formatter, - }, - } - : null, - ); - params.event.event.preventDefault(); - } - }; - - return ( - - { - echartsLoaded(chart); - }} - opts={{ height: "auto", width: "auto" }} - style={{ height: "inherit", width: "inherit" }} - /> - setContextMenu(null)} - /> - - ); + const { data } = useBlock(id); + const mapRef: any = useRef({}); + echarts.use([BarChart, CanvasRenderer, TooltipComponent]); + const [contextMenu, setContextMenu] = useState<{ + mouseX: number; + mouseY: number; + value: unknown; + } | null>(null); + const frame = useFrame(data?.frame?.name, { + selector: getSelector(data, data?.aggregate), + }); + const updatedOption = + mapRef.current && typeof mapRef.current.getOption === "function" + ? mapRef.current.getOption() + : {}; + + function debounce(fn, delay) { + let timer; + return (...args) => { + clearTimeout(timer); + timer = setTimeout(() => fn(...args), delay); + }; + } + + const handleSelection = debounce(async (value: any, name: any, chart) => { + // update the frame + await frame.filter(`SetFrameFilter(${name}==[${value}])`); + disabledBrush(chart); + }, 1000); + + const echartsLoaded = debounce((chart) => { + mapRef.current = chart; + const option = data.option; + data.option = option; + + chart.setOption(option); + chart.resize(); + chart.on("contextmenu", (params) => { + onClickChart(chart, params); + }); + chart.on("brushselected", (params) => { + const selectedData = params.batch[0]?.selected[0]?.dataIndex; + const currentOption = chart.getOption(); + const labelData = currentOption.series[0]?.data; + const filteredLabels = selectedData?.map( + (index) => labelData[index]?.label?.formatter, + ); + if (filteredLabels?.length > 0) { + handleSelection( + filteredLabels, + currentOption["_state"]["fields"]["label"], + chart, + ); + } + }); + }, 2000); + + const disabledBrush = (chart) => { + chart.dispatchAction({ + type: "brush", + areas: [], + }); + + chart.setOption({ + brush: { + toolbox: [], + brushMode: false, + }, + }); + }; + + const worldJson: any = fetchWorldMap(""); + + useEffect(() => { + let option = data.option; + echarts.registerMap("world", worldJson); + option = { + geo: { + map: "world", + roam: true, + zoom: 1, + center: [0, 0], + }, + series: [ + { + type: "scatter", + // name: 'Scatters Plot', + coordinateSystem: "geo", + }, + ], + }; + + data.option = option; + // mapRef.current?.setOption(option); + }, []); + + const processedFrameData = processData(frame.data, data); + if (processedFrameData && processedFrameData.length > 0) { + data.option["series"][0]["data"] = processedFrameData; + } + + if (!Object.hasOwn(data.option["tooltip"], "formatter")) { + data.option["tooltip"] = { + ...data.option["tooltip"], + formatter: formatdatapoints(frame.data, data), + }; + } + + // Calculate bounding box + const lats = data.option["series"][0]["data"].map((d) => d.value[0]); + const lons = data.option["series"][0]["data"].map((d) => d.value[1]); + const minLat = Math.min(...lats); + const maxLat = Math.max(...lats); + const minLon = Math.min(...lons); + const maxLon = Math.max(...lons); + + // Compute center + const centerLat = (minLat + maxLat) / 2; + const centerLon = (minLon + maxLon) / 2; + + // Adjust zoom level based on spread + const latDiff = maxLat - minLat; + const lonDiff = maxLon - minLon; + const maxDiff = Math.max(latDiff, lonDiff); + let zoomLevel = 4; + + // Default zoom + if (maxDiff < 1) zoomLevel = 8; + else if (maxDiff < 5) zoomLevel = 6; + else if (maxDiff < 10) zoomLevel = 5; + else if (maxDiff < 20) zoomLevel = 4; + else zoomLevel = 1; + + if (frame.data.values.length > 0) { + updatedOption["geo"][0]["center"] = [ + centerLat ? centerLat : 0, + centerLon ? centerLon : 0, + ]; + updatedOption["geo"][0]["zoom"] = zoomLevel ? zoomLevel : 4; + } + + if (frame.data.values.length > 0) { + if (Object.hasOwn(data.option, "_state")) { + if (Object.hasOwn(data.option["_state"], "fields")) { + if (Object.hasOwn(data.option["_state"]["fields"], "label")) { + const seriesData = data.option["series"][0]["data"]; + + if ( + Object.hasOwn(data.option["_state"]["fields"], "color") + ) { + const n = Object.hasOwn( + data.option["_state"]["fields"], + "size", + ) + ? 4 + : 3; + const test = frame.data.values + .map((item: any) => item[n]) + .map(String); + + data.option["series"] = []; + + data.option["series"] = test.map((name, index) => ({ + name: String(name), + data: seriesData, + coordinateSystem: "geo", + type: "scatter", + label: { + show: false, + rotate: 0, + name: "", + position: "top", + fontFamily: "sans-serif", + fontSize: 12, + color: "#000000", + }, + symbolSize: data.option["symbolSize"], + symbol: "circle", + })); + + data.option["legend"]["data"] = test; + } else { + mapRef.current.clear(); + + updatedOption["series"] = updatedOption["series"][0]; + mapRef.current.setOption(updatedOption); + + data.option["series"][0]["name"] = + data.option["_state"]["fields"]["label"]; + data.option["legend"]["data"] = [ + data.option["_state"]["fields"]["label"], + ]; + } + } + } + } + } + + const onClickChart = (chart, params) => { + if (params.data) { + const currentOption = chart.getOption(); + const labelName = currentOption["_state"]["fields"]["label"]; + setContextMenu( + contextMenu === null + ? { + mouseX: params.event.event.clientX, + mouseY: params.event.event.clientY, + value: { + label: labelName, + value: params.data.label.formatter, + }, + } + : null, + ); + params.event.event.preventDefault(); + } + }; + + return ( + + { + echartsLoaded(chart); + }} + opts={{ height: "auto", width: "auto" }} + style={{ height: "inherit", width: "inherit" }} + /> + setContextMenu(null)} + /> + + ); }); diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/map-chart/MapChartProcessData.tsx b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/map-chart/MapChartProcessData.tsx index 03accf8514..27dde4e7c5 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/map-chart/MapChartProcessData.tsx +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/map-chart/MapChartProcessData.tsx @@ -1,2167 +1,2165 @@ export const processData = (apiData, data) => { - let fields = "", - label = "", - latitude = "", - longitude = "", - size = "", - color = "", - tooltip = ""; - if (data.option.hasOwnProperty("_state")) { - fields = data.option["_state"]["fields"]; - label = fields["label"]; - latitude = fields["Latitude"]; - longitude = fields["Longitude"]; - size = fields["size"]; - color = fields["color"]; - tooltip = fields["tooltip"]; - } - const formatItem = (label, latitude, longitude) => ({ - value: [longitude, latitude], // latitude and longitude values - label: { - formatter: label.toString(), // Use array[0] as the label - }, - }); + let fields = "", + label = "", + latitude = "", + longitude = "", + size = "", + color = "", + tooltip = ""; + if (Object.hasOwn(data.option, "_state")) { + fields = data.option["_state"]["fields"]; + label = fields["label"]; + latitude = fields["Latitude"]; + longitude = fields["Longitude"]; + size = fields["size"]; + color = fields["color"]; + tooltip = fields["tooltip"]; + } + const formatItem = (label, latitude, longitude) => ({ + value: [longitude, latitude], // latitude and longitude values + label: { + formatter: label.toString(), // Use array[0] as the label + }, + }); - const formatDataItem = ( - label, - latitude, - longitude, - size, - color, - tooltip, - colorMap = null, - ) => { - if (!colorMap.has(color)) { - colorMap.set( - color, - data.option["color"][ - colorMap.size % data.option["color"]?.length - ], - ); - } - const adjustedSize = Math.min(size + data.option["symbolSize"], 50); - return { - value: [longitude, latitude], // latitude and longitude values - label: { - formatter: label.toString(), // Use array[0] as the label - }, - tempSymbolSize: size, // Individual symbol size - symbolSize: adjustedSize, // Individual symbol size - itemStyle: { - color: colorMap.get(color), - colorValue: color, - }, - tooltipValue: tooltip, //tooltip value - }; - }; - const formatData = ( - label, - latitude, - longitude, - size, - color, - colorMap = null, - ) => { - if (!colorMap.has(color)) { - colorMap.set( - color, - data.option["color"][ - colorMap.size % data.option["color"]?.length - ], - ); - } - const adjustedSize = Math.min(size + data.option["symbolSize"], 50); - return { - value: [longitude, latitude], // latitude and longitude values - label: { - formatter: label.toString(), // Use array[0] as the label - }, - tempSymbolSize: size, // Individual symbol size - symbolSize: adjustedSize, // Individual symbol size - itemStyle: { - color: colorMap.get(color), - colorValue: color, - }, - }; - }; - const formatItemData = ( - label, - latitude, - longitude, - color, - tooltip, - colorMap = null, - ) => { - if (!colorMap.has(color)) { - colorMap.set( - color, - data.option["color"][ - colorMap.size % data.option["color"]?.length - ], - ); - } - return { - value: [longitude, latitude], // latitude and longitude values - label: { - formatter: label.toString(), // Use array[0] as the label - }, - itemStyle: { - color: colorMap.get(color), - colorValue: color, - }, - tooltipValue: tooltip, //tooltip value - }; - }; - const formatItems = (label, latitude, longitude, size, tooltip) => { - const adjustedSize = Math.min(size + data.option["symbolSize"], 50); - return { - value: [longitude, latitude], // latitude and longitude values - label: { - formatter: label.toString(), // Use array[0] as the label - }, - tempSymbolSize: size, // Individual symbol size - symbolSize: adjustedSize, // Individual symbol size - tooltipValue: tooltip, //tooltip value - }; - }; - const formatColorDataItem = ( - label, - latitude, - longitude, - color, - colorMap = null, - ) => { - if (!colorMap.has(color)) { - colorMap.set( - color, - data.option["color"][ - colorMap.size % data.option["color"]?.length - ], - ); - } - return { - value: [longitude, latitude], // latitude and longitude values - label: { - formatter: label.toString(), - }, - itemStyle: { - color: colorMap.get(color), - colorValue: color, - }, - }; - }; - const formatSizeDataItem = (label, latitude, longitude, size) => { - const adjustedSize = Math.min(size + data.option["symbolSize"], 50); + const formatDataItem = ( + label, + latitude, + longitude, + size, + color, + tooltip, + colorMap = null, + ) => { + if (!colorMap.has(color)) { + colorMap.set( + color, + data.option["color"][ + colorMap.size % data.option["color"]?.length + ], + ); + } + const adjustedSize = Math.min(size + data.option["symbolSize"], 50); + return { + value: [longitude, latitude], // latitude and longitude values + label: { + formatter: label.toString(), // Use array[0] as the label + }, + tempSymbolSize: size, // Individual symbol size + symbolSize: adjustedSize, // Individual symbol size + itemStyle: { + color: colorMap.get(color), + colorValue: color, + }, + tooltipValue: tooltip, //tooltip value + }; + }; + const formatData = ( + label, + latitude, + longitude, + size, + color, + colorMap = null, + ) => { + if (!colorMap.has(color)) { + colorMap.set( + color, + data.option["color"][ + colorMap.size % data.option["color"]?.length + ], + ); + } + const adjustedSize = Math.min(size + data.option["symbolSize"], 50); + return { + value: [longitude, latitude], // latitude and longitude values + label: { + formatter: label.toString(), // Use array[0] as the label + }, + tempSymbolSize: size, // Individual symbol size + symbolSize: adjustedSize, // Individual symbol size + itemStyle: { + color: colorMap.get(color), + colorValue: color, + }, + }; + }; + const formatItemData = ( + label, + latitude, + longitude, + color, + tooltip, + colorMap = null, + ) => { + if (!colorMap.has(color)) { + colorMap.set( + color, + data.option["color"][ + colorMap.size % data.option["color"]?.length + ], + ); + } + return { + value: [longitude, latitude], // latitude and longitude values + label: { + formatter: label.toString(), // Use array[0] as the label + }, + itemStyle: { + color: colorMap.get(color), + colorValue: color, + }, + tooltipValue: tooltip, //tooltip value + }; + }; + const formatItems = (label, latitude, longitude, size, tooltip) => { + const adjustedSize = Math.min(size + data.option["symbolSize"], 50); + return { + value: [longitude, latitude], // latitude and longitude values + label: { + formatter: label.toString(), // Use array[0] as the label + }, + tempSymbolSize: size, // Individual symbol size + symbolSize: adjustedSize, // Individual symbol size + tooltipValue: tooltip, //tooltip value + }; + }; + const formatColorDataItem = ( + label, + latitude, + longitude, + color, + colorMap = null, + ) => { + if (!colorMap.has(color)) { + colorMap.set( + color, + data.option["color"][ + colorMap.size % data.option["color"]?.length + ], + ); + } + return { + value: [longitude, latitude], // latitude and longitude values + label: { + formatter: label.toString(), + }, + itemStyle: { + color: colorMap.get(color), + colorValue: color, + }, + }; + }; + const formatSizeDataItem = (label, latitude, longitude, size) => { + const adjustedSize = Math.min(size + data.option["symbolSize"], 50); - return { - value: [longitude, latitude], // latitude and longitude values - label: { - formatter: label.toString(), // Use array[0] as the label - }, - tempSymbolSize: size, // Individual symbol size - symbolSize: adjustedSize, // Individual symbol size - }; - }; - const formatTooltipDataItem = (label, latitude, longitude, tooltip) => ({ - value: [longitude, latitude], // latitude and longitude values - label: { - formatter: label.toString(), // Use array[0] as the label - }, - tooltipValue: tooltip, //tooltip value - }); + return { + value: [longitude, latitude], // latitude and longitude values + label: { + formatter: label.toString(), // Use array[0] as the label + }, + tempSymbolSize: size, // Individual symbol size + symbolSize: adjustedSize, // Individual symbol size + }; + }; + const formatTooltipDataItem = (label, latitude, longitude, tooltip) => ({ + value: [longitude, latitude], // latitude and longitude values + label: { + formatter: label.toString(), // Use array[0] as the label + }, + tooltipValue: tooltip, //tooltip value + }); - if (apiData["values"]) { - if (data.option.hasOwnProperty("_state")) { - if (data.option["_state"].hasOwnProperty("fields")) { - if ( - label && - latitude && - longitude && - size && - color && - tooltip - ) { - const colorMap = new Map(); - if ( - latitude === longitude && - latitude === size && - latitude === color && - latitude === tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[1], - item[1], - item[1], - colorMap, - ), - })); - } - if ( - latitude == longitude && - label == size && - label == color && - label == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[0], - item[0], - item[0], - colorMap, - ), - })); - } - if ( - latitude == longitude && - latitude == size && - label == color && - label == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[1], - item[0], - item[0], - colorMap, - ), - })); - } - if ( - latitude == longitude && - latitude == size && - label == color && - latitude == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[1], - item[0], - item[1], - colorMap, - ), - })); - } - if ( - latitude == longitude && - label == size && - latitude == color && - label == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[0], - item[1], - item[0], - colorMap, - ), - })); - } - if ( - latitude == longitude && - label == size && - label == color && - latitude == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[0], - item[0], - item[1], - colorMap, - ), - })); - } - if ( - latitude == longitude && - size == color && - size == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[2], - item[2], - colorMap, - ), - })); - } - if ( - latitude == longitude && - label == color && - size == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[0], - item[2], - colorMap, - ), - })); - } - if ( - latitude == longitude && - size == tooltip && - latitude == color - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[1], - item[2], - colorMap, - ), - })); - } - if ( - latitude == longitude && - size == color && - latitude == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[2], - item[1], - colorMap, - ), - })); - } - if ( - latitude === size && - latitude === color && - latitude === tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[1], - item[1], - colorMap, - ), - })); - } - if ( - longitude === size && - longitude === color && - longitude === tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[2], - item[2], - colorMap, - ), - })); - } - if ( - latitude === size && - latitude === color && - longitude === tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[1], - item[2], - colorMap, - ), - })); - } - if ( - latitude === size && - longitude === color && - latitude === tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[2], - item[1], - colorMap, - ), - })); - } - if ( - longitude === size && - latitude === color && - latitude === tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[1], - item[1], - colorMap, - ), - })); - } - if ( - longitude === size && - longitude === color && - latitude === tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[2], - item[1], - colorMap, - ), - })); - } - if ( - longitude === size && - latitude === color && - longitude === tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[1], - item[2], - colorMap, - ), - })); - } - if ( - latitude === size && - longitude === color && - longitude === tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[2], - item[2], - colorMap, - ), - })); - } - if ( - latitude === size && - latitude === tooltip && - label === color - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[0], - item[1], - colorMap, - ), - })); - } - if ( - longitude === size && - longitude === tooltip && - label === color - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[0], - item[2], - colorMap, - ), - })); - } - if ( - latitude === size && - longitude === tooltip && - label === color - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[0], - item[2], - colorMap, - ), - })); - } - if ( - longitude === size && - latitude === tooltip && - label === color - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[0], - item[1], - colorMap, - ), - })); - } - if ( - latitude == longitude && - label == size && - latitude == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[0], - item[2], - item[1], - colorMap, - ), - })); - } - if ( - latitude == longitude && - latitude == size && - latitude == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[1], - item[2], - item[1], - colorMap, - ), - })); - } - if ( - latitude == longitude && - label == color && - latitude == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[0], - item[1], - colorMap, - ), - })); - } - if ( - latitude == longitude && - label == size && - label == color - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[0], - item[0], - item[2], - colorMap, - ), - })); - } - if ( - latitude == longitude && - label == color && - label == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[0], - item[0], - colorMap, - ), - })); - } - if ( - latitude == longitude && - label == size && - label == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[0], - item[2], - item[0], - colorMap, - ), - })); - } - if ( - latitude == longitude && - latitude == size && - latitude == color - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[1], - item[1], - item[2], - colorMap, - ), - })); - } - if ( - latitude == longitude && - latitude == size && - latitude == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[1], - item[2], - item[1], - colorMap, - ), - })); - } - if ( - latitude == longitude && - latitude == color && - latitude == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[1], - item[1], - colorMap, - ), - })); - } - if ( - latitude === longitude && - latitude === size && - label === color - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[1], - item[0], - item[2], - colorMap, - ), - })); - } - if (size == color && latitude == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[3], - item[1], - colorMap, - ), - })); - } - if (size == color && longitude == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[3], - item[2], - colorMap, - ), - })); - } - if (size == color && longitude == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[3], - item[2], - colorMap, - ), - })); - } - if (size == color && size == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[3], - item[3], - colorMap, - ), - })); - } - if (size == tooltip && latitude == color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[1], - item[3], - colorMap, - ), - })); - } - if (size == tooltip && longitude == color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[2], - item[3], - colorMap, - ), - })); - } - if (latitude == longitude && latitude == size) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[1], - item[2], - item[3], - colorMap, - ), - })); - } - if (latitude == longitude && latitude == color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[1], - item[3], - colorMap, - ), - })); - } - if (latitude == longitude && size == color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[2], - item[3], - colorMap, - ), - })); - } - if (latitude == longitude && latitude == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[3], - item[1], - colorMap, - ), - })); - } - if (latitude == longitude && size == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[3], - item[2], - colorMap, - ), - })); - } - if (latitude == longitude && label == size) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[0], - item[2], - item[3], - colorMap, - ), - })); - } - if (latitude == longitude && label == color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[0], - item[3], - colorMap, - ), - })); - } - if (latitude == longitude && label == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[3], - item[0], - colorMap, - ), - })); - } - if (latitude == size && label == color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[0], - item[3], - colorMap, - ), - })); - } - if (longitude === size && label === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[0], - item[3], - colorMap, - ), - })); - } - if (latitude === tooltip && label === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[0], - item[1], - colorMap, - ), - })); - } - if (longitude === tooltip && label === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[0], - item[2], - colorMap, - ), - })); - } - if (latitude === size && latitude === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[1], - item[3], - colorMap, - ), - })); - } - if (longitude === size && longitude === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[2], - item[3], - colorMap, - ), - })); - } - if (latitude === size && latitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[3], - item[1], - colorMap, - ), - })); - } - if (longitude === size && longitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[3], - item[2], - colorMap, - ), - })); - } - if (latitude === color && latitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[1], - item[1], - colorMap, - ), - })); - } - if (longitude === color && longitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[2], - item[2], - colorMap, - ), - })); - } - if (latitude === size && longitude === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[2], - item[3], - colorMap, - ), - })); - } - if (longitude === size && latitude === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[1], - item[3], - colorMap, - ), - })); - } - if (latitude === size && longitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[3], - item[2], - colorMap, - ), - })); - } - if (longitude === size && latitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[3], - item[1], - colorMap, - ), - })); - } - if (latitude === color && longitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[1], - item[2], - colorMap, - ), - })); - } - if (longitude === color && latitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[2], - item[1], - colorMap, - ), - })); - } - if (size === tooltip && label === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[0], - item[3], - colorMap, - ), - })); - } - if (latitude == longitude) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[3], - item[4], - colorMap, - ), - })); - } - if (label === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[0], - item[4], - colorMap, - ), - })); - } - if (size === label) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[4], - item[5], - colorMap, - ), - })); - } - if (tooltip === label) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[4], - item[5], - colorMap, - ), - })); - } - if (latitude === size) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[3], - item[4], - colorMap, - ), - })); - } - if (latitude === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[1], - item[4], - colorMap, - ), - })); - } - if (latitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[4], - item[1], - colorMap, - ), - })); - } - if (longitude === size) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[3], - item[4], - colorMap, - ), - })); - } - if (longitude === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[2], - item[4], - colorMap, - ), - })); - } - if (longitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[4], - item[2], - colorMap, - ), - })); - } - if (size === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[3], - item[4], - colorMap, - ), - })); - } - if (size === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[4], - item[3], - colorMap, - ), - })); - } - if (color === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[4], - item[4], - colorMap, - ), - })); - } - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[4], - item[5], - colorMap, - ), - })); - } - if (label && latitude && longitude && size && color) { - const colorMap = new Map(); - if ( - latitude == longitude && - latitude == size && - label == color - ) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[1], - item[1], - item[0], - colorMap, - ), - })); - } - if ( - latitude == longitude && - latitude == size && - latitude == color - ) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[1], - item[1], - item[1], - colorMap, - ), - })); - } - if (latitude == longitude && latitude == color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[1], - item[2], - item[1], - colorMap, - ), - })); - } - if (latitude == longitude && size == color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[1], - item[2], - item[2], - colorMap, - ), - })); - } - if (latitude == longitude && label == color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[1], - item[2], - item[0], - colorMap, - ), - })); - } - if (latitude == longitude && latitude == size) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[1], - item[1], - item[2], - colorMap, - ), - })); - } - if (latitude === size && latitude === color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[1], - item[1], - colorMap, - ), - })); - } - if (longitude === size && longitude === color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[2], - item[2], - colorMap, - ), - })); - } - if (latitude === size && longitude === color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[1], - item[2], - colorMap, - ), - })); - } - if (longitude === size && latitude === color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[2], - item[1], - colorMap, - ), - })); - } - if (latitude === size && label === color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[1], - item[0], - colorMap, - ), - })); - } - if (longitude === size && label === color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[2], - item[0], - colorMap, - ), - })); - } - if (latitude == longitude) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[1], - item[2], - item[3], - colorMap, - ), - })); - } - if (label === color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[3], - item[0], - colorMap, - ), - })); - } - if (size === color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[3], - item[3], - colorMap, - ), - })); - } - if (latitude === size) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[1], - item[3], - colorMap, - ), - })); - } - if (longitude === size) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[2], - item[3], - colorMap, - ), - })); - } - if (latitude === color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[3], - item[1], - colorMap, - ), - })); - } - if (longitude === color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[3], - item[2], - colorMap, - ), - })); - } - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[3], - item[4], - colorMap, - ), - })); - } - if (label && latitude && longitude && color && tooltip) { - const colorMap = new Map(); - if ( - latitude == longitude && - latitude == tooltip && - label == color - ) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[1], - item[0], - item[1], - colorMap, - ), - })); - } - if ( - latitude == longitude && - latitude == tooltip && - latitude == color - ) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[1], - item[1], - item[1], - colorMap, - ), - })); - } - if (latitude == longitude && latitude == color) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[1], - item[1], - item[2], - colorMap, - ), - })); - } - if (latitude == longitude && label == color) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[1], - item[0], - item[2], - colorMap, - ), - })); - } - if (latitude == longitude && latitude == tooltip) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[1], - item[2], - item[1], - colorMap, - ), - })); - } - if (latitude == color && latitude == tooltip) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[1], - item[1], - colorMap, - ), - })); - } - if (longitude === color && longitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[2], - item[2], - colorMap, - ), - })); - } - if (latitude === color && longitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[1], - item[1], - colorMap, - ), - })); - } - if (longitude === color && latitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[2], - item[1], - colorMap, - ), - })); - } - if (latitude === tooltip && label === color) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[0], - item[1], - colorMap, - ), - })); - } - if (longitude === tooltip && label === color) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[0], - item[2], - colorMap, - ), - })); - } - if (latitude == longitude) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[1], - item[2], - item[3], - colorMap, - ), - })); - } - if (label === color) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[0], - item[3], - colorMap, - ), - })); - } - if (color === tooltip) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[3], - item[3], - colorMap, - ), - })); - } - if (latitude === color) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[1], - item[3], - colorMap, - ), - })); - } - if (longitude === color) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[2], - item[3], - colorMap, - ), - })); - } - if (latitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[3], - item[1], - colorMap, - ), - })); - } - if (longitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[3], - item[2], - colorMap, - ), - })); - } - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[3], - item[4], - colorMap, - ), - })); - } - if (label && latitude && longitude && size && tooltip) { - if ( - latitude == longitude && - latitude == size && - latitude == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[1], - item[1], - item[1], - ), - })); - } - if (latitude == longitude && latitude == size) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[1], - item[1], - item[2], - ), - })); - } - if (latitude == longitude && latitude == tooltip) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[1], - item[2], - item[1], - ), - })); - } - if (latitude == longitude && size == tooltip) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[1], - item[2], - item[2], - ), - })); - } - if (latitude === size && latitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[2], - item[1], - item[1], - ), - })); - } - if (longitude === size && longitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[2], - item[2], - item[2], - ), - })); - } - if (latitude === size && longitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[2], - item[1], - item[2], - ), - })); - } - if (longitude === size && latitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[2], - item[2], - item[1], - ), - })); - } - if (latitude == longitude) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[1], - item[2], - item[3], - ), - })); - } - if (size === tooltip) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[2], - item[3], - item[3], - ), - })); - } - if (latitude === size) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[2], - item[1], - item[3], - ), - })); - } - if (longitude === size) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[2], - item[2], - item[3], - ), - })); - } - if (latitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[2], - item[3], - item[1], - ), - })); - } - if (longitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[2], - item[3], - item[2], - ), - })); - } - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[2], - item[4], - item[4], - ), - })); - } - if (label && latitude && longitude && color) { - const colorMap = new Map(); - if (latitude === longitude && latitude === color) { - return apiData.values.map((item) => ({ - ...formatColorDataItem( - item[0], - item[1], - item[1], - item[1], - colorMap, - ), - })); - } - if (latitude === longitude && label === color) { - return apiData.values.map((item) => ({ - ...formatColorDataItem( - item[0], - item[1], - item[1], - item[0], - colorMap, - ), - })); - } - if (latitude === longitude) { - return apiData.values.map((item) => ({ - ...formatColorDataItem( - item[0], - item[1], - item[1], - item[2], - colorMap, - ), - })); - } - if (latitude === color) { - return apiData.values.map((item) => ({ - ...formatColorDataItem( - item[0], - item[1], - item[2], - item[1], - colorMap, - ), - })); - } - if (longitude === color) { - return apiData.values.map((item) => ({ - ...formatColorDataItem( - item[0], - item[1], - item[2], - item[2], - colorMap, - ), - })); - } - if (label === color) { - return apiData.values.map((item) => ({ - ...formatColorDataItem( - item[0], - item[1], - item[2], - item[0], - colorMap, - ), - })); - } - return apiData.values.map((item, index) => ({ - ...formatColorDataItem( - item[0], - item[1], - item[2], - item[3], - colorMap, - ), - })); - } - if (label && latitude && longitude && size) { - if (latitude === longitude && latitude === size) { - return apiData.values.map((item) => ({ - ...formatSizeDataItem( - item[0], - item[1], - item[1], - item[1], - ), - })); - } - if (latitude === longitude) { - return apiData.values.map((item) => ({ - ...formatSizeDataItem( - item[0], - item[1], - item[1], - item[2], - ), - })); - } - if (latitude === size) { - return apiData.values.map((item) => ({ - ...formatSizeDataItem( - item[0], - item[1], - item[2], - item[1], - ), - })); - } - if (longitude === size) { - return apiData.values.map((item) => ({ - ...formatSizeDataItem( - item[0], - item[1], - item[2], - item[2], - ), - })); - } - return apiData.values.map((item) => ({ - ...formatSizeDataItem( - item[0], - item[1], - item[2], - item[3], - ), - })); - } - if (label && latitude && longitude && tooltip) { - if (latitude === longitude && latitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatTooltipDataItem( - item[0], - item[1], - item[1], - item[1], - ), - })); - } - if (latitude === longitude) { - return apiData.values.map((item) => ({ - ...formatTooltipDataItem( - item[0], - item[1], - item[1], - item[2], - ), - })); - } - if (latitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatTooltipDataItem( - item[0], - item[1], - item[2], - item[1], - ), - })); - } - if (longitude === tooltip) { - return apiData.values.map((item) => ({ - ...formatTooltipDataItem( - item[0], - item[1], - item[2], - item[2], - ), - })); - } - return apiData.values.map((item) => ({ - ...formatTooltipDataItem( - item[0], - item[1], - item[2], - item[3], - ), - })); - } - } - } - if (label && latitude && longitude) { - { - if (latitude === longitude) { - return apiData.values.map((item) => ({ - ...formatItem(item[0], item[1], item[1]), - })); - } - return apiData.values.map((item) => ({ - ...formatItem(item[0], item[1], item[2]), - })); - } - } - } + if (apiData["values"]) { + if (Object.hasOwn(data.option, "_state")) { + if (Object.hasOwn(data.option["_state"], "fields")) { + if ( + label && + latitude && + longitude && + size && + color && + tooltip + ) { + const colorMap = new Map(); + if ( + latitude === longitude && + latitude === size && + latitude === color && + latitude === tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[1], + item[1], + item[1], + colorMap, + ), + })); + } + if ( + latitude == longitude && + label == size && + label == color && + label == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[0], + item[0], + item[0], + colorMap, + ), + })); + } + if ( + latitude == longitude && + latitude == size && + label == color && + label == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[1], + item[0], + item[0], + colorMap, + ), + })); + } + if ( + latitude == longitude && + latitude == size && + label == color && + latitude == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[1], + item[0], + item[1], + colorMap, + ), + })); + } + if ( + latitude == longitude && + label == size && + latitude == color && + label == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[0], + item[1], + item[0], + colorMap, + ), + })); + } + if ( + latitude == longitude && + label == size && + label == color && + latitude == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[0], + item[0], + item[1], + colorMap, + ), + })); + } + if ( + latitude == longitude && + size == color && + size == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[2], + item[2], + colorMap, + ), + })); + } + if ( + latitude == longitude && + label == color && + size == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[0], + item[2], + colorMap, + ), + })); + } + if ( + latitude == longitude && + size == tooltip && + latitude == color + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[1], + item[2], + colorMap, + ), + })); + } + if ( + latitude == longitude && + size == color && + latitude == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[2], + item[1], + colorMap, + ), + })); + } + if ( + latitude === size && + latitude === color && + latitude === tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[1], + item[1], + colorMap, + ), + })); + } + if ( + longitude === size && + longitude === color && + longitude === tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[2], + item[2], + colorMap, + ), + })); + } + if ( + latitude === size && + latitude === color && + longitude === tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[1], + item[2], + colorMap, + ), + })); + } + if ( + latitude === size && + longitude === color && + latitude === tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[2], + item[1], + colorMap, + ), + })); + } + if ( + longitude === size && + latitude === color && + latitude === tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[1], + item[1], + colorMap, + ), + })); + } + if ( + longitude === size && + longitude === color && + latitude === tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[2], + item[1], + colorMap, + ), + })); + } + if ( + longitude === size && + latitude === color && + longitude === tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[1], + item[2], + colorMap, + ), + })); + } + if ( + latitude === size && + longitude === color && + longitude === tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[2], + item[2], + colorMap, + ), + })); + } + if ( + latitude === size && + latitude === tooltip && + label === color + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[0], + item[1], + colorMap, + ), + })); + } + if ( + longitude === size && + longitude === tooltip && + label === color + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[0], + item[2], + colorMap, + ), + })); + } + if ( + latitude === size && + longitude === tooltip && + label === color + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[0], + item[2], + colorMap, + ), + })); + } + if ( + longitude === size && + latitude === tooltip && + label === color + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[0], + item[1], + colorMap, + ), + })); + } + if ( + latitude == longitude && + label == size && + latitude == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[0], + item[2], + item[1], + colorMap, + ), + })); + } + if ( + latitude == longitude && + latitude == size && + latitude == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[1], + item[2], + item[1], + colorMap, + ), + })); + } + if ( + latitude == longitude && + label == color && + latitude == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[0], + item[1], + colorMap, + ), + })); + } + if ( + latitude == longitude && + label == size && + label == color + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[0], + item[0], + item[2], + colorMap, + ), + })); + } + if ( + latitude == longitude && + label == color && + label == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[0], + item[0], + colorMap, + ), + })); + } + if ( + latitude == longitude && + label == size && + label == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[0], + item[2], + item[0], + colorMap, + ), + })); + } + if ( + latitude == longitude && + latitude == size && + latitude == color + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[1], + item[1], + item[2], + colorMap, + ), + })); + } + if ( + latitude == longitude && + latitude == size && + latitude == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[1], + item[2], + item[1], + colorMap, + ), + })); + } + if ( + latitude == longitude && + latitude == color && + latitude == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[1], + item[1], + colorMap, + ), + })); + } + if ( + latitude === longitude && + latitude === size && + label === color + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[1], + item[0], + item[2], + colorMap, + ), + })); + } + if (size == color && latitude == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[3], + item[1], + colorMap, + ), + })); + } + if (size == color && longitude == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[3], + item[2], + colorMap, + ), + })); + } + if (size == color && longitude == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[3], + item[2], + colorMap, + ), + })); + } + if (size == color && size == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[3], + item[3], + colorMap, + ), + })); + } + if (size == tooltip && latitude == color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[1], + item[3], + colorMap, + ), + })); + } + if (size == tooltip && longitude == color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[2], + item[3], + colorMap, + ), + })); + } + if (latitude == longitude && latitude == size) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[1], + item[2], + item[3], + colorMap, + ), + })); + } + if (latitude == longitude && latitude == color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[1], + item[3], + colorMap, + ), + })); + } + if (latitude == longitude && size == color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[2], + item[3], + colorMap, + ), + })); + } + if (latitude == longitude && latitude == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[3], + item[1], + colorMap, + ), + })); + } + if (latitude == longitude && size == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[3], + item[2], + colorMap, + ), + })); + } + if (latitude == longitude && label == size) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[0], + item[2], + item[3], + colorMap, + ), + })); + } + if (latitude == longitude && label == color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[0], + item[3], + colorMap, + ), + })); + } + if (latitude == longitude && label == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[3], + item[0], + colorMap, + ), + })); + } + if (latitude == size && label == color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[0], + item[3], + colorMap, + ), + })); + } + if (longitude === size && label === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[0], + item[3], + colorMap, + ), + })); + } + if (latitude === tooltip && label === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[0], + item[1], + colorMap, + ), + })); + } + if (longitude === tooltip && label === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[0], + item[2], + colorMap, + ), + })); + } + if (latitude === size && latitude === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[1], + item[3], + colorMap, + ), + })); + } + if (longitude === size && longitude === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[2], + item[3], + colorMap, + ), + })); + } + if (latitude === size && latitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[3], + item[1], + colorMap, + ), + })); + } + if (longitude === size && longitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[3], + item[2], + colorMap, + ), + })); + } + if (latitude === color && latitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[1], + item[1], + colorMap, + ), + })); + } + if (longitude === color && longitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[2], + item[2], + colorMap, + ), + })); + } + if (latitude === size && longitude === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[2], + item[3], + colorMap, + ), + })); + } + if (longitude === size && latitude === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[1], + item[3], + colorMap, + ), + })); + } + if (latitude === size && longitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[3], + item[2], + colorMap, + ), + })); + } + if (longitude === size && latitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[3], + item[1], + colorMap, + ), + })); + } + if (latitude === color && longitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[1], + item[2], + colorMap, + ), + })); + } + if (longitude === color && latitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[2], + item[1], + colorMap, + ), + })); + } + if (size === tooltip && label === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[0], + item[3], + colorMap, + ), + })); + } + if (latitude == longitude) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[3], + item[4], + colorMap, + ), + })); + } + if (label === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[0], + item[4], + colorMap, + ), + })); + } + if (size === label) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[4], + item[5], + colorMap, + ), + })); + } + if (tooltip === label) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[4], + item[5], + colorMap, + ), + })); + } + if (latitude === size) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[3], + item[4], + colorMap, + ), + })); + } + if (latitude === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[1], + item[4], + colorMap, + ), + })); + } + if (latitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[4], + item[1], + colorMap, + ), + })); + } + if (longitude === size) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[3], + item[4], + colorMap, + ), + })); + } + if (longitude === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[2], + item[4], + colorMap, + ), + })); + } + if (longitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[4], + item[2], + colorMap, + ), + })); + } + if (size === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[3], + item[4], + colorMap, + ), + })); + } + if (size === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[4], + item[3], + colorMap, + ), + })); + } + if (color === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[4], + item[4], + colorMap, + ), + })); + } + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[4], + item[5], + colorMap, + ), + })); + } + if (label && latitude && longitude && size && color) { + const colorMap = new Map(); + if ( + latitude == longitude && + latitude == size && + label == color + ) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[1], + item[1], + item[0], + colorMap, + ), + })); + } + if ( + latitude == longitude && + latitude == size && + latitude == color + ) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[1], + item[1], + item[1], + colorMap, + ), + })); + } + if (latitude == longitude && latitude == color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[1], + item[2], + item[1], + colorMap, + ), + })); + } + if (latitude == longitude && size == color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[1], + item[2], + item[2], + colorMap, + ), + })); + } + if (latitude == longitude && label == color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[1], + item[2], + item[0], + colorMap, + ), + })); + } + if (latitude == longitude && latitude == size) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[1], + item[1], + item[2], + colorMap, + ), + })); + } + if (latitude === size && latitude === color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[1], + item[1], + colorMap, + ), + })); + } + if (longitude === size && longitude === color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[2], + item[2], + colorMap, + ), + })); + } + if (latitude === size && longitude === color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[1], + item[2], + colorMap, + ), + })); + } + if (longitude === size && latitude === color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[2], + item[1], + colorMap, + ), + })); + } + if (latitude === size && label === color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[1], + item[0], + colorMap, + ), + })); + } + if (longitude === size && label === color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[2], + item[0], + colorMap, + ), + })); + } + if (latitude == longitude) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[1], + item[2], + item[3], + colorMap, + ), + })); + } + if (label === color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[3], + item[0], + colorMap, + ), + })); + } + if (size === color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[3], + item[3], + colorMap, + ), + })); + } + if (latitude === size) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[1], + item[3], + colorMap, + ), + })); + } + if (longitude === size) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[2], + item[3], + colorMap, + ), + })); + } + if (latitude === color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[3], + item[1], + colorMap, + ), + })); + } + if (longitude === color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[3], + item[2], + colorMap, + ), + })); + } + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[3], + item[4], + colorMap, + ), + })); + } + if (label && latitude && longitude && color && tooltip) { + const colorMap = new Map(); + if ( + latitude == longitude && + latitude == tooltip && + label == color + ) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[1], + item[0], + item[1], + colorMap, + ), + })); + } + if ( + latitude == longitude && + latitude == tooltip && + latitude == color + ) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[1], + item[1], + item[1], + colorMap, + ), + })); + } + if (latitude == longitude && latitude == color) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[1], + item[1], + item[2], + colorMap, + ), + })); + } + if (latitude == longitude && label == color) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[1], + item[0], + item[2], + colorMap, + ), + })); + } + if (latitude == longitude && latitude == tooltip) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[1], + item[2], + item[1], + colorMap, + ), + })); + } + if (latitude == color && latitude == tooltip) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[1], + item[1], + colorMap, + ), + })); + } + if (longitude === color && longitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[2], + item[2], + colorMap, + ), + })); + } + if (latitude === color && longitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[1], + item[1], + colorMap, + ), + })); + } + if (longitude === color && latitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[2], + item[1], + colorMap, + ), + })); + } + if (latitude === tooltip && label === color) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[0], + item[1], + colorMap, + ), + })); + } + if (longitude === tooltip && label === color) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[0], + item[2], + colorMap, + ), + })); + } + if (latitude == longitude) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[1], + item[2], + item[3], + colorMap, + ), + })); + } + if (label === color) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[0], + item[3], + colorMap, + ), + })); + } + if (color === tooltip) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[3], + item[3], + colorMap, + ), + })); + } + if (latitude === color) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[1], + item[3], + colorMap, + ), + })); + } + if (longitude === color) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[2], + item[3], + colorMap, + ), + })); + } + if (latitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[3], + item[1], + colorMap, + ), + })); + } + if (longitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[3], + item[2], + colorMap, + ), + })); + } + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[3], + item[4], + colorMap, + ), + })); + } + if (label && latitude && longitude && size && tooltip) { + if ( + latitude == longitude && + latitude == size && + latitude == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[1], + item[1], + item[1], + ), + })); + } + if (latitude == longitude && latitude == size) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[1], + item[1], + item[2], + ), + })); + } + if (latitude == longitude && latitude == tooltip) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[1], + item[2], + item[1], + ), + })); + } + if (latitude == longitude && size == tooltip) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[1], + item[2], + item[2], + ), + })); + } + if (latitude === size && latitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[2], + item[1], + item[1], + ), + })); + } + if (longitude === size && longitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[2], + item[2], + item[2], + ), + })); + } + if (latitude === size && longitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[2], + item[1], + item[2], + ), + })); + } + if (longitude === size && latitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[2], + item[2], + item[1], + ), + })); + } + if (latitude == longitude) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[1], + item[2], + item[3], + ), + })); + } + if (size === tooltip) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[2], + item[3], + item[3], + ), + })); + } + if (latitude === size) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[2], + item[1], + item[3], + ), + })); + } + if (longitude === size) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[2], + item[2], + item[3], + ), + })); + } + if (latitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[2], + item[3], + item[1], + ), + })); + } + if (longitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[2], + item[3], + item[2], + ), + })); + } + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[2], + item[4], + item[4], + ), + })); + } + if (label && latitude && longitude && color) { + const colorMap = new Map(); + if (latitude === longitude && latitude === color) { + return apiData.values.map((item) => ({ + ...formatColorDataItem( + item[0], + item[1], + item[1], + item[1], + colorMap, + ), + })); + } + if (latitude === longitude && label === color) { + return apiData.values.map((item) => ({ + ...formatColorDataItem( + item[0], + item[1], + item[1], + item[0], + colorMap, + ), + })); + } + if (latitude === longitude) { + return apiData.values.map((item) => ({ + ...formatColorDataItem( + item[0], + item[1], + item[1], + item[2], + colorMap, + ), + })); + } + if (latitude === color) { + return apiData.values.map((item) => ({ + ...formatColorDataItem( + item[0], + item[1], + item[2], + item[1], + colorMap, + ), + })); + } + if (longitude === color) { + return apiData.values.map((item) => ({ + ...formatColorDataItem( + item[0], + item[1], + item[2], + item[2], + colorMap, + ), + })); + } + if (label === color) { + return apiData.values.map((item) => ({ + ...formatColorDataItem( + item[0], + item[1], + item[2], + item[0], + colorMap, + ), + })); + } + return apiData.values.map((item, index) => ({ + ...formatColorDataItem( + item[0], + item[1], + item[2], + item[3], + colorMap, + ), + })); + } + if (label && latitude && longitude && size) { + if (latitude === longitude && latitude === size) { + return apiData.values.map((item) => ({ + ...formatSizeDataItem( + item[0], + item[1], + item[1], + item[1], + ), + })); + } + if (latitude === longitude) { + return apiData.values.map((item) => ({ + ...formatSizeDataItem( + item[0], + item[1], + item[1], + item[2], + ), + })); + } + if (latitude === size) { + return apiData.values.map((item) => ({ + ...formatSizeDataItem( + item[0], + item[1], + item[2], + item[1], + ), + })); + } + if (longitude === size) { + return apiData.values.map((item) => ({ + ...formatSizeDataItem( + item[0], + item[1], + item[2], + item[2], + ), + })); + } + return apiData.values.map((item) => ({ + ...formatSizeDataItem( + item[0], + item[1], + item[2], + item[3], + ), + })); + } + if (label && latitude && longitude && tooltip) { + if (latitude === longitude && latitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatTooltipDataItem( + item[0], + item[1], + item[1], + item[1], + ), + })); + } + if (latitude === longitude) { + return apiData.values.map((item) => ({ + ...formatTooltipDataItem( + item[0], + item[1], + item[1], + item[2], + ), + })); + } + if (latitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatTooltipDataItem( + item[0], + item[1], + item[2], + item[1], + ), + })); + } + if (longitude === tooltip) { + return apiData.values.map((item) => ({ + ...formatTooltipDataItem( + item[0], + item[1], + item[2], + item[2], + ), + })); + } + return apiData.values.map((item) => ({ + ...formatTooltipDataItem( + item[0], + item[1], + item[2], + item[3], + ), + })); + } + } + } + if (label && latitude && longitude) { + if (latitude === longitude) { + return apiData.values.map((item) => ({ + ...formatItem(item[0], item[1], item[1]), + })); + } + return apiData.values.map((item) => ({ + ...formatItem(item[0], item[1], item[2]), + })); + } + } }; diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/map-chart/MapChartTooltipData.ts b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/map-chart/MapChartTooltipData.ts index 448c7f167a..3f43b4124b 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/map-chart/MapChartTooltipData.ts +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/map-chart/MapChartTooltipData.ts @@ -1,1135 +1,1135 @@ export const formatdatapoints = (apiData, data) => { - let fields = "", - label = "", - latitude = "", - longitude = "", - size = "", - color = "", - tooltip = ""; - if (data.option.hasOwnProperty("_state")) { - fields = data.option["_state"]["fields"]; - label = fields["label"]; - latitude = fields["Latitude"]; - longitude = fields["Longitude"]; - size = fields["size"]; - color = fields["color"]; - tooltip = fields["tooltip"]; - } - const getSelectorType = (type) => { - return fields[type] === "NUMBER" ? "Average of" : "Count of"; - }; - const getSelectors = () => { - return { - latitude: "Coordinates:", - longitude: getSelectorType("LongitudeDataType"), - size: getSelectorType("sizeDataType"), - tooltip: getSelectorType("tooltipDataType"), - color: "Unique Group Concat of", - }; - }; - const selectors = getSelectors(); - const getToolTipContent = (color, Data, apiData) => { - return ` + let fields = "", + label = "", + latitude = "", + longitude = "", + size = "", + color = "", + tooltip = ""; + if (Object.hasOwn(data.option, "_state")) { + fields = data.option["_state"]["fields"]; + label = fields["label"]; + latitude = fields["Latitude"]; + longitude = fields["Longitude"]; + size = fields["size"]; + color = fields["color"]; + tooltip = fields["tooltip"]; + } + const getSelectorType = (type) => { + return fields[type] === "NUMBER" ? "Average of" : "Count of"; + }; + const getSelectors = () => { + return { + latitude: "Coordinates:", + longitude: getSelectorType("LongitudeDataType"), + size: getSelectorType("sizeDataType"), + tooltip: getSelectorType("tooltipDataType"), + color: "Unique Group Concat of", + }; + }; + const selectors = getSelectors(); + const getToolTipContent = (color, Data, apiData) => { + return `
\u25CF ${Data.label.formatter.toString()}
${selectors.latitude} ${Data.value[0]},${Data.value[1]}
`; - }; - if (apiData["values"]) { - if (data.option.hasOwnProperty("_state")) { - if (data.option["_state"].hasOwnProperty("fields")) { - if ( - label && - latitude && - longitude && - size && - color && - tooltip - ) { - return function (params) { - const { data: Data, color: Color } = params; - if ( - latitude == longitude && - latitude == size && - latitude == color && - latitude == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
+ }; + if (apiData["values"]) { + if (Object.hasOwn(data.option, "_state")) { + if (Object.hasOwn(data.option["_state"], "fields")) { + if ( + label && + latitude && + longitude && + size && + color && + tooltip + ) { + return (params) => { + const { data: Data, color: Color } = params; + if ( + latitude == longitude && + latitude == size && + latitude == color && + latitude == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - latitude == longitude && - label == size && - label == color && - label == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
+ ); + } + if ( + latitude == longitude && + label == size && + label == color && + label == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - latitude == longitude && - latitude == size && - label == color && - label == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
+ ); + } + if ( + latitude == longitude && + latitude == size && + label == color && + label == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - latitude == longitude && - latitude == size && - label == color && - latitude == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - ` + ); + } + if ( + latitude == longitude && + latitude == size && + label == color && + latitude == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - latitude == longitude && - label == size && - latitude == color && - label == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
+ ); + } + if ( + latitude == longitude && + label == size && + latitude == color && + label == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - latitude == longitude && - label == size && - label == color && - latitude == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
+ ); + } + if ( + latitude == longitude && + label == size && + label == color && + latitude == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - latitude == longitude && - (size == color || label == color) && - size == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
+ ); + } + if ( + latitude == longitude && + (size == color || label == color) && + size == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - latitude === size && - latitude === color && - latitude === tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.value[0]}
` - ); - } - if ( - longitude === size && - longitude === color && - longitude === tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.value[1]}
` - ); - } - if ( - latitude === size && - latitude === color && - longitude === tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.value[0]}
` - ); - } - if ( - latitude === size && - longitude === color && - latitude === tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.value[1]}
` - ); - } - if ( - longitude === size && - latitude === color && - latitude === tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.value[0]}
` - ); - } - if ( - longitude === size && - longitude === color && - latitude === tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.value[1]}
` - ); - } - if ( - longitude === size && - latitude === color && - longitude === tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.value[0]}
` - ); - } - if ( - latitude === size && - longitude === color && - longitude === tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.value[1]}
` - ); - } - if ( - latitude === size && - latitude === tooltip && - label === color - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - longitude === size && - longitude === tooltip && - label === color - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - latitude === size && - longitude === tooltip && - label === color - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - longitude === size && - latitude === tooltip && - label === color - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - latitude == longitude && - (label == size || latitude == size) && - latitude == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
+ ); + } + if ( + latitude === size && + latitude === color && + latitude === tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.value[0]}
` + ); + } + if ( + longitude === size && + longitude === color && + longitude === tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.value[1]}
` + ); + } + if ( + latitude === size && + latitude === color && + longitude === tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.value[0]}
` + ); + } + if ( + latitude === size && + longitude === color && + latitude === tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.value[1]}
` + ); + } + if ( + longitude === size && + latitude === color && + latitude === tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.value[0]}
` + ); + } + if ( + longitude === size && + longitude === color && + latitude === tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.value[1]}
` + ); + } + if ( + longitude === size && + latitude === color && + longitude === tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.value[0]}
` + ); + } + if ( + latitude === size && + longitude === color && + longitude === tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.value[1]}
` + ); + } + if ( + latitude === size && + latitude === tooltip && + label === color + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if ( + longitude === size && + longitude === tooltip && + label === color + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if ( + latitude === size && + longitude === tooltip && + label === color + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if ( + longitude === size && + latitude === tooltip && + label === color + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if ( + latitude == longitude && + (label == size || latitude == size) && + latitude == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - latitude == longitude && - label == color && - latitude == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
+ ); + } + if ( + latitude == longitude && + label == color && + latitude == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - latitude == longitude && - label == size && - label == color - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
+ ); + } + if ( + latitude == longitude && + label == size && + label == color + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - latitude === longitude && - latitude === size && - label === color - ) { - return ( - getToolTipContent(Color, Data, apiData) + - ` + ); + } + if ( + latitude === longitude && + latitude === size && + label === color + ) { + return ( + getToolTipContent(Color, Data, apiData) + + ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - latitude == longitude && - label == color && - label == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + - ` ${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - latitude == longitude && - label == size && - label == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + - ` ${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - latitude == longitude && - latitude == size && - latitude == color - ) { - return ( - getToolTipContent(Color, Data, apiData) + - ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
+ ); + } + if ( + latitude == longitude && + label == color && + label == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + + ` ${tooltip}: ${Data.tooltipValue}
` + ); + } + if ( + latitude == longitude && + label == size && + label == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + + ` ${tooltip}: ${Data.tooltipValue}
` + ); + } + if ( + latitude == longitude && + latitude == size && + latitude == color + ) { + return ( + getToolTipContent(Color, Data, apiData) + + ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - latitude == longitude && - latitude == size && - latitude == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - latitude == longitude && - latitude == color && - latitude == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
+ ); + } + if ( + latitude == longitude && + latitude == size && + latitude == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if ( + latitude == longitude && + latitude == color && + latitude == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - (size == color && latitude == tooltip) || - longitude == tooltip || - (size == color && size == tooltip) || - (size == tooltip && latitude == color) || - longitude == color - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (latitude == longitude && latitude == size) { - return ( - getToolTipContent(Color, Data, apiData) + - ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
+ ); + } + if ( + (size == color && latitude == tooltip) || + longitude == tooltip || + (size == color && size == tooltip) || + (size == tooltip && latitude == color) || + longitude == color + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (latitude == longitude && latitude == size) { + return ( + getToolTipContent(Color, Data, apiData) + + ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - (latitude == longitude && latitude == color) || - size == color - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
+ ); + } + if ( + (latitude == longitude && latitude == color) || + size == color + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - (latitude == longitude && latitude == tooltip) || - size == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
+ ); + } + if ( + (latitude == longitude && latitude == tooltip) || + size == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (latitude == longitude && label == size) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
+ ); + } + if (latitude == longitude && label == size) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${tooltip}: ${Data.tooltipValue}
` - ); - } - if (latitude == longitude && label == color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
+ ); + } + if (latitude == longitude && label == color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${tooltip}: ${Data.tooltipValue}
` - ); - } - if (latitude == longitude && label == tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
+ ); + } + if (latitude == longitude && label == tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${tooltip}: ${Data.tooltipValue}
` - ); - } + ); + } - if (latitude === size && label === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + - ` ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (longitude === size && label === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + - ` ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (latitude === tooltip && label === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (longitude === tooltip && label === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (latitude === size && latitude === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
+ if (latitude === size && label === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + + ` ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (longitude === size && label === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + + ` ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (latitude === tooltip && label === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (longitude === tooltip && label === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (latitude === size && latitude === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${tooltip}: ${Data.tooltipValue}
` - ); - } - if (longitude === size && longitude === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
+ ); + } + if (longitude === size && longitude === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${tooltip}: ${Data.tooltipValue}
` - ); - } - if (latitude === size && latitude === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (longitude === size && longitude === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (latitude === color && latitude === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
+ ); + } + if (latitude === size && latitude === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (longitude === size && longitude === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (latitude === color && latitude === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (longitude === color && longitude === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (latitude === size && longitude === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + - ` ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (longitude === size && latitude === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + - ` ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (latitude === size && longitude === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (longitude === size && latitude === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (latitude === color && longitude === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (longitude === color && latitude === tooltip) { - return ` + ); + } + if (longitude === color && longitude === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (latitude === size && longitude === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + + ` ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (longitude === size && latitude === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + + ` ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (latitude === size && longitude === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (longitude === size && latitude === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (latitude === color && longitude === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (longitude === color && latitude === tooltip) { + return ` ${getToolTipContent(Color, Data, apiData)} ${selectors.longitude} ${apiData.headers[2]}: ${ - Data.value[1] - }
+ Data.value[1] + }
${selectors.size} ${size}: ${ - Data.tempSymbolSize - }
+ Data.tempSymbolSize + }
${selectors.color} ${color}: ${ - Data.itemStyle.colorValue - }
+ Data.itemStyle.colorValue + }
`; - } - if (size === tooltip && label === color) { - return ` + } + if (size === tooltip && label === color) { + return ` ${getToolTipContent(Color, Data, apiData)} ${selectors.longitude} ${apiData.headers[2]}: ${ - Data.value[1] - }
+ Data.value[1] + }
${selectors.size} ${size}: ${ - Data.tempSymbolSize - }
+ Data.tempSymbolSize + }
${selectors.color} ${color}: ${ - Data.itemStyle.colorValue - }
+ Data.itemStyle.colorValue + }
`; - } - if (latitude == longitude) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + - ` ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (label === color) { - return ` + } + if (latitude == longitude) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + + ` ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (label === color) { + return ` ${getToolTipContent(Color, Data, apiData)} ${selectors.longitude} ${apiData.headers[2]}: ${ - Data.value[1] - }
+ Data.value[1] + }
${selectors.size} ${size}: ${ - Data.tempSymbolSize - }
+ Data.tempSymbolSize + }
${selectors.color} ${color}: ${ - Data.itemStyle.colorValue - }
+ Data.itemStyle.colorValue + }
${tooltip}: ${Data.tooltipValue}
`; - } - if (size === label) { - return ` + } + if (size === label) { + return ` ${getToolTipContent(Color, Data, apiData)} ${selectors.longitude} ${apiData.headers[2]}: ${ - Data.value[1] - }
+ Data.value[1] + }
${selectors.size} ${size}: ${ - Data.tempSymbolSize - }
+ Data.tempSymbolSize + }
${selectors.color} ${color}: ${ - Data.itemStyle.colorValue - }
+ Data.itemStyle.colorValue + }
${tooltip}: ${Data.tooltipValue}
`; - } - if (tooltip === label) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + - ` ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (latitude === size) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
+ } + if (tooltip === label) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + + ` ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (latitude === size) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${tooltip}: ${Data.tooltipValue}
` - ); - } - if (latitude === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
+ ); + } + if (latitude === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
${selectors.color} ${color}: ${Data.value[0]}
${tooltip}: ${Data.tooltipValue}
` - ); - } - if (latitude === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (longitude === size) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + - ` ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (longitude === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + - `${selectors.color} ${color}: ${Data.value[1]}
` + - ` ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (longitude === tooltip) { - return ` + ); + } + if (latitude === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (longitude === size) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + + ` ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (longitude === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + + `${selectors.color} ${color}: ${Data.value[1]}
` + + ` ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (longitude === tooltip) { + return ` ${getToolTipContent(Color, Data, apiData)} ${selectors.longitude} ${apiData.headers[2]}: ${ - Data.value[1] - }
+ Data.value[1] + }
${selectors.size} ${size}: ${ - Data.tempSymbolSize - }
+ Data.tempSymbolSize + }
${selectors.color} ${color}: ${ - Data.itemStyle.colorValue - }
+ Data.itemStyle.colorValue + }
`; - } - if (size === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + - `${selectors.color} ${color}: ${Data.tempSymbolSize}
` + - ` ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (size === tooltip) { - return ` + } + if (size === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + + `${selectors.color} ${color}: ${Data.tempSymbolSize}
` + + ` ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (size === tooltip) { + return ` ${getToolTipContent(Color, Data, apiData)} ${selectors.longitude} ${apiData.headers[2]}: ${ - Data.value[1] - }
+ Data.value[1] + }
${selectors.size} ${size}: ${ - Data.tempSymbolSize - }
+ Data.tempSymbolSize + }
${selectors.color} ${color}: ${ - Data.itemStyle.colorValue - }
+ Data.itemStyle.colorValue + }
`; - } - if (color === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
+ } + if (color === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + - `${selectors.color} ${apiData.headers[4]}: ${Data.itemStyle.colorValue}
` + - ` ${apiData.headers[5]}: ${Data.tooltipValue}
` - ); - }; - } - if (label && latitude && longitude && size && color) { - return function (params) { - const { data: Data, color: Color } = params; - if ( - latitude == longitude && - latitude == size && - (latitude == color || latitude == color) - ) { - return ( - getToolTipContent(Color, Data, apiData) + - ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - latitude == longitude && - (latitude == color || size == color) - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
+ ); + } + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + + `${selectors.color} ${apiData.headers[4]}: ${Data.itemStyle.colorValue}
` + + ` ${apiData.headers[5]}: ${Data.tooltipValue}
` + ); + }; + } + if (label && latitude && longitude && size && color) { + return (params) => { + const { data: Data, color: Color } = params; + if ( + latitude == longitude && + latitude == size && + (latitude == color || latitude == color) + ) { + return ( + getToolTipContent(Color, Data, apiData) + + ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if ( + latitude == longitude && + (latitude == color || size == color) + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (latitude == longitude && label == color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (latitude == longitude && latitude == size) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (latitude === size && latitude === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.value[0]}
` - ); - } - if (longitude === size && longitude === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.value[1]}
` - ); - } - if (latitude === size && longitude === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.value[0]}
` - ); - } - if (longitude === size && latitude === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.value[0]}
` - ); - } - if (latitude === size && label === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (longitude === size && label === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (latitude == longitude) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
+ ); + } + if (latitude == longitude && label == color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (latitude == longitude && latitude == size) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (latitude === size && latitude === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.value[0]}
` + ); + } + if (longitude === size && longitude === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.value[1]}
` + ); + } + if (latitude === size && longitude === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.value[0]}
` + ); + } + if (longitude === size && latitude === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.value[0]}
` + ); + } + if (latitude === size && label === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (longitude === size && label === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (latitude == longitude) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (label === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + - `${selectors.color} ${data.option["_state"]["fields"]["color"]}: ${Data.itemStyle.colorValue}
` - ); - } - if (size === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (latitude === size) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (longitude === size) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (latitude === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
+ ); + } + if (label === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + + `${selectors.color} ${data.option["_state"]["fields"]["color"]}: ${Data.itemStyle.colorValue}
` + ); + } + if (size === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (latitude === size) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (longitude === size) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (latitude === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (longitude === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + - `${selectors.color} ${apiData.headers[4]}: ${Data.itemStyle.colorValue}
` - ); - }; - } - if (label && latitude && longitude && color && tooltip) { - return function (params) { - const { data: Data, color: Color } = params; - if ( - latitude == longitude && - (latitude == color || label == color) && - latitude == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - latitude == longitude && - (latitude == color || label == color) - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
+ ); + } + if (longitude === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + + `${selectors.color} ${apiData.headers[4]}: ${Data.itemStyle.colorValue}
` + ); + }; + } + if (label && latitude && longitude && color && tooltip) { + return (params) => { + const { data: Data, color: Color } = params; + if ( + latitude == longitude && + (latitude == color || label == color) && + latitude == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if ( + latitude == longitude && + (latitude == color || label == color) + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${tooltip}: ${Data.tooltipValue}
` - ); - } - if (latitude == longitude && latitude == tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}` - ); - } - if (latitude === color && latitude === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.value[0]}
` - ); - } - if (longitude === color && longitude === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.value[1]}
` - ); - } - if (latitude === color && longitude === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.value[0]}
` - ); - } - if (longitude === color && latitude === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.value[1]}
` - ); - } - if (latitude === tooltip && label === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${tooltip}: ${Data.itemStyle.colorValue}
` - ); - } - if (longitude === tooltip && label === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${tooltip}: ${Data.itemStyle.colorValue}
` - ); - } - if (latitude == longitude) { - return ( - getToolTipContent(Color, Data, apiData) + - ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
+ ); + } + if (latitude == longitude && latitude == tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}` + ); + } + if (latitude === color && latitude === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.value[0]}
` + ); + } + if (longitude === color && longitude === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.value[1]}
` + ); + } + if (latitude === color && longitude === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.value[0]}
` + ); + } + if (longitude === color && latitude === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.value[1]}
` + ); + } + if (latitude === tooltip && label === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${tooltip}: ${Data.itemStyle.colorValue}
` + ); + } + if (longitude === tooltip && label === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${tooltip}: ${Data.itemStyle.colorValue}
` + ); + } + if (latitude == longitude) { + return ( + getToolTipContent(Color, Data, apiData) + + ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${tooltip}: ${Data.tooltipValue}
` - ); - } - if (label === color) { - return ( - getToolTipContent(Color, Data, apiData) + - ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
+ ); + } + if (label === color) { + return ( + getToolTipContent(Color, Data, apiData) + + ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${tooltip}: ${Data.tooltipValue}
` - ); - } - if (color === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (latitude === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.value[0]}
${tooltip}: ${Data.tooltipValue}
` - ); - } - if (longitude === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.value[1]}
${tooltip}: ${Data.tooltipValue}
` - ); - } - if (latitude === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (longitude === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${apiData.headers[3]}: ${Data.itemStyle.colorValue}
` + - ` ${apiData.headers[4]}: ${Data.tooltipValue}
` - ); - }; - } - if (label && latitude && longitude && size && tooltip) { - return function (params) { - const { data: Data, color: Color } = params; - if ( - latitude == longitude && - latitude == size && - latitude == tooltip - ) { - return getToolTipContent(Color, Data, apiData); - } - if (latitude == longitude && latitude == size) { - return ( - getToolTipContent(Color, Data, apiData) + - `${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - (latitude == longitude && latitude == tooltip) || - size == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` - ); - } - if (latitude === size && latitude === tooltip) { - return getToolTipContent(Color, Data, apiData); - } - if (longitude === size && longitude === tooltip) { - return getToolTipContent(Color, Data, apiData); - } - if (latitude === size && longitude === tooltip) { - return getToolTipContent(Color, Data, apiData); - } - if (longitude === size && latitude === tooltip) { - return getToolTipContent(Color, Data, apiData); - } - if (latitude == longitude) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + - ` ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (size === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` - ); - } - if (latitude === size) { - return ( - getToolTipContent(Color, Data, apiData) + - `${tooltip}: ${Data.value[0]}
` - ); - } - if (longitude === size) { - return ( - getToolTipContent(Color, Data, apiData) + - `${tooltip}: ${Data.tooltipValue}
` - ); - } - if (latitude === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` - ); - } - if (longitude === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` - ); - } - return ` + ); + } + if (color === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (latitude === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.value[0]}
${tooltip}: ${Data.tooltipValue}
` + ); + } + if (longitude === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.value[1]}
${tooltip}: ${Data.tooltipValue}
` + ); + } + if (latitude === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (longitude === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${apiData.headers[3]}: ${Data.itemStyle.colorValue}
` + + ` ${apiData.headers[4]}: ${Data.tooltipValue}
` + ); + }; + } + if (label && latitude && longitude && size && tooltip) { + return (params) => { + const { data: Data, color: Color } = params; + if ( + latitude == longitude && + latitude == size && + latitude == tooltip + ) { + return getToolTipContent(Color, Data, apiData); + } + if (latitude == longitude && latitude == size) { + return ( + getToolTipContent(Color, Data, apiData) + + `${tooltip}: ${Data.tooltipValue}
` + ); + } + if ( + (latitude == longitude && latitude == tooltip) || + size == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + ); + } + if (latitude === size && latitude === tooltip) { + return getToolTipContent(Color, Data, apiData); + } + if (longitude === size && longitude === tooltip) { + return getToolTipContent(Color, Data, apiData); + } + if (latitude === size && longitude === tooltip) { + return getToolTipContent(Color, Data, apiData); + } + if (longitude === size && latitude === tooltip) { + return getToolTipContent(Color, Data, apiData); + } + if (latitude == longitude) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + + ` ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (size === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + ); + } + if (latitude === size) { + return ( + getToolTipContent(Color, Data, apiData) + + `${tooltip}: ${Data.value[0]}
` + ); + } + if (longitude === size) { + return ( + getToolTipContent(Color, Data, apiData) + + `${tooltip}: ${Data.tooltipValue}
` + ); + } + if (latitude === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + ); + } + if (longitude === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + ); + } + return ` ${getToolTipContent(Color, Data, apiData)} ${selectors.longitude} ${apiData.headers[2]}: ${ - Data.value[1] - }
+ Data.value[1] + }
${selectors.size} ${apiData.headers[3]}: ${ - Data.tempSymbolSize - }
+ Data.tempSymbolSize + }
${apiData.headers[4]}: ${Data.tooltipValue}
`; - }; - } - if (label && latitude && longitude && color) { - return function (params) { - const { data: Data, color: Color } = params; - if ( - latitude == longitude && - (latitude == color || label == color) - ) { - return ` + }; + } + if (label && latitude && longitude && color) { + return (params) => { + const { data: Data, color: Color } = params; + if ( + latitude == longitude && + (latitude == color || label == color) + ) { + return ` ${getToolTipContent(Color, Data, apiData)} ${selectors.color} ${color}: ${ - Data.itemStyle.colorValue - }
+ Data.itemStyle.colorValue + }
`; - } - if (latitude == longitude) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (latitude === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.value[0]}
` - ); - } - if (longitude === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.value[1]}
` - ); - } - if (label == color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${apiData.headers[3]}: ${Data.itemStyle.colorValue}
` - ); - }; - } - if (label && latitude && longitude && size) { - return function (params) { - const { data: Data, color: Color } = params; - if (latitude == longitude && latitude == size) { - return getToolTipContent(Color, Data, apiData); - } - if (latitude == longitude) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.tempSymbolSize}
` - ); - } - if (latitude == size) { - return getToolTipContent(Color, Data, apiData); - } - if (longitude == size) { - return getToolTipContent(Color, Data, apiData); - } - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${apiData.headers[3]}: ${Data.tempSymbolSize}
` - ); - }; - } - if (label && latitude && longitude && tooltip) { - return function (params) { - const { data: Data, color: Color } = params; - if (latitude == longitude && latitude == tooltip) { - return getToolTipContent(Color, Data, apiData); - } - if (latitude == longitude) { - return ( - getToolTipContent(Color, Data, apiData) + - `${apiData.headers[2]}: ${Data.tooltipValue}
+ } + if (latitude == longitude) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (latitude === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.value[0]}
` + ); + } + if (longitude === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.value[1]}
` + ); + } + if (label == color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${apiData.headers[3]}: ${Data.itemStyle.colorValue}
` + ); + }; + } + if (label && latitude && longitude && size) { + return (params) => { + const { data: Data, color: Color } = params; + if (latitude == longitude && latitude == size) { + return getToolTipContent(Color, Data, apiData); + } + if (latitude == longitude) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.tempSymbolSize}
` + ); + } + if (latitude == size) { + return getToolTipContent(Color, Data, apiData); + } + if (longitude == size) { + return getToolTipContent(Color, Data, apiData); + } + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${apiData.headers[3]}: ${Data.tempSymbolSize}
` + ); + }; + } + if (label && latitude && longitude && tooltip) { + return (params) => { + const { data: Data, color: Color } = params; + if (latitude == longitude && latitude == tooltip) { + return getToolTipContent(Color, Data, apiData); + } + if (latitude == longitude) { + return ( + getToolTipContent(Color, Data, apiData) + + `${apiData.headers[2]}: ${Data.tooltipValue}
` - ); - } - if (latitude == tooltip) { - return getToolTipContent(Color, Data, apiData); - } - if (longitude == tooltip) { - return getToolTipContent(Color, Data, apiData); - } - return ( - getToolTipContent(Color, Data, apiData) + - `${apiData.headers[3]}: ${Data.tooltipValue}
` - ); - }; - } - if (label && latitude && longitude) { - if (latitude == longitude) { - return function (params) { - const { data: Data, color: Color } = params; - return getToolTipContent(Color, Data, apiData); - }; - } - return function (params) { - const { data: Data, color: Color } = params; - return getToolTipContent(Color, Data, apiData); - }; - } - } - return ""; - } - return ""; - } - return ""; + ); + } + if (latitude == tooltip) { + return getToolTipContent(Color, Data, apiData); + } + if (longitude == tooltip) { + return getToolTipContent(Color, Data, apiData); + } + return ( + getToolTipContent(Color, Data, apiData) + + `${apiData.headers[3]}: ${Data.tooltipValue}
` + ); + }; + } + if (label && latitude && longitude) { + if (latitude == longitude) { + return (params) => { + const { data: Data, color: Color } = params; + return getToolTipContent(Color, Data, apiData); + }; + } + return (params) => { + const { data: Data, color: Color } = params; + return getToolTipContent(Color, Data, apiData); + }; + } + } + return ""; + } + return ""; + } + return ""; }; diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/map-chart/MapSelector.ts b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/map-chart/MapSelector.ts index edffbb5999..9760df1ff9 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/map-chart/MapSelector.ts +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/map-chart/MapSelector.ts @@ -1,602 +1,602 @@ export const getSelector = (data, aggregates) => { - let fields = "", - label = "", - latitude = "", - longitude = "", - size = "", - color = "", - tooltip = "", - labelName = "", - latitudeName = "", - longitudeName = ""; - if (data.option.hasOwnProperty("_state")) { - fields = data.option["_state"]["fields"]; - label = fields["label"]; - latitude = fields["Latitude"]; - longitude = fields["Longitude"]; - size = fields["size"]; - color = fields["color"]; - tooltip = fields["tooltip"]; - labelName = fields["label"]; - latitudeName = fields["Latitude"]; - longitudeName = fields["Longitude"]; - } - const getSelectorType = (type) => { - return fields[type] === "NUMBER" ? "Average" : "Count"; - }; - const getAggregates = (field) => { - if (!fields[field] || Object.values(aggregates[field]).length === 0) - return ""; - return Object.values(aggregates[field])[0]; - }; - const getSelectors = () => { - return { - latitude: getAggregates("Latitude"), - longitude: getAggregates("Longitude"), - size: getAggregates("size"), - tooltip: getAggregates("tooltip"), - }; - }; - const selectors = getSelectors(); - let selector = ""; - if (data.option.hasOwnProperty("_state")) { - if (data.option["_state"].hasOwnProperty("fields")) { - if (label && latitude && longitude && size && color && tooltip) { - if ( - latitude == longitude && - latitude == size && - latitude == color && - latitude == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); - } - if ( - latitude == longitude && - label == size && - label == color && - label == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); - } - if ( - latitude == longitude && - label == size && - label == color && - label == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); - } - if ( - latitude == longitude && - latitude == size && - label == color && - latitude == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); - } - if ( - latitude == longitude && - label == size && - latitude == color && - label == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); - } - if ( - latitude == longitude && - label == size && - label == color && - latitude == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); - } - if ( - latitude == longitude && - (size == color || label == color) && - size == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${size}])|Group(${labelName})`); - } - if ( - latitude == longitude && - label == color && - latitude == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${size}])|Group(${labelName})`); - } - if ( - latitude == longitude && - latitude == color && - size == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${size}])|Group(${labelName})`); - } - if ( - latitude == longitude && - latitude == tooltip && - size == color - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${size}])|Group(${labelName})`); - } - if ( - latitude == size && - latitude == color && - latitude == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if ( - longitude == size && - longitude == color && - longitude == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if ( - latitude == size && - latitude == color && - longitude == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if ( - latitude == size && - longitude == color && - latitude == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if ( - longitude == size && - latitude == color && - latitude == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if ( - longitude == size && - longitude == color && - latitude == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if ( - longitude == size && - latitude == color && - longitude == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if ( - latitude == size && - longitude == color && - longitude == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if ( - (latitude == size && - latitude == tooltip && - label == color) || - (longitude == size && - longitude == tooltip && - label == color) || - (latitude == size && - longitude == tooltip && - label == color) || - (longitude == size && latitude == tooltip && label == color) - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if ( - latitude == longitude && - (label == size || latitude == size) && - label == color - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${tooltip}])|Group(${labelName})`); - } - if ( - latitude == longitude && - label == color && - label == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${size}])|Group(${labelName})`); - } - if ( - latitude == longitude && - label == size && - label == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),(${color})).as([${labelName}, ${latitudeName},${color}])|Group(${labelName},${color})`); - } - if ( - latitude == longitude && - latitude == size && - latitude == color - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${tooltip}])|Group(${labelName})`); - } - if ( - latitude == longitude && - latitude == size && - latitude == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),(${color})).as([${labelName}, ${latitudeName},${color}])|Group(${labelName},${color})`); - } - if ( - latitude == longitude && - latitude == color && - latitude == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${size}])|Group(${labelName})`); - } - if ( - latitude === longitude && - latitude === size && - label === color - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${tooltip}])|Group(${labelName})`); - } - if (latitude == longitude && latitude == size) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${color},${tooltip}])|Group(${labelName},${color})`); - } - if ( - (size == color && latitude == tooltip) || - longitude == tooltip || - (size == color && size == tooltip) || - (size == tooltip && latitude == color) || - longitude == color - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); - } + let fields = "", + label = "", + latitude = "", + longitude = "", + size = "", + color = "", + tooltip = "", + labelName = "", + latitudeName = "", + longitudeName = ""; + if (Object.hasOwn(data.option, "_state")) { + fields = data.option["_state"]["fields"]; + label = fields["label"]; + latitude = fields["Latitude"]; + longitude = fields["Longitude"]; + size = fields["size"]; + color = fields["color"]; + tooltip = fields["tooltip"]; + labelName = fields["label"]; + latitudeName = fields["Latitude"]; + longitudeName = fields["Longitude"]; + } + const getSelectorType = (type) => { + return fields[type] === "NUMBER" ? "Average" : "Count"; + }; + const getAggregates = (field) => { + if (!fields[field] || Object.values(aggregates[field]).length === 0) + return ""; + return Object.values(aggregates[field])[0]; + }; + const getSelectors = () => { + return { + latitude: getAggregates("Latitude"), + longitude: getAggregates("Longitude"), + size: getAggregates("size"), + tooltip: getAggregates("tooltip"), + }; + }; + const selectors = getSelectors(); + let selector = ""; + if (Object.hasOwn(data.option, "_state")) { + if (Object.hasOwn(data.option["_state"], "fields")) { + if (label && latitude && longitude && size && color && tooltip) { + if ( + latitude == longitude && + latitude == size && + latitude == color && + latitude == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); + } + if ( + latitude == longitude && + label == size && + label == color && + label == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); + } + if ( + latitude == longitude && + label == size && + label == color && + label == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); + } + if ( + latitude == longitude && + latitude == size && + label == color && + latitude == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); + } + if ( + latitude == longitude && + label == size && + latitude == color && + label == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); + } + if ( + latitude == longitude && + label == size && + label == color && + latitude == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); + } + if ( + latitude == longitude && + (size == color || label == color) && + size == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${size}])|Group(${labelName})`); + } + if ( + latitude == longitude && + label == color && + latitude == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${size}])|Group(${labelName})`); + } + if ( + latitude == longitude && + latitude == color && + size == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${size}])|Group(${labelName})`); + } + if ( + latitude == longitude && + latitude == tooltip && + size == color + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${size}])|Group(${labelName})`); + } + if ( + latitude == size && + latitude == color && + latitude == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if ( + longitude == size && + longitude == color && + longitude == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if ( + latitude == size && + latitude == color && + longitude == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if ( + latitude == size && + longitude == color && + latitude == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if ( + longitude == size && + latitude == color && + latitude == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if ( + longitude == size && + longitude == color && + latitude == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if ( + longitude == size && + latitude == color && + longitude == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if ( + latitude == size && + longitude == color && + longitude == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if ( + (latitude == size && + latitude == tooltip && + label == color) || + (longitude == size && + longitude == tooltip && + label == color) || + (latitude == size && + longitude == tooltip && + label == color) || + (longitude == size && latitude == tooltip && label == color) + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if ( + latitude == longitude && + (label == size || latitude == size) && + label == color + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${tooltip}])|Group(${labelName})`); + } + if ( + latitude == longitude && + label == color && + label == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${size}])|Group(${labelName})`); + } + if ( + latitude == longitude && + label == size && + label == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),(${color})).as([${labelName}, ${latitudeName},${color}])|Group(${labelName},${color})`); + } + if ( + latitude == longitude && + latitude == size && + latitude == color + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${tooltip}])|Group(${labelName})`); + } + if ( + latitude == longitude && + latitude == size && + latitude == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),(${color})).as([${labelName}, ${latitudeName},${color}])|Group(${labelName},${color})`); + } + if ( + latitude == longitude && + latitude == color && + latitude == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${size}])|Group(${labelName})`); + } + if ( + latitude === longitude && + latitude === size && + label === color + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${tooltip}])|Group(${labelName})`); + } + if (latitude == longitude && latitude == size) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${color},${tooltip}])|Group(${labelName},${color})`); + } + if ( + (size == color && latitude == tooltip) || + longitude == tooltip || + (size == color && size == tooltip) || + (size == tooltip && latitude == color) || + longitude == color + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); + } - if ( - (latitude == longitude && latitude == color) || - size == color - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${size},${tooltip}])|Group(${labelName})`); - } - if ( - (latitude == longitude && latitude == tooltip) || - size == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${latitudeName},${size},${color}])|Group(${labelName},${color})`); - } - if (latitude == longitude && label == size) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${color},${tooltip}])|Group(${labelName},${color})`); - } - if (latitude == longitude && label == color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${size},${tooltip}])|Group(${labelName})`); - } - if (latitude == longitude && label == tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${latitudeName},${size},${color}])|Group(${labelName},${color})`); - } - if ( - latitude == longitude && - label == size && - latitude == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),(${color})).as([${labelName}, ${latitudeName}${color}])|Group(${labelName},${color})`); - } + if ( + (latitude == longitude && latitude == color) || + size == color + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${size},${tooltip}])|Group(${labelName})`); + } + if ( + (latitude == longitude && latitude == tooltip) || + size == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${latitudeName},${size},${color}])|Group(${labelName},${color})`); + } + if (latitude == longitude && label == size) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${color},${tooltip}])|Group(${labelName},${color})`); + } + if (latitude == longitude && label == color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${size},${tooltip}])|Group(${labelName})`); + } + if (latitude == longitude && label == tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${latitudeName},${size},${color}])|Group(${labelName},${color})`); + } + if ( + latitude == longitude && + label == size && + latitude == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),(${color})).as([${labelName}, ${latitudeName}${color}])|Group(${labelName},${color})`); + } - if ( - (latitude == size && label == color) || - (longitude == size && label == color) - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); - } - if ( - (latitude == tooltip && label == color) || - (longitude == tooltip && label == color) - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); - } - if (latitude == size && latitude == color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); - } - if (longitude == size && longitude == color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); - } - if (latitude == size && latitude == tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${color}])|Group(${labelName},${color})`); - } - if (longitude == size && longitude == tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${color}])|Group(${labelName},${color})`); - } - if (latitude == color && latitude == tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); - } - if (longitude == color && longitude == tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); - } - if (latitude == size && longitude == color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); - } - if (longitude == size && latitude == color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); - } - if (latitude == size && longitude == tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${color}])|Group(${labelName},${color})`); - } - if (longitude == size && latitude == tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${color}])|Group(${labelName},${color})`); - } - if (latitude == color && longitude == tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); - } - if (longitude == color && latitude == tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); - } - if (size === tooltip && label === color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); - } - if (latitude == longitude) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${size},${color},${tooltip}])|Group(${labelName},${color})`); - } - if (label === color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${size},${tooltip}])|Group(${labelName})`); - } - if (latitude == size) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${color},${tooltip}])|Group(${labelName},${color})`); - } - if (latitude == color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${size},${tooltip}])|Group(${labelName})`); - } - if (latitude == tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${size},${color}])|Group(${labelName},${color})`); - } - if (longitude == size) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${color},${tooltip}])|Group(${labelName},${color})`); - } - if (longitude == color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${size},${tooltip}])|Group(${labelName})`); - } - if (longitude == tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${size},${color}])|Group(${labelName},${color})`); - } - if (size === color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${size},${tooltip}])|Group(${labelName})`); - } - if (size === tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${size},${color}])|Group(${labelName},${color})`); - } - if (color === tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${size},${color}])|Group(${labelName},${color})`); - } - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${size},${color},${tooltip}])|Group(${labelName},${color})`); - } - if (label && latitude && longitude && size && color) { - if ( - latitude == longitude && - latitude == size && - (latitude == color || label == color) - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); - } - if ( - latitude == longitude && - (latitude == color || size == color) - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${size}])|Group(${labelName})`); - } - if (latitude == longitude && label == color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${size}])|Group(${labelName})`); - } - if (latitude == longitude && latitude == size) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),(${color})).as([${labelName}, ${latitudeName},${color}])|Group(${labelName},${color})`); - } + if ( + (latitude == size && label == color) || + (longitude == size && label == color) + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); + } + if ( + (latitude == tooltip && label == color) || + (longitude == tooltip && label == color) + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); + } + if (latitude == size && latitude == color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); + } + if (longitude == size && longitude == color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); + } + if (latitude == size && latitude == tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${color}])|Group(${labelName},${color})`); + } + if (longitude == size && longitude == tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${color}])|Group(${labelName},${color})`); + } + if (latitude == color && latitude == tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); + } + if (longitude == color && longitude == tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); + } + if (latitude == size && longitude == color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); + } + if (longitude == size && latitude == color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); + } + if (latitude == size && longitude == tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${color}])|Group(${labelName},${color})`); + } + if (longitude == size && latitude == tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${color}])|Group(${labelName},${color})`); + } + if (latitude == color && longitude == tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); + } + if (longitude == color && latitude == tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); + } + if (size === tooltip && label === color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); + } + if (latitude == longitude) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${size},${color},${tooltip}])|Group(${labelName},${color})`); + } + if (label === color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${size},${tooltip}])|Group(${labelName})`); + } + if (latitude == size) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${color},${tooltip}])|Group(${labelName},${color})`); + } + if (latitude == color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${size},${tooltip}])|Group(${labelName})`); + } + if (latitude == tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${size},${color}])|Group(${labelName},${color})`); + } + if (longitude == size) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${color},${tooltip}])|Group(${labelName},${color})`); + } + if (longitude == color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${size},${tooltip}])|Group(${labelName})`); + } + if (longitude == tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${size},${color}])|Group(${labelName},${color})`); + } + if (size === color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${size},${tooltip}])|Group(${labelName})`); + } + if (size === tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${size},${color}])|Group(${labelName},${color})`); + } + if (color === tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${size},${color}])|Group(${labelName},${color})`); + } + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${size},${color},${tooltip}])|Group(${labelName},${color})`); + } + if (label && latitude && longitude && size && color) { + if ( + latitude == longitude && + latitude == size && + (latitude == color || label == color) + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); + } + if ( + latitude == longitude && + (latitude == color || size == color) + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${size}])|Group(${labelName})`); + } + if (latitude == longitude && label == color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${size}])|Group(${labelName})`); + } + if (latitude == longitude && latitude == size) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),(${color})).as([${labelName}, ${latitudeName},${color}])|Group(${labelName},${color})`); + } - if (latitude == size && latitude == color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if (longitude == size && longitude == color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if (latitude == size && longitude == color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if (longitude === size && latitude === color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if ( - (latitude == size && label == color) || - (longitude == size && label == color) - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if (latitude == longitude) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${latitudeName},${size},${color}])|Group(${labelName},${color})`); - } + if (latitude == size && latitude == color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if (longitude == size && longitude == color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if (latitude == size && longitude == color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if (longitude === size && latitude === color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if ( + (latitude == size && label == color) || + (longitude == size && label == color) + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if (latitude == longitude) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${latitudeName},${size},${color}])|Group(${labelName},${color})`); + } - if (size == color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); - } - if (latitude === size) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${color}])|Group(${labelName},${color})`); - } - if (longitude === size) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${color}])|Group(${labelName},${color})`); - } - if (latitude === color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); - } - if (longitude === color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); - } - if (label === color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); - } + if (size == color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); + } + if (latitude === size) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${color}])|Group(${labelName},${color})`); + } + if (longitude === size) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${color}])|Group(${labelName},${color})`); + } + if (latitude === color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); + } + if (longitude === color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); + } + if (label === color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); + } - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${size},${color}])|Group(${labelName},${color})`); - } - if (label && latitude && longitude && color && tooltip) { - if ( - latitude == longitude && - (latitude == color || label == color) && - latitude == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); - } - if ( - latitude == longitude && - (latitude == color || label == color) - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${tooltip}])|Group(${labelName})`); - } + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${size},${color}])|Group(${labelName},${color})`); + } + if (label && latitude && longitude && color && tooltip) { + if ( + latitude == longitude && + (latitude == color || label == color) && + latitude == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); + } + if ( + latitude == longitude && + (latitude == color || label == color) + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${tooltip}])|Group(${labelName})`); + } - if (latitude == longitude && latitude == tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),(${color})).as([${labelName}, ${latitudeName},${color}])|Group(${labelName},${color})`); - } + if (latitude == longitude && latitude == tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),(${color})).as([${labelName}, ${latitudeName},${color}])|Group(${labelName},${color})`); + } - if (latitude == color && latitude == tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if (longitude == color && longitude == tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if (latitude === color && longitude === tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if (longitude === color && latitude === tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if ( - (latitude === tooltip && label === color) || - (longitude === tooltip && label === color) - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if (latitude == longitude) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${color},${tooltip}])|Group(${labelName},${color})`); - } - if (label === color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); - } - if (color == tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${color}])|Group(${labelName},${color})`); - } - if (latitude == color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); - } - if (longitude === color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); - } - if (latitude === tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${color}])|Group(${labelName},${color})`); - } - if (longitude === tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${color}])|Group(${labelName},${color})`); - } - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${color},${tooltip}])|Group(${labelName},${color})`); - } - if (label && latitude && longitude && size && tooltip) { - if ( - latitude == longitude && - latitude == size && - latitude == tooltip - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); - } - if (latitude == longitude && latitude == size) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${tooltip}])|Group(${labelName})`); - } - if ( - latitude == longitude && - (latitude == tooltip || size == tooltip) - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${size}])|Group(${labelName})`); - } - if (latitude === size && latitude === tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if (longitude === size && longitude === tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if (latitude === size && longitude === tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if (longitude === size && latitude === tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if (latitude == longitude) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${size},${tooltip}])|Group(${labelName})`); - } - if (size === tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); - } - if (latitude === size) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); - } - if (longitude === size) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); - } - if (latitude === tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); - } - if (longitude === tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); - } + if (latitude == color && latitude == tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if (longitude == color && longitude == tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if (latitude === color && longitude === tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if (longitude === color && latitude === tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if ( + (latitude === tooltip && label === color) || + (longitude === tooltip && label === color) + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if (latitude == longitude) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${color},${tooltip}])|Group(${labelName},${color})`); + } + if (label === color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); + } + if (color == tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${color}])|Group(${labelName},${color})`); + } + if (latitude == color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); + } + if (longitude === color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); + } + if (latitude === tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${color}])|Group(${labelName},${color})`); + } + if (longitude === tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${color}])|Group(${labelName},${color})`); + } + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${color},${tooltip}])|Group(${labelName},${color})`); + } + if (label && latitude && longitude && size && tooltip) { + if ( + latitude == longitude && + latitude == size && + latitude == tooltip + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); + } + if (latitude == longitude && latitude == size) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${tooltip}])|Group(${labelName})`); + } + if ( + latitude == longitude && + (latitude == tooltip || size == tooltip) + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${size}])|Group(${labelName})`); + } + if (latitude === size && latitude === tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if (longitude === size && longitude === tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if (latitude === size && longitude === tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if (longitude === size && latitude === tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if (latitude == longitude) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${size},${tooltip}])|Group(${labelName})`); + } + if (size === tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); + } + if (latitude === size) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); + } + if (longitude === size) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); + } + if (latitude === tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); + } + if (longitude === tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); + } - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${size},${tooltip}])|Group(${labelName})`); - } - if (label && latitude && longitude && color) { - if ( - latitude == longitude && - (latitude == color || label == color) - ) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); - } - if (latitude === longitude) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),(${color})).as([${labelName}, ${latitudeName},${color}])|Group(${labelName},${color})`); - } - if (latitude === color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if (longitude === color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if (label === color) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${color}])|Group(${labelName},${color})`); - } - if (label && latitude && longitude && size) { - if (latitude === longitude && latitude === size) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); - } - if (latitude === longitude) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${size}])|Group(${labelName})`); - } - if (latitude === size) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if (longitude === size) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); - } - if (label && latitude && longitude && tooltip) { - if (latitude === longitude && latitude === tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); - } - if (latitude === longitude) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${tooltip}])|Group(${labelName})`); - } - if (latitude === tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - if (longitude === tooltip) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); - } - if (label && latitude && longitude) { - if (latitude == longitude) { - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); - } - return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); - } - } - } - return ""; + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${size},${tooltip}])|Group(${labelName})`); + } + if (label && latitude && longitude && color) { + if ( + latitude == longitude && + (latitude == color || label == color) + ) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); + } + if (latitude === longitude) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),(${color})).as([${labelName}, ${latitudeName},${color}])|Group(${labelName},${color})`); + } + if (latitude === color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if (longitude === color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if (label === color) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),(${color})).as([${labelName}, ${latitudeName},${longitudeName},${color}])|Group(${labelName},${color})`); + } + if (label && latitude && longitude && size) { + if (latitude === longitude && latitude === size) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); + } + if (latitude === longitude) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${size}])|Group(${labelName})`); + } + if (latitude === size) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if (longitude === size) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.size}(${size})).as([${labelName}, ${latitudeName},${longitudeName},${size}])|Group(${labelName})`); + } + if (label && latitude && longitude && tooltip) { + if (latitude === longitude && latitude === tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); + } + if (latitude === longitude) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${tooltip}])|Group(${labelName})`); + } + if (latitude === tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + if (longitude === tooltip) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${latitudeName},${longitudeName},${tooltip}])|Group(${labelName})`); + } + if (label && latitude && longitude) { + if (latitude == longitude) { + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName})).as([${labelName}, ${latitudeName}])|Group(${labelName})`); + } + return (selector = `Select(${labelName},${selectors.latitude}(${latitudeName}),${selectors.longitude}(${longitudeName})).as([${labelName}, ${latitudeName},${longitudeName}])|Group(${labelName})`); + } + } + } + return ""; }; diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/map-chart/map-utility.tsx b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/map-chart/map-utility.tsx index f6a17afd3f..10b05817ba 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/map-chart/map-utility.tsx +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/map-chart/map-utility.tsx @@ -1,7 +1,7 @@ import worldjson from "./world"; const fetchWorldMap = (urlString: string) => { - return worldjson; + return worldjson; }; export default fetchWorldMap; diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/pie-chart/Pie.tsx b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/pie-chart/Pie.tsx index 7e72c55485..b429a1bffe 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/pie-chart/Pie.tsx +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/pie-chart/Pie.tsx @@ -1,232 +1,230 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { useCallback, useEffect, useMemo, useState } from "react"; + +import type { EChartsOption } from "echarts"; import ReactECharts from "echarts-for-react"; -import { observer } from "mobx-react-lite"; import { computed } from "mobx"; -import { EChartsOption } from "echarts"; - +import { observer } from "mobx-react-lite"; +import { useCallback, useEffect, useMemo, useState } from "react"; import { styled } from "@semoss/ui"; - -import { useFrame, useBlock } from "../../../../../hooks"; +import { useBlock, useFrame } from "../../../../../hooks"; import { getValueByPath } from "../../../../../utility"; -import { EchartVisualizationBlockDef } from "../.."; - +import type { EchartVisualizationBlockDef } from "../.."; import { CustomContextMenu } from "../../CustomContextMenu"; const StyledChartContainer = styled("div")(() => ({ - height: "inherit", + height: "inherit", })); const StyledNoDataContainer = styled("div", { - shouldForwardProp: (prop) => prop !== "error", + shouldForwardProp: (prop) => prop !== "error", })<{ error?: boolean }>(({ error = false, theme }) => ({ - height: "30vh", - width: "80vh", - color: error ? theme.palette.error.main : "unset", + height: "30vh", + width: "80vh", + color: error ? theme.palette.error.main : "unset", })); interface PieProps { - /** - * - */ - id: string; - - /** - * - */ - updateJson: (data: any, path: any) => void; + /** + * + */ + id: string; + + /** + * + */ + updateJson: (data: any, path: any) => void; } export const Pie = observer(({ id, updateJson }: PieProps) => { - const { data } = useBlock(id); - - const [contextMenu, setContextMenu] = useState<{ - mouseX: number; - mouseY: number; - value: unknown; - } | null>(null); - let resultData: unknown = {}; - - /** - * Builds a dynamic query string based on the provided input data. - * @param inputData - An array of tuples where each tuple contains a string and an object mapping field names to aggregation methods. - * @returns A query string that selects and groups by the specified fields with appropriate aggregations. - */ - const buildDynamicQuery = (inputData): string => { - const selectParts: string[] = []; - const aliasParts: string[] = []; - const groupByParts: string[] = []; - - inputData.forEach(([_, fields]) => { - for (const field in fields) { - const rawAgg = fields[field]; - aliasParts.push(field); - - if (rawAgg) { - const cleanedAgg = rawAgg.split(" ").join(""); // Remove spaces (e.g., "Unique Count" → "UniqueCount") - selectParts.push(`${cleanedAgg}(${field})`); - } else { - selectParts.push(field); - groupByParts.push(field); // Only unaggregated fields are grouped - } - } - }); - - return `Select(${selectParts.join(", ")}).as([${aliasParts.join( - ", ", - )}]) | Group(${groupByParts.join(", ")})`; - }; - - /** - * get the frame - */ - const frame = useFrame(data?.frame?.name, { - selector: buildDynamicQuery(Object.entries(data?.aggregate ?? {})), - }); - - /** - * @description Trying out different approach for TrendLine, work in progress - */ - const computedValue = useMemo(() => { - return computed(() => { - if (!data) { - return ""; - } - const v = getValueByPath(data, "option"); - if (typeof v === "undefined") { - return ""; - } else if (typeof v === "string") { - return v; - } - return JSON.stringify(v, null, 2); - }); - }, [data, "option"]).get(); - - /** - * @description - */ - const parsedOption = useMemo(() => { - return typeof computedValue === "string" - ? JSON.parse(computedValue) - : computedValue; - }, [computedValue]); - - /** - * @description - */ - useEffect(() => { - if ( - data?.frame?.name && - frame?.data?.values.length > 0 && - frame?.isLoading === false - ) { - updateJson(parsedOption, "option"); - } - }, [frame.data.values]); - - /** - * @description format the frame option data for echart - */ - const formatDataPoints = useCallback( - (resultData: unknown) => { - if (frame.data.values.length > 0) { - const valuesDataSet = JSON.parse( - JSON.stringify(frame.data.values), - ); - let headersDataSet: string[] = JSON.parse( - JSON.stringify(frame.data.headers), - ); - headersDataSet = headersDataSet.map((header: string) => - header.replace("Average_", ""), - ); - //format the data points to match the echart specification - resultData["series"][0]["data"] = valuesDataSet.map( - ([name, value]) => ({ name, value }), - ); - valuesDataSet.map((x) => x.shift()); - headersDataSet.shift(); - } else { - delete resultData["tooltip"]["formatter"]; - } - return resultData; - }, - [frame.data.values], - ); - - /** - * @description - */ - const onClickChart = { - contextmenu: (params) => { - // let currentOption = chart.getOption(); - if (params.data) { - const labelName = data.option["_state"]["fields"]["Label"][0]; - setContextMenu( - contextMenu === null - ? { - mouseX: params.event.event.clientX, - mouseY: params.event.event.clientY, - value: { - label: labelName, - value: params.data.name, - }, - } - : // repeated contextmenu when it is already open closes it with Chrome 84 on Ubuntu - // Other native context menus might behave different. - // With this behavior we prevent contextmenu from the backdrop to re-locale existing context menus. - null, - ); - params.event.event.preventDefault(); - } else { - params.event.event.preventDefault(); - } - }, - }; - - if (typeof data.option === "string") { - // if it's a string, it's either invalid json or a query output that needs to be parsed - // try to parse, and show error otherwise - try { - const lineOptions = JSON.parse(data.option); - return ( - - - - ); - } catch (e) { - return ( - - There was an issue parsing your JSON. - - ); - } - } else { - resultData = - data?.frame?.name && - frame.data.values.length > 0 && - frame.isLoading === false - ? formatDataPoints(parsedOption) - : parsedOption; - return ( - - - setContextMenu(null)} - /> - - ); - } + const { data } = useBlock(id); + + const [contextMenu, setContextMenu] = useState<{ + mouseX: number; + mouseY: number; + value: unknown; + } | null>(null); + let resultData: unknown = {}; + + /** + * Builds a dynamic query string based on the provided input data. + * @param inputData - An array of tuples where each tuple contains a string and an object mapping field names to aggregation methods. + * @returns A query string that selects and groups by the specified fields with appropriate aggregations. + */ + const buildDynamicQuery = (inputData): string => { + const selectParts: string[] = []; + const aliasParts: string[] = []; + const groupByParts: string[] = []; + + inputData.forEach(([_, fields]) => { + for (const field in fields) { + const rawAgg = fields[field]; + aliasParts.push(field); + + if (rawAgg) { + const cleanedAgg = rawAgg.split(" ").join(""); // Remove spaces (e.g., "Unique Count" → "UniqueCount") + selectParts.push(`${cleanedAgg}(${field})`); + } else { + selectParts.push(field); + groupByParts.push(field); // Only unaggregated fields are grouped + } + } + }); + + return `Select(${selectParts.join(", ")}).as([${aliasParts.join( + ", ", + )}]) | Group(${groupByParts.join(", ")})`; + }; + + /** + * get the frame + */ + const frame = useFrame(data?.frame?.name, { + selector: buildDynamicQuery(Object.entries(data?.aggregate ?? {})), + }); + + /** + * @description Trying out different approach for TrendLine, work in progress + */ + const computedValue = useMemo(() => { + return computed(() => { + if (!data) { + return ""; + } + const v = getValueByPath(data, "option"); + if (typeof v === "undefined") { + return ""; + } else if (typeof v === "string") { + return v; + } + return JSON.stringify(v, null, 2); + }); + }, [data, "option"]).get(); + + /** + * @description + */ + const parsedOption = useMemo(() => { + return typeof computedValue === "string" + ? JSON.parse(computedValue) + : computedValue; + }, [computedValue]); + + /** + * @description + */ + useEffect(() => { + if ( + data?.frame?.name && + frame?.data?.values.length > 0 && + frame?.isLoading === false + ) { + updateJson(parsedOption, "option"); + } + }, [frame.data.values]); + + /** + * @description format the frame option data for echart + */ + const formatDataPoints = useCallback( + (resultData: unknown) => { + if (frame.data.values.length > 0) { + const valuesDataSet = JSON.parse( + JSON.stringify(frame.data.values), + ); + let headersDataSet: string[] = JSON.parse( + JSON.stringify(frame.data.headers), + ); + headersDataSet = headersDataSet.map((header: string) => + header.replace("Average_", ""), + ); + //format the data points to match the echart specification + resultData["series"][0]["data"] = valuesDataSet.map( + ([name, value]) => ({ name, value }), + ); + valuesDataSet.map((x) => x.shift()); + headersDataSet.shift(); + } else { + delete resultData["tooltip"]["formatter"]; + } + return resultData; + }, + [frame.data.values], + ); + + /** + * @description + */ + const onClickChart = { + contextmenu: (params) => { + // let currentOption = chart.getOption(); + if (params.data) { + const labelName = data.option["_state"]["fields"]["Label"][0]; + setContextMenu( + contextMenu === null + ? { + mouseX: params.event.event.clientX, + mouseY: params.event.event.clientY, + value: { + label: labelName, + value: params.data.name, + }, + } + : // repeated contextmenu when it is already open closes it with Chrome 84 on Ubuntu + // Other native context menus might behave different. + // With this behavior we prevent contextmenu from the backdrop to re-locale existing context menus. + null, + ); + params.event.event.preventDefault(); + } else { + params.event.event.preventDefault(); + } + }, + }; + + if (typeof data.option === "string") { + // if it's a string, it's either invalid json or a query output that needs to be parsed + // try to parse, and show error otherwise + try { + const lineOptions = JSON.parse(data.option); + return ( + + + + ); + } catch (e) { + return ( + + There was an issue parsing your JSON. + + ); + } + } else { + resultData = + data?.frame?.name && + frame.data.values.length > 0 && + frame.isLoading === false + ? formatDataPoints(parsedOption) + : parsedOption; + return ( + + + setContextMenu(null)} + /> + + ); + } }); diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/scatter-plot/ScatterPlot.tsx b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/scatter-plot/ScatterPlot.tsx index 81e84f03a4..6e6a301c67 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/scatter-plot/ScatterPlot.tsx +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/scatter-plot/ScatterPlot.tsx @@ -1,207 +1,205 @@ -import { useState } from "react"; -import { observer } from "mobx-react-lite"; -import * as echarts from "echarts/core"; +import type { EChartsOption } from "echarts"; import { BarChart } from "echarts/charts"; -import EChartsReact from "echarts-for-react"; -import { CanvasRenderer } from "echarts/renderers"; import { TooltipComponent } from "echarts/components"; -import { EChartsOption } from "echarts"; - +import * as echarts from "echarts/core"; +import { CanvasRenderer } from "echarts/renderers"; +import EChartsReact from "echarts-for-react"; +import { observer } from "mobx-react-lite"; +import { useState } from "react"; import { styled } from "@semoss/ui"; - -import { useFrame, useBlock } from "../../../../../hooks"; -import { BlockComponent } from "../../../../../store"; - -import { getSelector } from "./ScatterPlotSelector"; +import { useBlock, useFrame } from "../../../../../hooks"; +import type { BlockComponent } from "../../../../../store"; +import { VizBlockContextMenu } from "../../VizBlockContextMenu"; import { processData } from "./ScatterPlotProcessData"; +import { getSelector } from "./ScatterPlotSelector"; import { formatdatapoints } from "./ScatterPlotTooltipData"; -import { VizBlockContextMenu } from "../../VizBlockContextMenu"; const StyledNoDataContainer = styled("div", { - shouldForwardProp: (prop) => prop !== "error", + shouldForwardProp: (prop) => prop !== "error", })<{ error?: boolean }>(({ error = false, theme }) => ({ - height: "100%", - width: "100%", - color: error ? theme.palette.error.main : "unset", + height: "100%", + width: "100%", + color: error ? theme.palette.error.main : "unset", })); export interface EChartColumns { - name: string; - selector: string; - width: string; + name: string; + selector: string; + width: string; } export interface EchartVisualizationBlockDef { - widget: "e-chart"; - data: { - option: {}; - frame: { - name: string; - }; - variation: undefined | string; - columns: EChartColumns[]; - aggregate: Record; - contextMenu: { - hideUnfilter: boolean; - hideFilter: boolean; - hideExclude: boolean; - }; - }; - listeners: {}; - slots: never; + widget: "e-chart"; + data: { + option: {}; + frame: { + name: string; + }; + variation: undefined | string; + columns: EChartColumns[]; + aggregate: Record; + contextMenu: { + hideUnfilter: boolean; + hideFilter: boolean; + hideExclude: boolean; + }; + }; + listeners: {}; + slots: never; } export const ScatterPlotBlock: BlockComponent = observer(({ id }) => { - const { data } = useBlock(id); + const { data } = useBlock(id); - echarts.use([BarChart, CanvasRenderer, TooltipComponent]); - const [contextMenu, setContextMenu] = useState<{ - mouseX: number; - mouseY: number; - value: unknown; - } | null>(null); + echarts.use([BarChart, CanvasRenderer, TooltipComponent]); + const [contextMenu, setContextMenu] = useState<{ + mouseX: number; + mouseY: number; + value: unknown; + } | null>(null); - const frame = useFrame(data?.frame?.name, { - selector: getSelector(data, data?.aggregate), - }); - function debounce(fn, delay) { - let timer; - return (...args) => { - clearTimeout(timer); - timer = setTimeout(() => fn(...args), delay); - }; - } - const echartsLoaded = debounce((chart) => { - chart.on("brushSelected", (params) => { - const selectedData = params.batch[0].selected[0].dataIndex; - const currentOption = chart.getOption(); - const labelData = currentOption.series[0].data; - const filteredLabels = selectedData.map( - (index) => labelData[index].label.formatter, - ); - if (filteredLabels.length > 0) { - handleSelection( - filteredLabels, - currentOption.series[0].label.name, - ); - } - }); - }, 2000); + const frame = useFrame(data?.frame?.name, { + selector: getSelector(data, data?.aggregate), + }); + function debounce(fn, delay) { + let timer; + return (...args) => { + clearTimeout(timer); + timer = setTimeout(() => fn(...args), delay); + }; + } + const echartsLoaded = debounce((chart) => { + chart.on("brushSelected", (params) => { + const selectedData = params.batch[0].selected[0].dataIndex; + const currentOption = chart.getOption(); + const labelData = currentOption.series[0].data; + const filteredLabels = selectedData.map( + (index) => labelData[index].label.formatter, + ); + if (filteredLabels.length > 0) { + handleSelection( + filteredLabels, + currentOption.series[0].label.name, + ); + } + }); + }, 2000); - const handleSelection = debounce((value: any, name: any) => { - // update the frame - frame.filter(`SetFrameFilter(${name}==[${value}])`); - }, 2000); - const onClickChart = { - contextmenu: (params) => { - if (params.data) { - const labelName = data.option["series"][0]["label"]["name"]; - setContextMenu( - contextMenu === null - ? { - mouseX: params.event.event.clientX, - mouseY: params.event.event.clientY, - value: { - label: labelName, - value: params.data.label.formatter, - }, - } - : null, - ); - params.event.event.preventDefault(); - } else { - params.event.event.preventDefault(); - } - }, - }; + const handleSelection = debounce((value: any, name: any) => { + // update the frame + frame.filter(`SetFrameFilter(${name}==[${value}])`); + }, 2000); + const onClickChart = { + contextmenu: (params) => { + if (params.data) { + const labelName = data.option["series"][0]["label"]["name"]; + setContextMenu( + contextMenu === null + ? { + mouseX: params.event.event.clientX, + mouseY: params.event.event.clientY, + value: { + label: labelName, + value: params.data.label.formatter, + }, + } + : null, + ); + params.event.event.preventDefault(); + } else { + params.event.event.preventDefault(); + } + }, + }; - if (!data.option) { - return ( - - Add JSON to render your visualization - - ); - } - if (typeof data.option === "string") { - try { - const processedFrameData = processData(frame.data, data); - if (processedFrameData && processedFrameData.length > 0) { - data.option["series"][0]["data"] = processedFrameData; - } - if (!data.option["tooltip"].hasOwnProperty("formatter")) { - data.option["tooltip"] = { - ...data.option["tooltip"], - formatter: formatdatapoints(frame.data, data), - }; - } - return ( - - { - echartsLoaded(chart); - }} - style={{ height: "inherit", width: "inherit" }} - onEvents={onClickChart} - /> - setContextMenu(null)} - /> - - ); - } catch (e) { - return ( - - There was an issue parsing your JSON. - - ); - } - } else { - if (data.option.hasOwnProperty("_state")) { - if (data.option["_state"].hasOwnProperty("fields")) { - if ( - data.option["_state"]["fields"].hasOwnProperty("label") && - data.option["_state"]["fields"].hasOwnProperty("XAxis") && - data.option["_state"]["fields"].hasOwnProperty("YAxis") - ) { - const processedFrameData = processData(frame.data, data); - if (processedFrameData && processedFrameData.length > 0) { - data.option["series"][0]["data"] = processedFrameData; - } - if (frame.data.values.length > 0) { - if ( - !data.option["tooltip"].hasOwnProperty( - "formatter", - ) || - data.option["tooltip"]["formatter"] === "" - ) { - data.option["tooltip"] = { - ...data.option["tooltip"], - formatter: formatdatapoints(frame.data, data), - }; - } - } - } - } - } - return ( - - { - echartsLoaded(chart); - }} - style={{ height: "inherit", width: "inherit" }} - onEvents={onClickChart} - /> - setContextMenu(null)} - /> - - ); - } + if (!data.option) { + return ( + + Add JSON to render your visualization + + ); + } + if (typeof data.option === "string") { + try { + const processedFrameData = processData(frame.data, data); + if (processedFrameData && processedFrameData.length > 0) { + data.option["series"][0]["data"] = processedFrameData; + } + if (!Object.hasOwn(data.option["tooltip"], "formatter")) { + data.option["tooltip"] = { + ...data.option["tooltip"], + formatter: formatdatapoints(frame.data, data), + }; + } + return ( + + { + echartsLoaded(chart); + }} + style={{ height: "inherit", width: "inherit" }} + onEvents={onClickChart} + /> + setContextMenu(null)} + /> + + ); + } catch (e) { + return ( + + There was an issue parsing your JSON. + + ); + } + } else { + if (Object.hasOwn(data.option, "_state")) { + if (Object.hasOwn(data.option["_state"], "fields")) { + if ( + Object.hasOwn(data.option["_state"]["fields"], "label") && + Object.hasOwn(data.option["_state"]["fields"], "XAxis") && + Object.hasOwn(data.option["_state"]["fields"], "YAxis") + ) { + const processedFrameData = processData(frame.data, data); + if (processedFrameData && processedFrameData.length > 0) { + data.option["series"][0]["data"] = processedFrameData; + } + if (frame.data.values.length > 0) { + if ( + !Object.hasOwn( + data.option["tooltip"], + "formatter", + ) || + data.option["tooltip"]["formatter"] === "" + ) { + data.option["tooltip"] = { + ...data.option["tooltip"], + formatter: formatdatapoints(frame.data, data), + }; + } + } + } + } + } + return ( + + { + echartsLoaded(chart); + }} + style={{ height: "inherit", width: "inherit" }} + onEvents={onClickChart} + /> + setContextMenu(null)} + /> + + ); + } }); diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/scatter-plot/ScatterPlotProcessData.ts b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/scatter-plot/ScatterPlotProcessData.ts index b0306f0668..77b999aea0 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/scatter-plot/ScatterPlotProcessData.ts +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/scatter-plot/ScatterPlotProcessData.ts @@ -1,2064 +1,2062 @@ export const processData = (apiData, data) => { - let fields = "", - label = "", - xAxis = "", - yAxis = "", - size = "", - color = "", - tooltip = ""; - if (data.option.hasOwnProperty("_state")) { - fields = data.option["_state"]["fields"]; - label = fields["label"]; - xAxis = fields["XAxis"]; - yAxis = fields["YAxis"]; - size = fields["size"]; - color = fields["color"]; - tooltip = fields["tooltip"]; - } - const formatItem = (label, xAxis, yAxis) => ({ - value: [xAxis, yAxis], // x and y values - label: { - formatter: label.toString(), // Use array[0] as the label - }, - }); + let fields = "", + label = "", + xAxis = "", + yAxis = "", + size = "", + color = "", + tooltip = ""; + if (Object.hasOwn(data.option, "_state")) { + fields = data.option["_state"]["fields"]; + label = fields["label"]; + xAxis = fields["XAxis"]; + yAxis = fields["YAxis"]; + size = fields["size"]; + color = fields["color"]; + tooltip = fields["tooltip"]; + } + const formatItem = (label, xAxis, yAxis) => ({ + value: [xAxis, yAxis], // x and y values + label: { + formatter: label.toString(), // Use array[0] as the label + }, + }); - const formatDataItem = ( - label, - xAxis, - yAxis, - size, - color, - tooltip, - colorMap = null, - ) => { - if (!colorMap.has(color)) { - colorMap.set( - color, - data.option["color"][ - colorMap.size % data.option["color"]?.length - ], - ); - } - return { - value: [xAxis, yAxis], // x and y values - label: { - formatter: label.toString(), // Use array[0] as the label - }, - symbolSize: size, // Individual symbol size - itemStyle: { - color: colorMap.get(color), - colorValue: color, - }, - tooltipValue: tooltip, //tooltip value - }; - }; - const formatData = (label, xAxis, yAxis, size, color, colorMap = null) => { - if (!colorMap.has(color)) { - colorMap.set( - color, - data.option["color"][ - colorMap.size % data.option["color"]?.length - ], - ); - } - return { - value: [xAxis, yAxis], // x and y values - label: { - formatter: label.toString(), // Use array[0] as the label - }, - symbolSize: size, // Individual symbol size - itemStyle: { - color: colorMap.get(color), - colorValue: color, - }, - }; - }; - const formatItemData = ( - label, - xAxis, - yAxis, - color, - tooltip, - colorMap = null, - ) => { - if (!colorMap.has(color)) { - colorMap.set( - color, - data.option["color"][ - colorMap.size % data.option["color"]?.length - ], - ); - } - return { - value: [xAxis, yAxis], // x and y values - label: { - formatter: label.toString(), // Use array[0] as the label - }, - itemStyle: { - color: colorMap.get(color), - colorValue: color, - }, - tooltipValue: tooltip, //tooltip value - }; - }; - const formatItems = (label, xAxis, yAxis, size, tooltip) => ({ - value: [xAxis, yAxis], // x and y values - label: { - formatter: label.toString(), // Use array[0] as the label - }, - symbolSize: size, // Individual symbol size - tooltipValue: tooltip, //tooltip value - }); - const formatColorDataItem = ( - label, - xAxis, - yAxis, - color, - colorMap = null, - ) => { - if (!colorMap.has(color)) { - colorMap.set( - color, - data.option["color"][ - colorMap.size % data.option["color"]?.length - ], - ); - } - return { - value: [xAxis, yAxis], // x and y values - label: { - formatter: label.toString(), - }, - itemStyle: { - color: colorMap.get(color), - colorValue: color, - }, - }; - }; - const formatSizeDataItem = (label, xAxis, yAxis, size) => ({ - value: [xAxis, yAxis], // x and y values - label: { - formatter: label.toString(), // Use array[0] as the label - }, - symbolSize: size, // Individual symbol size - }); - const formatTooltipDataItem = (label, xAxis, yAxis, tooltip) => ({ - value: [xAxis, yAxis], // x and y values - label: { - formatter: label.toString(), // Use array[0] as the label - }, - tooltipValue: tooltip, //tooltip value - }); + const formatDataItem = ( + label, + xAxis, + yAxis, + size, + color, + tooltip, + colorMap = null, + ) => { + if (!colorMap.has(color)) { + colorMap.set( + color, + data.option["color"][ + colorMap.size % data.option["color"]?.length + ], + ); + } + return { + value: [xAxis, yAxis], // x and y values + label: { + formatter: label.toString(), // Use array[0] as the label + }, + symbolSize: size, // Individual symbol size + itemStyle: { + color: colorMap.get(color), + colorValue: color, + }, + tooltipValue: tooltip, //tooltip value + }; + }; + const formatData = (label, xAxis, yAxis, size, color, colorMap = null) => { + if (!colorMap.has(color)) { + colorMap.set( + color, + data.option["color"][ + colorMap.size % data.option["color"]?.length + ], + ); + } + return { + value: [xAxis, yAxis], // x and y values + label: { + formatter: label.toString(), // Use array[0] as the label + }, + symbolSize: size, // Individual symbol size + itemStyle: { + color: colorMap.get(color), + colorValue: color, + }, + }; + }; + const formatItemData = ( + label, + xAxis, + yAxis, + color, + tooltip, + colorMap = null, + ) => { + if (!colorMap.has(color)) { + colorMap.set( + color, + data.option["color"][ + colorMap.size % data.option["color"]?.length + ], + ); + } + return { + value: [xAxis, yAxis], // x and y values + label: { + formatter: label.toString(), // Use array[0] as the label + }, + itemStyle: { + color: colorMap.get(color), + colorValue: color, + }, + tooltipValue: tooltip, //tooltip value + }; + }; + const formatItems = (label, xAxis, yAxis, size, tooltip) => ({ + value: [xAxis, yAxis], // x and y values + label: { + formatter: label.toString(), // Use array[0] as the label + }, + symbolSize: size, // Individual symbol size + tooltipValue: tooltip, //tooltip value + }); + const formatColorDataItem = ( + label, + xAxis, + yAxis, + color, + colorMap = null, + ) => { + if (!colorMap.has(color)) { + colorMap.set( + color, + data.option["color"][ + colorMap.size % data.option["color"]?.length + ], + ); + } + return { + value: [xAxis, yAxis], // x and y values + label: { + formatter: label.toString(), + }, + itemStyle: { + color: colorMap.get(color), + colorValue: color, + }, + }; + }; + const formatSizeDataItem = (label, xAxis, yAxis, size) => ({ + value: [xAxis, yAxis], // x and y values + label: { + formatter: label.toString(), // Use array[0] as the label + }, + symbolSize: size, // Individual symbol size + }); + const formatTooltipDataItem = (label, xAxis, yAxis, tooltip) => ({ + value: [xAxis, yAxis], // x and y values + label: { + formatter: label.toString(), // Use array[0] as the label + }, + tooltipValue: tooltip, //tooltip value + }); - if (apiData["values"]) { - if (data.option.hasOwnProperty("_state")) { - if (data.option["_state"].hasOwnProperty("fields")) { - if (label && xAxis && yAxis && size && color && tooltip) { - const colorMap = new Map(); - if ( - xAxis === yAxis && - xAxis === size && - xAxis === color && - xAxis === tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[1], - item[1], - item[1], - colorMap, - ), - })); - } - if ( - xAxis == yAxis && - label == size && - label == color && - label == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[0], - item[0], - item[0], - colorMap, - ), - })); - } - if ( - xAxis == yAxis && - xAxis == size && - label == color && - label == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[1], - item[0], - item[0], - colorMap, - ), - })); - } - if ( - xAxis == yAxis && - xAxis == size && - label == color && - xAxis == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[1], - item[0], - item[1], - colorMap, - ), - })); - } - if ( - xAxis == yAxis && - label == size && - xAxis == color && - label == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[0], - item[1], - item[0], - colorMap, - ), - })); - } - if ( - xAxis == yAxis && - label == size && - label == color && - xAxis == tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[0], - item[0], - item[1], - colorMap, - ), - })); - } - if (xAxis == yAxis && size == color && size == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[2], - item[2], - colorMap, - ), - })); - } - if (xAxis == yAxis && label == color && size == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[0], - item[2], - colorMap, - ), - })); - } - if (xAxis == yAxis && size == tooltip && xAxis == color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[1], - item[2], - colorMap, - ), - })); - } - if (xAxis == yAxis && size == color && xAxis == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[2], - item[1], - colorMap, - ), - })); - } - if ( - xAxis === size && - xAxis === color && - xAxis === tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[1], - item[1], - colorMap, - ), - })); - } - if ( - yAxis === size && - yAxis === color && - yAxis === tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[2], - item[2], - colorMap, - ), - })); - } - if ( - xAxis === size && - xAxis === color && - yAxis === tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[1], - item[2], - colorMap, - ), - })); - } - if ( - xAxis === size && - yAxis === color && - xAxis === tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[2], - item[1], - colorMap, - ), - })); - } - if ( - yAxis === size && - xAxis === color && - xAxis === tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[1], - item[1], - colorMap, - ), - })); - } - if ( - yAxis === size && - yAxis === color && - xAxis === tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[2], - item[1], - colorMap, - ), - })); - } - if ( - yAxis === size && - xAxis === color && - yAxis === tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[1], - item[2], - colorMap, - ), - })); - } - if ( - xAxis === size && - yAxis === color && - yAxis === tooltip - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[2], - item[2], - colorMap, - ), - })); - } - if ( - xAxis === size && - xAxis === tooltip && - label === color - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[0], - item[1], - colorMap, - ), - })); - } - if ( - yAxis === size && - yAxis === tooltip && - label === color - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[0], - item[2], - colorMap, - ), - })); - } - if ( - xAxis === size && - yAxis === tooltip && - label === color - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[0], - item[2], - colorMap, - ), - })); - } - if ( - yAxis === size && - xAxis === tooltip && - label === color - ) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[0], - item[1], - colorMap, - ), - })); - } - if (xAxis == yAxis && label == size && xAxis == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[0], - item[2], - item[1], - colorMap, - ), - })); - } - if (xAxis == yAxis && xAxis == size && xAxis == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[1], - item[2], - item[1], - colorMap, - ), - })); - } - if (xAxis == yAxis && label == color && xAxis == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[0], - item[1], - colorMap, - ), - })); - } - if (xAxis == yAxis && label == size && label == color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[0], - item[0], - item[2], - colorMap, - ), - })); - } - if (xAxis == yAxis && label == color && label == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[0], - item[0], - colorMap, - ), - })); - } - if (xAxis == yAxis && label == size && label == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[0], - item[2], - item[0], - colorMap, - ), - })); - } - if (xAxis == yAxis && xAxis == size && xAxis == color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[1], - item[1], - item[2], - colorMap, - ), - })); - } - if (xAxis == yAxis && xAxis == size && xAxis == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[1], - item[2], - item[1], - colorMap, - ), - })); - } - if (xAxis == yAxis && xAxis == color && xAxis == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[1], - item[1], - colorMap, - ), - })); - } - if (xAxis === yAxis && xAxis === size && label === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[1], - item[0], - item[2], - colorMap, - ), - })); - } - if (size == color && xAxis == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[3], - item[1], - colorMap, - ), - })); - } - if (size == color && yAxis == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[3], - item[2], - colorMap, - ), - })); - } - if (size == color && yAxis == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[3], - item[2], - colorMap, - ), - })); - } - if (size == color && size == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[3], - item[3], - colorMap, - ), - })); - } - if (size == tooltip && xAxis == color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[1], - item[3], - colorMap, - ), - })); - } - if (size == tooltip && yAxis == color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[2], - item[3], - colorMap, - ), - })); - } - if (xAxis == yAxis && xAxis == size) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[1], - item[2], - item[3], - colorMap, - ), - })); - } - if (xAxis == yAxis && xAxis == color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[1], - item[3], - colorMap, - ), - })); - } - if (xAxis == yAxis && size == color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[2], - item[3], - colorMap, - ), - })); - } - if (xAxis == yAxis && xAxis == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[3], - item[1], - colorMap, - ), - })); - } - if (xAxis == yAxis && size == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[3], - item[2], - colorMap, - ), - })); - } - if (xAxis == yAxis && label == size) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[0], - item[2], - item[3], - colorMap, - ), - })); - } - if (xAxis == yAxis && label == color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[0], - item[3], - colorMap, - ), - })); - } - if (xAxis == yAxis && label == tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[3], - item[0], - colorMap, - ), - })); - } - if (xAxis == size && label == color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[0], - item[3], - colorMap, - ), - })); - } - if (yAxis === size && label === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[0], - item[3], - colorMap, - ), - })); - } - if (xAxis === tooltip && label === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[0], - item[1], - colorMap, - ), - })); - } - if (yAxis === tooltip && label === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[0], - item[2], - colorMap, - ), - })); - } - if (xAxis === size && xAxis === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[1], - item[3], - colorMap, - ), - })); - } - if (yAxis === size && yAxis === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[2], - item[3], - colorMap, - ), - })); - } - if (xAxis === size && xAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[3], - item[1], - colorMap, - ), - })); - } - if (yAxis === size && yAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[3], - item[2], - colorMap, - ), - })); - } - if (xAxis === color && xAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[1], - item[1], - colorMap, - ), - })); - } - if (yAxis === color && yAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[2], - item[2], - colorMap, - ), - })); - } - if (xAxis === size && yAxis === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[2], - item[3], - colorMap, - ), - })); - } - if (yAxis === size && xAxis === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[1], - item[3], - colorMap, - ), - })); - } - if (xAxis === size && yAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[3], - item[2], - colorMap, - ), - })); - } - if (yAxis === size && xAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[3], - item[1], - colorMap, - ), - })); - } - if (xAxis === color && yAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[1], - item[2], - colorMap, - ), - })); - } - if (yAxis === color && xAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[2], - item[1], - colorMap, - ), - })); - } - if (size === tooltip && label === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[0], - item[3], - colorMap, - ), - })); - } - if (xAxis == yAxis) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[1], - item[2], - item[3], - item[4], - colorMap, - ), - })); - } - if (label === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[0], - item[4], - colorMap, - ), - })); - } - if (size === label) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[4], - item[5], - colorMap, - ), - })); - } - if (tooltip === label) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[4], - item[5], - colorMap, - ), - })); - } - if (xAxis === size) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[1], - item[3], - item[4], - colorMap, - ), - })); - } - if (xAxis === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[1], - item[4], - colorMap, - ), - })); - } - if (xAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[4], - item[1], - colorMap, - ), - })); - } - if (yAxis === size) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[2], - item[3], - item[4], - colorMap, - ), - })); - } - if (yAxis === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[2], - item[4], - colorMap, - ), - })); - } - if (yAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[4], - item[2], - colorMap, - ), - })); - } - if (size === color) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[3], - item[4], - colorMap, - ), - })); - } - if (size === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[4], - item[3], - colorMap, - ), - })); - } - if (color === tooltip) { - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[4], - item[4], - colorMap, - ), - })); - } - return apiData.values.map((item) => ({ - ...formatDataItem( - item[0], - item[1], - item[2], - item[3], - item[4], - item[5], - colorMap, - ), - })); - } - if (label && xAxis && yAxis && size && color) { - const colorMap = new Map(); - if (xAxis == yAxis && xAxis == size && label == color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[1], - item[1], - item[0], - colorMap, - ), - })); - } - if (xAxis == yAxis && xAxis == size && xAxis == color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[1], - item[1], - item[1], - colorMap, - ), - })); - } - if (xAxis == yAxis && xAxis == color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[1], - item[2], - item[1], - colorMap, - ), - })); - } - if (xAxis == yAxis && size == color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[1], - item[2], - item[2], - colorMap, - ), - })); - } - if (xAxis == yAxis && label == color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[1], - item[2], - item[0], - colorMap, - ), - })); - } - if (xAxis == yAxis && xAxis == size) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[1], - item[1], - item[2], - colorMap, - ), - })); - } - if (xAxis === size && xAxis === color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[1], - item[1], - colorMap, - ), - })); - } - if (yAxis === size && yAxis === color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[2], - item[2], - colorMap, - ), - })); - } - if (xAxis === size && yAxis === color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[1], - item[2], - colorMap, - ), - })); - } - if (yAxis === size && xAxis === color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[2], - item[1], - colorMap, - ), - })); - } - if (xAxis === size && label === color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[1], - item[0], - colorMap, - ), - })); - } - if (yAxis === size && label === color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[2], - item[0], - colorMap, - ), - })); - } - if (xAxis == yAxis) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[1], - item[2], - item[3], - colorMap, - ), - })); - } - if (label === color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[3], - item[0], - colorMap, - ), - })); - } - if (size === color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[3], - item[3], - colorMap, - ), - })); - } - if (xAxis === size) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[1], - item[3], - colorMap, - ), - })); - } - if (yAxis === size) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[2], - item[3], - colorMap, - ), - })); - } - if (xAxis === color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[3], - item[1], - colorMap, - ), - })); - } - if (yAxis === color) { - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[3], - item[2], - colorMap, - ), - })); - } - return apiData.values.map((item) => ({ - ...formatData( - item[0], - item[1], - item[2], - item[3], - item[4], - colorMap, - ), - })); - } - if (label && xAxis && yAxis && color && tooltip) { - const colorMap = new Map(); - if (xAxis == yAxis && xAxis == tooltip && label == color) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[1], - item[0], - item[1], - colorMap, - ), - })); - } - if (xAxis == yAxis && xAxis == tooltip && xAxis == color) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[1], - item[1], - item[1], - colorMap, - ), - })); - } - if (xAxis == yAxis && xAxis == color) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[1], - item[1], - item[2], - colorMap, - ), - })); - } - if (xAxis == yAxis && label == color) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[1], - item[0], - item[2], - colorMap, - ), - })); - } - if (xAxis == yAxis && xAxis == tooltip) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[1], - item[2], - item[1], - colorMap, - ), - })); - } - if (xAxis == color && xAxis == tooltip) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[1], - item[1], - colorMap, - ), - })); - } - if (yAxis === color && yAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[2], - item[2], - colorMap, - ), - })); - } - if (xAxis === color && yAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[1], - item[1], - colorMap, - ), - })); - } - if (yAxis === color && xAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[2], - item[1], - colorMap, - ), - })); - } - if (xAxis === tooltip && label === color) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[0], - item[1], - colorMap, - ), - })); - } - if (yAxis === tooltip && label === color) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[0], - item[2], - colorMap, - ), - })); - } - if (xAxis == yAxis) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[1], - item[2], - item[3], - colorMap, - ), - })); - } - if (label === color) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[0], - item[3], - colorMap, - ), - })); - } - if (color === tooltip) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[3], - item[3], - colorMap, - ), - })); - } - if (xAxis === color) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[1], - item[3], - colorMap, - ), - })); - } - if (yAxis === color) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[2], - item[3], - colorMap, - ), - })); - } - if (xAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[3], - item[1], - colorMap, - ), - })); - } - if (yAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[3], - item[2], - colorMap, - ), - })); - } - return apiData.values.map((item) => ({ - ...formatItemData( - item[0], - item[1], - item[2], - item[3], - item[4], - colorMap, - ), - })); - } - if (label && xAxis && yAxis && size && tooltip) { - if (xAxis == yAxis && xAxis == size && xAxis == tooltip) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[1], - item[1], - item[1], - ), - })); - } - if (xAxis == yAxis && xAxis == size) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[1], - item[1], - item[2], - ), - })); - } - if (xAxis == yAxis && xAxis == tooltip) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[1], - item[2], - item[1], - ), - })); - } - if (xAxis == yAxis && size == tooltip) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[1], - item[2], - item[2], - ), - })); - } - if (xAxis === size && xAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[2], - item[1], - item[1], - ), - })); - } - if (yAxis === size && yAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[2], - item[2], - item[2], - ), - })); - } - if (xAxis === size && yAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[2], - item[1], - item[2], - ), - })); - } - if (yAxis === size && xAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[2], - item[2], - item[1], - ), - })); - } - if (xAxis == yAxis) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[1], - item[2], - item[3], - ), - })); - } - if (size === tooltip) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[2], - item[3], - item[3], - ), - })); - } - if (xAxis === size) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[2], - item[1], - item[3], - ), - })); - } - if (yAxis === size) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[2], - item[2], - item[3], - ), - })); - } - if (xAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[2], - item[3], - item[1], - ), - })); - } - if (yAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[2], - item[3], - item[2], - ), - })); - } - return apiData.values.map((item) => ({ - ...formatItems( - item[0], - item[1], - item[2], - item[4], - item[4], - ), - })); - } - if (label && xAxis && yAxis && color) { - const colorMap = new Map(); - if (xAxis === yAxis && xAxis === color) { - return apiData.values.map((item) => ({ - ...formatColorDataItem( - item[0], - item[1], - item[1], - item[1], - colorMap, - ), - })); - } - if (xAxis === yAxis && label === color) { - return apiData.values.map((item) => ({ - ...formatColorDataItem( - item[0], - item[1], - item[1], - item[0], - colorMap, - ), - })); - } - if (xAxis === yAxis) { - return apiData.values.map((item) => ({ - ...formatColorDataItem( - item[0], - item[1], - item[1], - item[2], - colorMap, - ), - })); - } - if (xAxis === color) { - return apiData.values.map((item) => ({ - ...formatColorDataItem( - item[0], - item[1], - item[2], - item[1], - colorMap, - ), - })); - } - if (yAxis === color) { - return apiData.values.map((item) => ({ - ...formatColorDataItem( - item[0], - item[1], - item[2], - item[2], - colorMap, - ), - })); - } - if (label === color) { - return apiData.values.map((item) => ({ - ...formatColorDataItem( - item[0], - item[1], - item[2], - item[0], - colorMap, - ), - })); - } - return apiData.values.map((item, index) => ({ - ...formatColorDataItem( - item[0], - item[1], - item[2], - item[3], - colorMap, - ), - })); - } - if (label && xAxis && yAxis && size) { - if (xAxis === yAxis && xAxis === size) { - return apiData.values.map((item) => ({ - ...formatSizeDataItem( - item[0], - item[1], - item[1], - item[1], - ), - })); - } - if (xAxis === yAxis) { - return apiData.values.map((item) => ({ - ...formatSizeDataItem( - item[0], - item[1], - item[1], - item[2], - ), - })); - } - if (xAxis === size) { - return apiData.values.map((item) => ({ - ...formatSizeDataItem( - item[0], - item[1], - item[2], - item[1], - ), - })); - } - if (yAxis === size) { - return apiData.values.map((item) => ({ - ...formatSizeDataItem( - item[0], - item[1], - item[2], - item[2], - ), - })); - } - return apiData.values.map((item) => ({ - ...formatSizeDataItem( - item[0], - item[1], - item[2], - item[3], - ), - })); - } - if (label && xAxis && yAxis && tooltip) { - if (xAxis === yAxis && xAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatTooltipDataItem( - item[0], - item[1], - item[1], - item[1], - ), - })); - } - if (xAxis === yAxis) { - return apiData.values.map((item) => ({ - ...formatTooltipDataItem( - item[0], - item[1], - item[1], - item[2], - ), - })); - } - if (xAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatTooltipDataItem( - item[0], - item[1], - item[2], - item[1], - ), - })); - } - if (yAxis === tooltip) { - return apiData.values.map((item) => ({ - ...formatTooltipDataItem( - item[0], - item[1], - item[2], - item[2], - ), - })); - } - return apiData.values.map((item) => ({ - ...formatTooltipDataItem( - item[0], - item[1], - item[2], - item[3], - ), - })); - } - } - } - if (label && xAxis && yAxis) { - { - if (xAxis === yAxis) { - return apiData.values.map((item) => ({ - ...formatItem(item[0], item[1], item[1]), - })); - } - return apiData.values.map((item) => ({ - ...formatItem(item[0], item[1], item[2]), - })); - } - } - } + if (apiData["values"]) { + if (Object.hasOwn(data.option, "_state")) { + if (Object.hasOwn(data.option["_state"], "fields")) { + if (label && xAxis && yAxis && size && color && tooltip) { + const colorMap = new Map(); + if ( + xAxis === yAxis && + xAxis === size && + xAxis === color && + xAxis === tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[1], + item[1], + item[1], + colorMap, + ), + })); + } + if ( + xAxis == yAxis && + label == size && + label == color && + label == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[0], + item[0], + item[0], + colorMap, + ), + })); + } + if ( + xAxis == yAxis && + xAxis == size && + label == color && + label == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[1], + item[0], + item[0], + colorMap, + ), + })); + } + if ( + xAxis == yAxis && + xAxis == size && + label == color && + xAxis == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[1], + item[0], + item[1], + colorMap, + ), + })); + } + if ( + xAxis == yAxis && + label == size && + xAxis == color && + label == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[0], + item[1], + item[0], + colorMap, + ), + })); + } + if ( + xAxis == yAxis && + label == size && + label == color && + xAxis == tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[0], + item[0], + item[1], + colorMap, + ), + })); + } + if (xAxis == yAxis && size == color && size == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[2], + item[2], + colorMap, + ), + })); + } + if (xAxis == yAxis && label == color && size == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[0], + item[2], + colorMap, + ), + })); + } + if (xAxis == yAxis && size == tooltip && xAxis == color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[1], + item[2], + colorMap, + ), + })); + } + if (xAxis == yAxis && size == color && xAxis == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[2], + item[1], + colorMap, + ), + })); + } + if ( + xAxis === size && + xAxis === color && + xAxis === tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[1], + item[1], + colorMap, + ), + })); + } + if ( + yAxis === size && + yAxis === color && + yAxis === tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[2], + item[2], + colorMap, + ), + })); + } + if ( + xAxis === size && + xAxis === color && + yAxis === tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[1], + item[2], + colorMap, + ), + })); + } + if ( + xAxis === size && + yAxis === color && + xAxis === tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[2], + item[1], + colorMap, + ), + })); + } + if ( + yAxis === size && + xAxis === color && + xAxis === tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[1], + item[1], + colorMap, + ), + })); + } + if ( + yAxis === size && + yAxis === color && + xAxis === tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[2], + item[1], + colorMap, + ), + })); + } + if ( + yAxis === size && + xAxis === color && + yAxis === tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[1], + item[2], + colorMap, + ), + })); + } + if ( + xAxis === size && + yAxis === color && + yAxis === tooltip + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[2], + item[2], + colorMap, + ), + })); + } + if ( + xAxis === size && + xAxis === tooltip && + label === color + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[0], + item[1], + colorMap, + ), + })); + } + if ( + yAxis === size && + yAxis === tooltip && + label === color + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[0], + item[2], + colorMap, + ), + })); + } + if ( + xAxis === size && + yAxis === tooltip && + label === color + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[0], + item[2], + colorMap, + ), + })); + } + if ( + yAxis === size && + xAxis === tooltip && + label === color + ) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[0], + item[1], + colorMap, + ), + })); + } + if (xAxis == yAxis && label == size && xAxis == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[0], + item[2], + item[1], + colorMap, + ), + })); + } + if (xAxis == yAxis && xAxis == size && xAxis == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[1], + item[2], + item[1], + colorMap, + ), + })); + } + if (xAxis == yAxis && label == color && xAxis == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[0], + item[1], + colorMap, + ), + })); + } + if (xAxis == yAxis && label == size && label == color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[0], + item[0], + item[2], + colorMap, + ), + })); + } + if (xAxis == yAxis && label == color && label == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[0], + item[0], + colorMap, + ), + })); + } + if (xAxis == yAxis && label == size && label == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[0], + item[2], + item[0], + colorMap, + ), + })); + } + if (xAxis == yAxis && xAxis == size && xAxis == color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[1], + item[1], + item[2], + colorMap, + ), + })); + } + if (xAxis == yAxis && xAxis == size && xAxis == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[1], + item[2], + item[1], + colorMap, + ), + })); + } + if (xAxis == yAxis && xAxis == color && xAxis == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[1], + item[1], + colorMap, + ), + })); + } + if (xAxis === yAxis && xAxis === size && label === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[1], + item[0], + item[2], + colorMap, + ), + })); + } + if (size == color && xAxis == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[3], + item[1], + colorMap, + ), + })); + } + if (size == color && yAxis == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[3], + item[2], + colorMap, + ), + })); + } + if (size == color && yAxis == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[3], + item[2], + colorMap, + ), + })); + } + if (size == color && size == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[3], + item[3], + colorMap, + ), + })); + } + if (size == tooltip && xAxis == color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[1], + item[3], + colorMap, + ), + })); + } + if (size == tooltip && yAxis == color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[2], + item[3], + colorMap, + ), + })); + } + if (xAxis == yAxis && xAxis == size) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[1], + item[2], + item[3], + colorMap, + ), + })); + } + if (xAxis == yAxis && xAxis == color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[1], + item[3], + colorMap, + ), + })); + } + if (xAxis == yAxis && size == color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[2], + item[3], + colorMap, + ), + })); + } + if (xAxis == yAxis && xAxis == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[3], + item[1], + colorMap, + ), + })); + } + if (xAxis == yAxis && size == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[3], + item[2], + colorMap, + ), + })); + } + if (xAxis == yAxis && label == size) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[0], + item[2], + item[3], + colorMap, + ), + })); + } + if (xAxis == yAxis && label == color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[0], + item[3], + colorMap, + ), + })); + } + if (xAxis == yAxis && label == tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[3], + item[0], + colorMap, + ), + })); + } + if (xAxis == size && label == color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[0], + item[3], + colorMap, + ), + })); + } + if (yAxis === size && label === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[0], + item[3], + colorMap, + ), + })); + } + if (xAxis === tooltip && label === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[0], + item[1], + colorMap, + ), + })); + } + if (yAxis === tooltip && label === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[0], + item[2], + colorMap, + ), + })); + } + if (xAxis === size && xAxis === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[1], + item[3], + colorMap, + ), + })); + } + if (yAxis === size && yAxis === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[2], + item[3], + colorMap, + ), + })); + } + if (xAxis === size && xAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[3], + item[1], + colorMap, + ), + })); + } + if (yAxis === size && yAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[3], + item[2], + colorMap, + ), + })); + } + if (xAxis === color && xAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[1], + item[1], + colorMap, + ), + })); + } + if (yAxis === color && yAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[2], + item[2], + colorMap, + ), + })); + } + if (xAxis === size && yAxis === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[2], + item[3], + colorMap, + ), + })); + } + if (yAxis === size && xAxis === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[1], + item[3], + colorMap, + ), + })); + } + if (xAxis === size && yAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[3], + item[2], + colorMap, + ), + })); + } + if (yAxis === size && xAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[3], + item[1], + colorMap, + ), + })); + } + if (xAxis === color && yAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[1], + item[2], + colorMap, + ), + })); + } + if (yAxis === color && xAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[2], + item[1], + colorMap, + ), + })); + } + if (size === tooltip && label === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[0], + item[3], + colorMap, + ), + })); + } + if (xAxis == yAxis) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[1], + item[2], + item[3], + item[4], + colorMap, + ), + })); + } + if (label === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[0], + item[4], + colorMap, + ), + })); + } + if (size === label) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[4], + item[5], + colorMap, + ), + })); + } + if (tooltip === label) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[4], + item[5], + colorMap, + ), + })); + } + if (xAxis === size) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[1], + item[3], + item[4], + colorMap, + ), + })); + } + if (xAxis === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[1], + item[4], + colorMap, + ), + })); + } + if (xAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[4], + item[1], + colorMap, + ), + })); + } + if (yAxis === size) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[2], + item[3], + item[4], + colorMap, + ), + })); + } + if (yAxis === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[2], + item[4], + colorMap, + ), + })); + } + if (yAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[4], + item[2], + colorMap, + ), + })); + } + if (size === color) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[3], + item[4], + colorMap, + ), + })); + } + if (size === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[4], + item[3], + colorMap, + ), + })); + } + if (color === tooltip) { + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[4], + item[4], + colorMap, + ), + })); + } + return apiData.values.map((item) => ({ + ...formatDataItem( + item[0], + item[1], + item[2], + item[3], + item[4], + item[5], + colorMap, + ), + })); + } + if (label && xAxis && yAxis && size && color) { + const colorMap = new Map(); + if (xAxis == yAxis && xAxis == size && label == color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[1], + item[1], + item[0], + colorMap, + ), + })); + } + if (xAxis == yAxis && xAxis == size && xAxis == color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[1], + item[1], + item[1], + colorMap, + ), + })); + } + if (xAxis == yAxis && xAxis == color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[1], + item[2], + item[1], + colorMap, + ), + })); + } + if (xAxis == yAxis && size == color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[1], + item[2], + item[2], + colorMap, + ), + })); + } + if (xAxis == yAxis && label == color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[1], + item[2], + item[0], + colorMap, + ), + })); + } + if (xAxis == yAxis && xAxis == size) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[1], + item[1], + item[2], + colorMap, + ), + })); + } + if (xAxis === size && xAxis === color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[1], + item[1], + colorMap, + ), + })); + } + if (yAxis === size && yAxis === color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[2], + item[2], + colorMap, + ), + })); + } + if (xAxis === size && yAxis === color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[1], + item[2], + colorMap, + ), + })); + } + if (yAxis === size && xAxis === color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[2], + item[1], + colorMap, + ), + })); + } + if (xAxis === size && label === color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[1], + item[0], + colorMap, + ), + })); + } + if (yAxis === size && label === color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[2], + item[0], + colorMap, + ), + })); + } + if (xAxis == yAxis) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[1], + item[2], + item[3], + colorMap, + ), + })); + } + if (label === color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[3], + item[0], + colorMap, + ), + })); + } + if (size === color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[3], + item[3], + colorMap, + ), + })); + } + if (xAxis === size) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[1], + item[3], + colorMap, + ), + })); + } + if (yAxis === size) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[2], + item[3], + colorMap, + ), + })); + } + if (xAxis === color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[3], + item[1], + colorMap, + ), + })); + } + if (yAxis === color) { + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[3], + item[2], + colorMap, + ), + })); + } + return apiData.values.map((item) => ({ + ...formatData( + item[0], + item[1], + item[2], + item[3], + item[4], + colorMap, + ), + })); + } + if (label && xAxis && yAxis && color && tooltip) { + const colorMap = new Map(); + if (xAxis == yAxis && xAxis == tooltip && label == color) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[1], + item[0], + item[1], + colorMap, + ), + })); + } + if (xAxis == yAxis && xAxis == tooltip && xAxis == color) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[1], + item[1], + item[1], + colorMap, + ), + })); + } + if (xAxis == yAxis && xAxis == color) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[1], + item[1], + item[2], + colorMap, + ), + })); + } + if (xAxis == yAxis && label == color) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[1], + item[0], + item[2], + colorMap, + ), + })); + } + if (xAxis == yAxis && xAxis == tooltip) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[1], + item[2], + item[1], + colorMap, + ), + })); + } + if (xAxis == color && xAxis == tooltip) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[1], + item[1], + colorMap, + ), + })); + } + if (yAxis === color && yAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[2], + item[2], + colorMap, + ), + })); + } + if (xAxis === color && yAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[1], + item[1], + colorMap, + ), + })); + } + if (yAxis === color && xAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[2], + item[1], + colorMap, + ), + })); + } + if (xAxis === tooltip && label === color) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[0], + item[1], + colorMap, + ), + })); + } + if (yAxis === tooltip && label === color) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[0], + item[2], + colorMap, + ), + })); + } + if (xAxis == yAxis) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[1], + item[2], + item[3], + colorMap, + ), + })); + } + if (label === color) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[0], + item[3], + colorMap, + ), + })); + } + if (color === tooltip) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[3], + item[3], + colorMap, + ), + })); + } + if (xAxis === color) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[1], + item[3], + colorMap, + ), + })); + } + if (yAxis === color) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[2], + item[3], + colorMap, + ), + })); + } + if (xAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[3], + item[1], + colorMap, + ), + })); + } + if (yAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[3], + item[2], + colorMap, + ), + })); + } + return apiData.values.map((item) => ({ + ...formatItemData( + item[0], + item[1], + item[2], + item[3], + item[4], + colorMap, + ), + })); + } + if (label && xAxis && yAxis && size && tooltip) { + if (xAxis == yAxis && xAxis == size && xAxis == tooltip) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[1], + item[1], + item[1], + ), + })); + } + if (xAxis == yAxis && xAxis == size) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[1], + item[1], + item[2], + ), + })); + } + if (xAxis == yAxis && xAxis == tooltip) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[1], + item[2], + item[1], + ), + })); + } + if (xAxis == yAxis && size == tooltip) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[1], + item[2], + item[2], + ), + })); + } + if (xAxis === size && xAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[2], + item[1], + item[1], + ), + })); + } + if (yAxis === size && yAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[2], + item[2], + item[2], + ), + })); + } + if (xAxis === size && yAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[2], + item[1], + item[2], + ), + })); + } + if (yAxis === size && xAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[2], + item[2], + item[1], + ), + })); + } + if (xAxis == yAxis) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[1], + item[2], + item[3], + ), + })); + } + if (size === tooltip) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[2], + item[3], + item[3], + ), + })); + } + if (xAxis === size) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[2], + item[1], + item[3], + ), + })); + } + if (yAxis === size) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[2], + item[2], + item[3], + ), + })); + } + if (xAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[2], + item[3], + item[1], + ), + })); + } + if (yAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[2], + item[3], + item[2], + ), + })); + } + return apiData.values.map((item) => ({ + ...formatItems( + item[0], + item[1], + item[2], + item[4], + item[4], + ), + })); + } + if (label && xAxis && yAxis && color) { + const colorMap = new Map(); + if (xAxis === yAxis && xAxis === color) { + return apiData.values.map((item) => ({ + ...formatColorDataItem( + item[0], + item[1], + item[1], + item[1], + colorMap, + ), + })); + } + if (xAxis === yAxis && label === color) { + return apiData.values.map((item) => ({ + ...formatColorDataItem( + item[0], + item[1], + item[1], + item[0], + colorMap, + ), + })); + } + if (xAxis === yAxis) { + return apiData.values.map((item) => ({ + ...formatColorDataItem( + item[0], + item[1], + item[1], + item[2], + colorMap, + ), + })); + } + if (xAxis === color) { + return apiData.values.map((item) => ({ + ...formatColorDataItem( + item[0], + item[1], + item[2], + item[1], + colorMap, + ), + })); + } + if (yAxis === color) { + return apiData.values.map((item) => ({ + ...formatColorDataItem( + item[0], + item[1], + item[2], + item[2], + colorMap, + ), + })); + } + if (label === color) { + return apiData.values.map((item) => ({ + ...formatColorDataItem( + item[0], + item[1], + item[2], + item[0], + colorMap, + ), + })); + } + return apiData.values.map((item, index) => ({ + ...formatColorDataItem( + item[0], + item[1], + item[2], + item[3], + colorMap, + ), + })); + } + if (label && xAxis && yAxis && size) { + if (xAxis === yAxis && xAxis === size) { + return apiData.values.map((item) => ({ + ...formatSizeDataItem( + item[0], + item[1], + item[1], + item[1], + ), + })); + } + if (xAxis === yAxis) { + return apiData.values.map((item) => ({ + ...formatSizeDataItem( + item[0], + item[1], + item[1], + item[2], + ), + })); + } + if (xAxis === size) { + return apiData.values.map((item) => ({ + ...formatSizeDataItem( + item[0], + item[1], + item[2], + item[1], + ), + })); + } + if (yAxis === size) { + return apiData.values.map((item) => ({ + ...formatSizeDataItem( + item[0], + item[1], + item[2], + item[2], + ), + })); + } + return apiData.values.map((item) => ({ + ...formatSizeDataItem( + item[0], + item[1], + item[2], + item[3], + ), + })); + } + if (label && xAxis && yAxis && tooltip) { + if (xAxis === yAxis && xAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatTooltipDataItem( + item[0], + item[1], + item[1], + item[1], + ), + })); + } + if (xAxis === yAxis) { + return apiData.values.map((item) => ({ + ...formatTooltipDataItem( + item[0], + item[1], + item[1], + item[2], + ), + })); + } + if (xAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatTooltipDataItem( + item[0], + item[1], + item[2], + item[1], + ), + })); + } + if (yAxis === tooltip) { + return apiData.values.map((item) => ({ + ...formatTooltipDataItem( + item[0], + item[1], + item[2], + item[2], + ), + })); + } + return apiData.values.map((item) => ({ + ...formatTooltipDataItem( + item[0], + item[1], + item[2], + item[3], + ), + })); + } + } + } + if (label && xAxis && yAxis) { + if (xAxis === yAxis) { + return apiData.values.map((item) => ({ + ...formatItem(item[0], item[1], item[1]), + })); + } + return apiData.values.map((item) => ({ + ...formatItem(item[0], item[1], item[2]), + })); + } + } }; diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/scatter-plot/ScatterPlotSelector.ts b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/scatter-plot/ScatterPlotSelector.ts index f56641778b..e2d5c5f155 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/scatter-plot/ScatterPlotSelector.ts +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/scatter-plot/ScatterPlotSelector.ts @@ -1,509 +1,509 @@ export const getSelector = (data, aggregates) => { - let fields = "", - label = "", - xAxis = "", - yAxis = "", - size = "", - color = "", - tooltip = "", - labelName = "", - xAxisName = "", - yAxisName = ""; - if (data.option.hasOwnProperty("_state")) { - fields = data.option["_state"]["fields"]; - label = fields["label"]; - xAxis = fields["XAxis"]; - yAxis = fields["YAxis"]; - size = fields["size"]; - color = fields["color"]; - tooltip = fields["tooltip"]; - labelName = data.option["series"][0]["label"]["name"]; - xAxisName = data.option["xAxis"]["pixelName"]; - yAxisName = data.option["yAxis"]["pixelName"]; - } - const getSelectorType = (type) => { - if (!fields[type]) return ""; - return fields[type][0] === "NUMBER" ? "Average" : "Count"; - }; + let fields = "", + label = "", + xAxis = "", + yAxis = "", + size = "", + color = "", + tooltip = "", + labelName = "", + xAxisName = "", + yAxisName = ""; + if (Object.hasOwn(data.option, "_state")) { + fields = data.option["_state"]["fields"]; + label = fields["label"]; + xAxis = fields["XAxis"]; + yAxis = fields["YAxis"]; + size = fields["size"]; + color = fields["color"]; + tooltip = fields["tooltip"]; + labelName = data.option["series"][0]["label"]["name"]; + xAxisName = data.option["xAxis"]["pixelName"]; + yAxisName = data.option["yAxis"]["pixelName"]; + } + const getSelectorType = (type) => { + if (!fields[type]) return ""; + return fields[type][0] === "NUMBER" ? "Average" : "Count"; + }; - const getAggregates = (field) => { - if ( - !fields[field] || - !aggregates[field] || - Object.values(aggregates[field]).length === 0 - ) - return ""; - return Object.values(aggregates[field])[0]; - }; - const getSelectors = () => { - return { - xAxis: getAggregates("XAxis"), - yAxis: getAggregates("YAxis"), - size: getAggregates("size"), - tooltip: getAggregates("tooltip"), - }; - }; - const selectors = getSelectors(); - let selector = ""; + const getAggregates = (field) => { + if ( + !fields[field] || + !aggregates[field] || + Object.values(aggregates[field]).length === 0 + ) + return ""; + return Object.values(aggregates[field])[0]; + }; + const getSelectors = () => { + return { + xAxis: getAggregates("XAxis"), + yAxis: getAggregates("YAxis"), + size: getAggregates("size"), + tooltip: getAggregates("tooltip"), + }; + }; + const selectors = getSelectors(); + let selector = ""; - if (data.option.hasOwnProperty("_state")) { - if (data.option["_state"].hasOwnProperty("fields")) { - if (label && xAxis && yAxis && size && color && tooltip) { - if ( - xAxis == yAxis && - xAxis == size && - xAxis == color && - xAxis == tooltip - ) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); - } - if ( - xAxis == yAxis && - label == size && - label == color && - label == tooltip - ) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); - } - if ( - xAxis == yAxis && - label == size && - label == color && - label == tooltip - ) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); - } - if ( - xAxis == yAxis && - xAxis == size && - label == color && - xAxis == tooltip - ) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); - } - if ( - xAxis == yAxis && - label == size && - xAxis == color && - label == tooltip - ) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); - } - if ( - xAxis == yAxis && - label == size && - label == color && - xAxis == tooltip - ) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); - } - if ( - xAxis == yAxis && - (size == color || label == color) && - size == tooltip - ) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${size}])|Group(${labelName})`); - } - if (xAxis == yAxis && label == color && xAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${size}])|Group(${labelName})`); - } - if (xAxis == yAxis && xAxis == color && size == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${size}])|Group(${labelName})`); - } - if (xAxis == yAxis && xAxis == tooltip && size == color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${size}])|Group(${labelName})`); - } - if (xAxis == size && xAxis == color && xAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (yAxis == size && yAxis == color && yAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (xAxis == size && xAxis == color && yAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (xAxis == size && yAxis == color && xAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (yAxis == size && xAxis == color && xAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (yAxis == size && yAxis == color && xAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (yAxis == size && xAxis == color && yAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (xAxis == size && yAxis == color && yAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if ( - (xAxis == size && xAxis == tooltip && label == color) || - (yAxis == size && yAxis == tooltip && label == color) || - (xAxis == size && yAxis == tooltip && label == color) || - (yAxis == size && xAxis == tooltip && label == color) - ) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if ( - xAxis == yAxis && - (label == size || xAxis == size) && - label == color - ) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${tooltip}])|Group(${labelName})`); - } - if (xAxis == yAxis && label == color && label == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${size}])|Group(${labelName})`); - } - if (xAxis == yAxis && label == size && label == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),(${color})).as([${labelName}, ${xAxisName},${color}])|Group(${labelName},${color})`); - } - if (xAxis == yAxis && xAxis == size && xAxis == color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${tooltip}])|Group(${labelName})`); - } - if (xAxis == yAxis && xAxis == size && xAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),(${color})).as([${labelName}, ${xAxisName},${color}])|Group(${labelName},${color})`); - } - if (xAxis == yAxis && xAxis == color && xAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${size}])|Group(${labelName})`); - } - if (xAxis === yAxis && xAxis === size && label === color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${tooltip}])|Group(${labelName})`); - } - if (xAxis == yAxis && xAxis == size) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${color},${tooltip}])|Group(${labelName},${color})`); - } - if ( - (size == color && xAxis == tooltip) || - yAxis == tooltip || - (size == color && size == tooltip) || - (size == tooltip && xAxis == color) || - yAxis == color - ) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); - } + if (Object.hasOwn(data.option, "_state")) { + if (Object.hasOwn(data.option["_state"], "fields")) { + if (label && xAxis && yAxis && size && color && tooltip) { + if ( + xAxis == yAxis && + xAxis == size && + xAxis == color && + xAxis == tooltip + ) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); + } + if ( + xAxis == yAxis && + label == size && + label == color && + label == tooltip + ) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); + } + if ( + xAxis == yAxis && + label == size && + label == color && + label == tooltip + ) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); + } + if ( + xAxis == yAxis && + xAxis == size && + label == color && + xAxis == tooltip + ) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); + } + if ( + xAxis == yAxis && + label == size && + xAxis == color && + label == tooltip + ) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); + } + if ( + xAxis == yAxis && + label == size && + label == color && + xAxis == tooltip + ) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); + } + if ( + xAxis == yAxis && + (size == color || label == color) && + size == tooltip + ) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${size}])|Group(${labelName})`); + } + if (xAxis == yAxis && label == color && xAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${size}])|Group(${labelName})`); + } + if (xAxis == yAxis && xAxis == color && size == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${size}])|Group(${labelName})`); + } + if (xAxis == yAxis && xAxis == tooltip && size == color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${size}])|Group(${labelName})`); + } + if (xAxis == size && xAxis == color && xAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (yAxis == size && yAxis == color && yAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (xAxis == size && xAxis == color && yAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (xAxis == size && yAxis == color && xAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (yAxis == size && xAxis == color && xAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (yAxis == size && yAxis == color && xAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (yAxis == size && xAxis == color && yAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (xAxis == size && yAxis == color && yAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if ( + (xAxis == size && xAxis == tooltip && label == color) || + (yAxis == size && yAxis == tooltip && label == color) || + (xAxis == size && yAxis == tooltip && label == color) || + (yAxis == size && xAxis == tooltip && label == color) + ) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if ( + xAxis == yAxis && + (label == size || xAxis == size) && + label == color + ) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${tooltip}])|Group(${labelName})`); + } + if (xAxis == yAxis && label == color && label == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${size}])|Group(${labelName})`); + } + if (xAxis == yAxis && label == size && label == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),(${color})).as([${labelName}, ${xAxisName},${color}])|Group(${labelName},${color})`); + } + if (xAxis == yAxis && xAxis == size && xAxis == color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${tooltip}])|Group(${labelName})`); + } + if (xAxis == yAxis && xAxis == size && xAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),(${color})).as([${labelName}, ${xAxisName},${color}])|Group(${labelName},${color})`); + } + if (xAxis == yAxis && xAxis == color && xAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${size}])|Group(${labelName})`); + } + if (xAxis === yAxis && xAxis === size && label === color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${tooltip}])|Group(${labelName})`); + } + if (xAxis == yAxis && xAxis == size) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${color},${tooltip}])|Group(${labelName},${color})`); + } + if ( + (size == color && xAxis == tooltip) || + yAxis == tooltip || + (size == color && size == tooltip) || + (size == tooltip && xAxis == color) || + yAxis == color + ) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); + } - if ((xAxis == yAxis && xAxis == color) || size == color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${size},${tooltip}])|Group(${labelName})`); - } - if ((xAxis == yAxis && xAxis == tooltip) || size == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${xAxisName},${size},${color}])|Group(${labelName},${color})`); - } - if (xAxis == yAxis && label == size) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${color},${tooltip}])|Group(${labelName},${color})`); - } - if (xAxis == yAxis && label == color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${size},${tooltip}])|Group(${labelName})`); - } - if (xAxis == yAxis && label == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${xAxisName},${size},${color}])|Group(${labelName},${color})`); - } - if (xAxis == yAxis && label == size && xAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),(${color})).as([${labelName}, ${xAxisName}${color}])|Group(${labelName},${color})`); - } + if ((xAxis == yAxis && xAxis == color) || size == color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${size},${tooltip}])|Group(${labelName})`); + } + if ((xAxis == yAxis && xAxis == tooltip) || size == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${xAxisName},${size},${color}])|Group(${labelName},${color})`); + } + if (xAxis == yAxis && label == size) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${color},${tooltip}])|Group(${labelName},${color})`); + } + if (xAxis == yAxis && label == color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${size},${tooltip}])|Group(${labelName})`); + } + if (xAxis == yAxis && label == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${xAxisName},${size},${color}])|Group(${labelName},${color})`); + } + if (xAxis == yAxis && label == size && xAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),(${color})).as([${labelName}, ${xAxisName}${color}])|Group(${labelName},${color})`); + } - if ( - (xAxis == size && label == color) || - (yAxis == size && label == color) - ) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); - } - if ( - (xAxis == tooltip && label == color) || - (yAxis == tooltip && label == color) - ) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); - } - if (xAxis == size && xAxis == color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); - } - if (yAxis == size && yAxis == color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); - } - if (xAxis == size && xAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${color}])|Group(${labelName},${color})`); - } - if (yAxis == size && yAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${color}])|Group(${labelName},${color})`); - } - if (xAxis == color && xAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); - } - if (yAxis == color && yAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); - } - if (xAxis == size && yAxis == color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); - } - if (yAxis == size && xAxis == color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); - } - if (xAxis == size && yAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${color}])|Group(${labelName},${color})`); - } - if (yAxis == size && xAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${color}])|Group(${labelName},${color})`); - } - if (xAxis == color && yAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); - } - if (yAxis == color && xAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); - } - if (size === tooltip && label === color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); - } - if (xAxis == yAxis) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${size},${color},${tooltip}])|Group(${labelName},${color})`); - } - if (label === color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${size},${tooltip}])|Group(${labelName})`); - } - if (xAxis == size) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${color},${tooltip}])|Group(${labelName},${color})`); - } - if (xAxis == color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${size},${tooltip}])|Group(${labelName})`); - } - if (xAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${size},${color}])|Group(${labelName},${color})`); - } - if (yAxis == size) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${color},${tooltip}])|Group(${labelName},${color})`); - } - if (yAxis == color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${size},${tooltip}])|Group(${labelName})`); - } - if (yAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${size},${color}])|Group(${labelName},${color})`); - } - if (size === color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${size},${tooltip}])|Group(${labelName})`); - } - if (size === tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${size},${color}])|Group(${labelName},${color})`); - } - if (color === tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${size},${color}])|Group(${labelName},${color})`); - } - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${size},${color},${tooltip}])|Group(${labelName},${color})`); - } - if (label && xAxis && yAxis && size && color) { - if ( - xAxis == yAxis && - xAxis == size && - (xAxis == color || label == color) - ) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); - } - if (xAxis == yAxis && (xAxis == color || size == color)) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${size}])|Group(${labelName})`); - } - if (xAxis == yAxis && label == color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${size}])|Group(${labelName})`); - } - if (xAxis == yAxis && xAxis == size) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),(${color})).as([${labelName}, ${xAxisName},${color}])|Group(${labelName},${color})`); - } + if ( + (xAxis == size && label == color) || + (yAxis == size && label == color) + ) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); + } + if ( + (xAxis == tooltip && label == color) || + (yAxis == tooltip && label == color) + ) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); + } + if (xAxis == size && xAxis == color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); + } + if (yAxis == size && yAxis == color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); + } + if (xAxis == size && xAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${color}])|Group(${labelName},${color})`); + } + if (yAxis == size && yAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${color}])|Group(${labelName},${color})`); + } + if (xAxis == color && xAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); + } + if (yAxis == color && yAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); + } + if (xAxis == size && yAxis == color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); + } + if (yAxis == size && xAxis == color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); + } + if (xAxis == size && yAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${color}])|Group(${labelName},${color})`); + } + if (yAxis == size && xAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${color}])|Group(${labelName},${color})`); + } + if (xAxis == color && yAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); + } + if (yAxis == color && xAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); + } + if (size === tooltip && label === color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); + } + if (xAxis == yAxis) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${size},${color},${tooltip}])|Group(${labelName},${color})`); + } + if (label === color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${size},${tooltip}])|Group(${labelName})`); + } + if (xAxis == size) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${color},${tooltip}])|Group(${labelName},${color})`); + } + if (xAxis == color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${size},${tooltip}])|Group(${labelName})`); + } + if (xAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${size},${color}])|Group(${labelName},${color})`); + } + if (yAxis == size) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${color},${tooltip}])|Group(${labelName},${color})`); + } + if (yAxis == color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${size},${tooltip}])|Group(${labelName})`); + } + if (yAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${size},${color}])|Group(${labelName},${color})`); + } + if (size === color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${size},${tooltip}])|Group(${labelName})`); + } + if (size === tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${size},${color}])|Group(${labelName},${color})`); + } + if (color === tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${size},${color}])|Group(${labelName},${color})`); + } + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${size},${color},${tooltip}])|Group(${labelName},${color})`); + } + if (label && xAxis && yAxis && size && color) { + if ( + xAxis == yAxis && + xAxis == size && + (xAxis == color || label == color) + ) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); + } + if (xAxis == yAxis && (xAxis == color || size == color)) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${size}])|Group(${labelName})`); + } + if (xAxis == yAxis && label == color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${size}])|Group(${labelName})`); + } + if (xAxis == yAxis && xAxis == size) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),(${color})).as([${labelName}, ${xAxisName},${color}])|Group(${labelName},${color})`); + } - if (xAxis == size && xAxis == color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (yAxis == size && yAxis == color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (xAxis == size && yAxis == color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (yAxis === size && xAxis === color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if ( - (xAxis == size && label == color) || - (yAxis == size && label == color) - ) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (xAxis == yAxis) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${xAxisName},${size},${color}])|Group(${labelName},${color})`); - } + if (xAxis == size && xAxis == color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (yAxis == size && yAxis == color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (xAxis == size && yAxis == color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (yAxis === size && xAxis === color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if ( + (xAxis == size && label == color) || + (yAxis == size && label == color) + ) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (xAxis == yAxis) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${xAxisName},${size},${color}])|Group(${labelName},${color})`); + } - if (size == color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); - } - if (xAxis === size) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${color}])|Group(${labelName},${color})`); - } - if (yAxis === size) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${color}])|Group(${labelName},${color})`); - } - if (xAxis === color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); - } - if (yAxis === color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); - } - if (label === color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); - } + if (size == color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); + } + if (xAxis === size) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${color}])|Group(${labelName},${color})`); + } + if (yAxis === size) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${color}])|Group(${labelName},${color})`); + } + if (xAxis === color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); + } + if (yAxis === color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); + } + if (label === color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); + } - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${size},${color}])|Group(${labelName},${color})`); - } - if (label && xAxis && yAxis && color && tooltip) { - if ( - xAxis == yAxis && - (xAxis == color || label == color) && - xAxis == tooltip - ) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); - } - if (xAxis == yAxis && (xAxis == color || label == color)) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${tooltip}])|Group(${labelName})`); - } + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${size},${color}])|Group(${labelName},${color})`); + } + if (label && xAxis && yAxis && color && tooltip) { + if ( + xAxis == yAxis && + (xAxis == color || label == color) && + xAxis == tooltip + ) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); + } + if (xAxis == yAxis && (xAxis == color || label == color)) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${tooltip}])|Group(${labelName})`); + } - if (xAxis == yAxis && xAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),(${color})).as([${labelName}, ${xAxisName},${color}])|Group(${labelName},${color})`); - } + if (xAxis == yAxis && xAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),(${color})).as([${labelName}, ${xAxisName},${color}])|Group(${labelName},${color})`); + } - if (xAxis == color && xAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (yAxis == color && yAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (xAxis === color && yAxis === tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (yAxis === color && xAxis === tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if ( - (xAxis === tooltip && label === color) || - (yAxis === tooltip && label === color) - ) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (xAxis == yAxis) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${color},${tooltip}])|Group(${labelName},${color})`); - } - if (label === color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); - } - if (color == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${color}])|Group(${labelName},${color})`); - } - if (xAxis == color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); - } - if (yAxis === color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); - } - if (xAxis === tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${color}])|Group(${labelName},${color})`); - } - if (yAxis === tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${color}])|Group(${labelName},${color})`); - } - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${color},${tooltip}])|Group(${labelName},${color})`); - } - if (label && xAxis && yAxis && size && tooltip) { - if (xAxis == yAxis && xAxis == size && xAxis == tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); - } - if (xAxis == yAxis && xAxis == size) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${tooltip}])|Group(${labelName})`); - } - if (xAxis == yAxis && (xAxis == tooltip || size == tooltip)) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${size}])|Group(${labelName})`); - } - if (xAxis === size && xAxis === tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (yAxis === size && yAxis === tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (xAxis === size && yAxis === tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (yAxis === size && xAxis === tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (xAxis == yAxis) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${size},${tooltip}])|Group(${labelName})`); - } - if (size === tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); - } - if (xAxis === size) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); - } - if (yAxis === size) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); - } - if (xAxis === tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); - } - if (yAxis === tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); - } + if (xAxis == color && xAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (yAxis == color && yAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (xAxis === color && yAxis === tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (yAxis === color && xAxis === tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if ( + (xAxis === tooltip && label === color) || + (yAxis === tooltip && label === color) + ) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (xAxis == yAxis) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${color},${tooltip}])|Group(${labelName},${color})`); + } + if (label === color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); + } + if (color == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${color}])|Group(${labelName},${color})`); + } + if (xAxis == color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); + } + if (yAxis === color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); + } + if (xAxis === tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${color}])|Group(${labelName},${color})`); + } + if (yAxis === tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${color}])|Group(${labelName},${color})`); + } + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${color},${tooltip}])|Group(${labelName},${color})`); + } + if (label && xAxis && yAxis && size && tooltip) { + if (xAxis == yAxis && xAxis == size && xAxis == tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); + } + if (xAxis == yAxis && xAxis == size) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${tooltip}])|Group(${labelName})`); + } + if (xAxis == yAxis && (xAxis == tooltip || size == tooltip)) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${size}])|Group(${labelName})`); + } + if (xAxis === size && xAxis === tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (yAxis === size && yAxis === tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (xAxis === size && yAxis === tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (yAxis === size && xAxis === tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (xAxis == yAxis) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${size},${tooltip}])|Group(${labelName})`); + } + if (size === tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); + } + if (xAxis === size) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); + } + if (yAxis === size) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); + } + if (xAxis === tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); + } + if (yAxis === tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); + } - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${size},${tooltip}])|Group(${labelName})`); - } - if (label && xAxis && yAxis && color) { - if (xAxis == yAxis && (xAxis == color || label == color)) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); - } - if (xAxis === yAxis) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),(${color})).as([${labelName}, ${xAxisName},${color}])|Group(${labelName},${color})`); - } - if (xAxis === color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (yAxis === color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (label === color) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${color}])|Group(${labelName},${color})`); - } - if (label && xAxis && yAxis && size) { - if (xAxis === yAxis && xAxis === size) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); - } - if (xAxis === yAxis) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${size}])|Group(${labelName})`); - } - if (xAxis === size) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (yAxis === size) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); - } - if (label && xAxis && yAxis && tooltip) { - if (xAxis === yAxis && xAxis === tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); - } - if (xAxis === yAxis) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${tooltip}])|Group(${labelName})`); - } - if (xAxis === tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - if (yAxis === tooltip) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); - } - if (label && xAxis && yAxis) { - if (xAxis == yAxis) { - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); - } - return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); - } - } - } - return ""; + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${size},${tooltip}])|Group(${labelName})`); + } + if (label && xAxis && yAxis && color) { + if (xAxis == yAxis && (xAxis == color || label == color)) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); + } + if (xAxis === yAxis) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),(${color})).as([${labelName}, ${xAxisName},${color}])|Group(${labelName},${color})`); + } + if (xAxis === color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (yAxis === color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (label === color) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),(${color})).as([${labelName}, ${xAxisName},${yAxisName},${color}])|Group(${labelName},${color})`); + } + if (label && xAxis && yAxis && size) { + if (xAxis === yAxis && xAxis === size) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); + } + if (xAxis === yAxis) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${size}])|Group(${labelName})`); + } + if (xAxis === size) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (yAxis === size) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.size}(${size})).as([${labelName}, ${xAxisName},${yAxisName},${size}])|Group(${labelName})`); + } + if (label && xAxis && yAxis && tooltip) { + if (xAxis === yAxis && xAxis === tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); + } + if (xAxis === yAxis) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${tooltip}])|Group(${labelName})`); + } + if (xAxis === tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + if (yAxis === tooltip) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName}),${selectors.tooltip}(${tooltip})).as([${labelName}, ${xAxisName},${yAxisName},${tooltip}])|Group(${labelName})`); + } + if (label && xAxis && yAxis) { + if (xAxis == yAxis) { + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName})).as([${labelName}, ${xAxisName}])|Group(${labelName})`); + } + return (selector = `Select(${labelName},${selectors.xAxis}(${xAxisName}),${selectors.yAxis}(${yAxisName})).as([${labelName}, ${xAxisName},${yAxisName}])|Group(${labelName})`); + } + } + } + return ""; }; diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/scatter-plot/ScatterPlotTooltipData.ts b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/scatter-plot/ScatterPlotTooltipData.ts index 1e1ea13cfe..d24ab5c987 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/scatter-plot/ScatterPlotTooltipData.ts +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/scatter-plot/ScatterPlotTooltipData.ts @@ -1,1192 +1,1192 @@ export const formatdatapoints = (apiData, data) => { - let fields = "", - label = "", - xAxis = "", - yAxis = "", - size = "", - color = "", - tooltip = ""; - if (data.option.hasOwnProperty("_state")) { - fields = data.option["_state"]["fields"]; - label = fields["label"]; - xAxis = fields["XAxis"]; - yAxis = fields["YAxis"]; - size = fields["size"]; - color = fields["color"]; - tooltip = fields["tooltip"]; - } - const getSelectorType = (type) => { - if (!fields[type]) return ""; - return fields[type][0] === "NUMBER" ? "Average of" : "Count of"; - }; - const getSelectors = () => { - return { - xAxis: getSelectorType("XAxisDataType"), - yAxis: getSelectorType("YAxisDataType"), - size: getSelectorType("sizeDataType"), - tooltip: getSelectorType("tooltipDataType"), - color: "Unique Group Concat of", - }; - }; - const selectors = getSelectors(); - const getToolTipContent = (color, Data, apiData) => { - return ` + let fields = "", + label = "", + xAxis = "", + yAxis = "", + size = "", + color = "", + tooltip = ""; + if (Object.hasOwn(data.option, "_state")) { + fields = data.option["_state"]["fields"]; + label = fields["label"]; + xAxis = fields["XAxis"]; + yAxis = fields["YAxis"]; + size = fields["size"]; + color = fields["color"]; + tooltip = fields["tooltip"]; + } + const getSelectorType = (type) => { + if (!fields[type]) return ""; + return fields[type][0] === "NUMBER" ? "Average of" : "Count of"; + }; + const getSelectors = () => { + return { + xAxis: getSelectorType("XAxisDataType"), + yAxis: getSelectorType("YAxisDataType"), + size: getSelectorType("sizeDataType"), + tooltip: getSelectorType("tooltipDataType"), + color: "Unique Group Concat of", + }; + }; + const selectors = getSelectors(); + const getToolTipContent = (color, Data, apiData) => { + return `
\u25CF ${Data.label.formatter.toString()}
${selectors.xAxis} ${xAxis}: ${Data.value[0]}
`; - }; - if (apiData["values"]) { - if (data.option.hasOwnProperty("_state")) { - if (data.option["_state"].hasOwnProperty("fields")) { - if (label && xAxis && yAxis && size && color && tooltip) { - return function (params) { - const { data: Data, color: Color } = params; - if ( - xAxis == yAxis && - xAxis == size && - xAxis == color && - xAxis == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
+ }; + if (apiData["values"]) { + if (Object.hasOwn(data.option, "_state")) { + if (Object.hasOwn(data.option["_state"], "fields")) { + if (label && xAxis && yAxis && size && color && tooltip) { + return (params) => { + const { data: Data, color: Color } = params; + if ( + xAxis == yAxis && + xAxis == size && + xAxis == color && + xAxis == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - xAxis == yAxis && - label == size && - label == color && - label == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
+ ); + } + if ( + xAxis == yAxis && + label == size && + label == color && + label == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - xAxis == yAxis && - xAxis == size && - label == color && - label == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
+ ); + } + if ( + xAxis == yAxis && + xAxis == size && + label == color && + label == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - xAxis == yAxis && - xAxis == size && - label == color && - xAxis == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - ` + ); + } + if ( + xAxis == yAxis && + xAxis == size && + label == color && + xAxis == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - xAxis == yAxis && - label == size && - xAxis == color && - label == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
+ ); + } + if ( + xAxis == yAxis && + label == size && + xAxis == color && + label == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - xAxis == yAxis && - label == size && - label == color && - xAxis == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
+ ); + } + if ( + xAxis == yAxis && + label == size && + label == color && + xAxis == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - xAxis == yAxis && - (size == color || label == color) && - size == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
+ ); + } + if ( + xAxis == yAxis && + (size == color || label == color) && + size == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - xAxis === size && - xAxis === color && - xAxis === tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
+ ); + } + if ( + xAxis === size && + xAxis === color && + xAxis === tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
` - ); - } - if ( - yAxis === size && - yAxis === color && - yAxis === tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[1]}
+ ); + } + if ( + yAxis === size && + yAxis === color && + yAxis === tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[1]}
` - ); - } - if ( - xAxis === size && - xAxis === color && - yAxis === tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
` - ); - } - if ( - xAxis === size && - yAxis === color && - xAxis === tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[1]}
` - ); - } - if ( - yAxis === size && - xAxis === color && - xAxis === tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
` - ); - } - if ( - yAxis === size && - yAxis === color && - xAxis === tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[1]}
` - ); - } - if ( - yAxis === size && - xAxis === color && - yAxis === tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
` - ); - } - if ( - xAxis === size && - yAxis === color && - yAxis === tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[1]}
` - ); - } - if ( - xAxis === size && - xAxis === tooltip && - label === color - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - yAxis === size && - yAxis === tooltip && - label === color - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - xAxis === size && - yAxis === tooltip && - label === color - ) { - return ( - getToolTipContent(Color, Data, apiData) + - ` ${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - yAxis === size && - xAxis === tooltip && - label === color - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - xAxis == yAxis && - (label == size || xAxis == size) && - xAxis == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
+ ); + } + if ( + xAxis === size && + xAxis === color && + yAxis === tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
` + ); + } + if ( + xAxis === size && + yAxis === color && + xAxis === tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[1]}
` + ); + } + if ( + yAxis === size && + xAxis === color && + xAxis === tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
` + ); + } + if ( + yAxis === size && + yAxis === color && + xAxis === tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[1]}
` + ); + } + if ( + yAxis === size && + xAxis === color && + yAxis === tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
` + ); + } + if ( + xAxis === size && + yAxis === color && + yAxis === tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[1]}
` + ); + } + if ( + xAxis === size && + xAxis === tooltip && + label === color + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if ( + yAxis === size && + yAxis === tooltip && + label === color + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if ( + xAxis === size && + yAxis === tooltip && + label === color + ) { + return ( + getToolTipContent(Color, Data, apiData) + + ` ${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if ( + yAxis === size && + xAxis === tooltip && + label === color + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if ( + xAxis == yAxis && + (label == size || xAxis == size) && + xAxis == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.size} ${size}: ${Data.symbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - xAxis == yAxis && - label == color && - xAxis == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
+ ); + } + if ( + xAxis == yAxis && + label == color && + xAxis == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (xAxis == yAxis && label == size && label == color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
+ ); + } + if (xAxis == yAxis && label == size && label == color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - xAxis === yAxis && - xAxis === size && - label === color - ) { - return ( - getToolTipContent(Color, Data, apiData) + - ` + ); + } + if ( + xAxis === yAxis && + xAxis === size && + label === color + ) { + return ( + getToolTipContent(Color, Data, apiData) + + ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - xAxis == yAxis && - label == color && - label == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + - `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - xAxis == yAxis && - label == size && - label == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + - `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (xAxis == yAxis && xAxis == size && xAxis == color) { - return ( - getToolTipContent(Color, Data, apiData) + - ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
+ ); + } + if ( + xAxis == yAxis && + label == color && + label == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + + `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` + ); + } + if ( + xAxis == yAxis && + label == size && + label == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + + `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (xAxis == yAxis && xAxis == size && xAxis == color) { + return ( + getToolTipContent(Color, Data, apiData) + + ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - xAxis == yAxis && - xAxis == size && - xAxis == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - xAxis == yAxis && - xAxis == color && - xAxis == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
+ ); + } + if ( + xAxis == yAxis && + xAxis == size && + xAxis == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if ( + xAxis == yAxis && + xAxis == color && + xAxis == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - (size == color && xAxis == tooltip) || - yAxis == tooltip || - (size == color && size == tooltip) || - (size == tooltip && xAxis == color) || - yAxis == color - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + - `${selectors.size} ${size}: ${Data.symbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (xAxis == yAxis && xAxis == size) { - return ( - getToolTipContent(Color, Data, apiData) + - ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
+ ); + } + if ( + (size == color && xAxis == tooltip) || + yAxis == tooltip || + (size == color && size == tooltip) || + (size == tooltip && xAxis == color) || + yAxis == color + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + + `${selectors.size} ${size}: ${Data.symbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (xAxis == yAxis && xAxis == size) { + return ( + getToolTipContent(Color, Data, apiData) + + ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - (xAxis == yAxis && xAxis == color) || - size == color - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
+ ); + } + if ( + (xAxis == yAxis && xAxis == color) || + size == color + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - (xAxis == yAxis && xAxis == tooltip) || - size == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
+ ); + } + if ( + (xAxis == yAxis && xAxis == tooltip) || + size == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (xAxis == yAxis && label == size) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
+ ); + } + if (xAxis == yAxis && label == size) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (xAxis == yAxis && label == color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
+ ); + } + if (xAxis == yAxis && label == color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (xAxis == yAxis && label == tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
+ ); + } + if (xAxis == yAxis && label == tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } + ); + } - if (xAxis === size && label === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + - `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (yAxis === size && label === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + - `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (xAxis === tooltip && label === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + - `${selectors.size} ${size}: ${Data.symbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (yAxis === tooltip && label === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + - `${selectors.size} ${size}: ${Data.symbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (xAxis === size && xAxis === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
+ if (xAxis === size && label === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + + `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (yAxis === size && label === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + + `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (xAxis === tooltip && label === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + + `${selectors.size} ${size}: ${Data.symbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (yAxis === tooltip && label === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + + `${selectors.size} ${size}: ${Data.symbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (xAxis === size && xAxis === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (yAxis === size && yAxis === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
+ ); + } + if (yAxis === size && yAxis === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (xAxis === size && xAxis === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (yAxis === size && yAxis === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (xAxis === color && xAxis === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
+ ); + } + if (xAxis === size && xAxis === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (yAxis === size && yAxis === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (xAxis === color && xAxis === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.size} ${size}: ${Data.symbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (yAxis === color && yAxis === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + - `${selectors.size} ${size}: ${Data.symbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (xAxis === size && yAxis === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + - `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (yAxis === size && xAxis === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + - `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (xAxis === size && yAxis === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (yAxis === size && xAxis === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (xAxis === color && yAxis === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + - `${selectors.size} ${size}: ${Data.symbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (yAxis === color && xAxis === tooltip) { - return ` + ); + } + if (yAxis === color && yAxis === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + + `${selectors.size} ${size}: ${Data.symbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (xAxis === size && yAxis === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + + `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (yAxis === size && xAxis === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + + `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (xAxis === size && yAxis === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (yAxis === size && xAxis === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (xAxis === color && yAxis === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + + `${selectors.size} ${size}: ${Data.symbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (yAxis === color && xAxis === tooltip) { + return ` ${getToolTipContent(Color, Data, apiData)} ${selectors.yAxis} ${yAxis}: ${ - Data.value[1] - }
+ Data.value[1] + }
${selectors.size} ${size}: ${ - Data.symbolSize - }
+ Data.symbolSize + }
${selectors.color} ${color}: ${ - Data.itemStyle.colorValue - }
+ Data.itemStyle.colorValue + }
`; - } - if (size === tooltip && label === color) { - return ` + } + if (size === tooltip && label === color) { + return ` ${getToolTipContent(Color, Data, apiData)} ${selectors.yAxis} ${yAxis}: ${ - Data.value[1] - }
+ Data.value[1] + }
${selectors.size} ${size}: ${ - Data.symbolSize - }
+ Data.symbolSize + }
${selectors.color} ${color}: ${ - Data.itemStyle.colorValue - }
+ Data.itemStyle.colorValue + }
`; - } - if (xAxis == yAxis) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + - `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (label === color) { - return ` + } + if (xAxis == yAxis) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + + `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (label === color) { + return ` ${getToolTipContent(Color, Data, apiData)} ${selectors.yAxis} ${yAxis}: ${ - Data.value[1] - }
+ Data.value[1] + }
${selectors.size} ${size}: ${ - Data.symbolSize - }
+ Data.symbolSize + }
${selectors.color} ${color}: ${ - Data.itemStyle.colorValue - }
+ Data.itemStyle.colorValue + }
${selectors.tooltip} ${tooltip}: ${ - Data.tooltipValue - }
+ Data.tooltipValue + }
`; - } - if (size === label) { - return ` + } + if (size === label) { + return ` ${getToolTipContent(Color, Data, apiData)} ${selectors.yAxis} ${yAxis}: ${ - Data.value[1] - }
+ Data.value[1] + }
${selectors.size} ${size}: ${ - Data.symbolSize - }
+ Data.symbolSize + }
${selectors.color} ${color}: ${ - Data.itemStyle.colorValue - }
+ Data.itemStyle.colorValue + }
${selectors.tooltip} ${tooltip}: ${ - Data.tooltipValue - }
+ Data.tooltipValue + }
`; - } - if (tooltip === label) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + - `${selectors.size} ${size}: ${Data.symbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + - `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (xAxis === size) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
+ } + if (tooltip === label) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + + `${selectors.size} ${size}: ${Data.symbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + + `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (xAxis === size) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (xAxis === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
+ ); + } + if (xAxis === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.size} ${size}: ${Data.symbolSize}
${selectors.color} ${color}: ${Data.value[0]}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (xAxis === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + - `${selectors.size} ${size}: ${Data.symbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (yAxis === size) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + - `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (yAxis === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + - `${selectors.size} ${size}: ${Data.symbolSize}
` + - `${selectors.color} ${color}: ${Data.value[1]}
` + - `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (yAxis === tooltip) { - return ` + ); + } + if (xAxis === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + + `${selectors.size} ${size}: ${Data.symbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (yAxis === size) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + + `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (yAxis === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + + `${selectors.size} ${size}: ${Data.symbolSize}
` + + `${selectors.color} ${color}: ${Data.value[1]}
` + + `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (yAxis === tooltip) { + return ` ${getToolTipContent(Color, Data, apiData)} ${selectors.yAxis} ${yAxis}: ${ - Data.value[1] - }
+ Data.value[1] + }
${selectors.size} ${size}: ${ - Data.symbolSize - }
+ Data.symbolSize + }
${selectors.color} ${color}: ${ - Data.itemStyle.colorValue - }
+ Data.itemStyle.colorValue + }
`; - } - if (size === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + - `${selectors.size} ${size}: ${Data.symbolSize}
` + - `${selectors.color} ${color}: ${Data.symbolSize}
` + - `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (size === tooltip) { - return ` + } + if (size === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + + `${selectors.size} ${size}: ${Data.symbolSize}
` + + `${selectors.color} ${color}: ${Data.symbolSize}
` + + `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (size === tooltip) { + return ` ${getToolTipContent(Color, Data, apiData)} ${selectors.yAxis} ${yAxis}: ${ - Data.value[1] - }
+ Data.value[1] + }
${selectors.size} ${size}: ${ - Data.symbolSize - }
+ Data.symbolSize + }
${selectors.color} ${color}: ${ - Data.itemStyle.colorValue - }
+ Data.itemStyle.colorValue + }
`; - } - if (color === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
+ } + if (color === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.size} ${size}: ${Data.symbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + - `${selectors.size} ${size}: ${Data.symbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + - `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - }; - } - if (label && xAxis && yAxis && size && color) { - return function (params) { - const { data: Data, color: Color } = params; - if ( - xAxis == yAxis && - xAxis == size && - (xAxis == color || xAxis == color) - ) { - return ( - getToolTipContent(Color, Data, apiData) + - ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - xAxis == yAxis && - (xAxis == color || size == color) - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
+ ); + } + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + + `${selectors.size} ${size}: ${Data.symbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + + `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` + ); + }; + } + if (label && xAxis && yAxis && size && color) { + return (params) => { + const { data: Data, color: Color } = params; + if ( + xAxis == yAxis && + xAxis == size && + (xAxis == color || xAxis == color) + ) { + return ( + getToolTipContent(Color, Data, apiData) + + ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if ( + xAxis == yAxis && + (xAxis == color || size == color) + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (xAxis == yAxis && label == color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (xAxis == yAxis && xAxis == size) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (xAxis === size && xAxis === color) { - return ( - getToolTipContent(Color, Data, apiData) + - ` ${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
` - ); - } - if (yAxis === size && yAxis === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[1]}
` - ); - } - if (xAxis === size && yAxis === color) { - return ( - getToolTipContent(Color, Data, apiData) + - ` ${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
` - ); - } - if (yAxis === size && xAxis === color) { - return ( - getToolTipContent(Color, Data, apiData) + - ` ${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
` - ); - } - if (xAxis === size && label === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (yAxis === size && label === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (xAxis == yAxis) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
+ ); + } + if (xAxis == yAxis && label == color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (xAxis == yAxis && xAxis == size) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (xAxis === size && xAxis === color) { + return ( + getToolTipContent(Color, Data, apiData) + + ` ${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
` + ); + } + if (yAxis === size && yAxis === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[1]}
` + ); + } + if (xAxis === size && yAxis === color) { + return ( + getToolTipContent(Color, Data, apiData) + + ` ${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
` + ); + } + if (yAxis === size && xAxis === color) { + return ( + getToolTipContent(Color, Data, apiData) + + ` ${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
` + ); + } + if (xAxis === size && label === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (yAxis === size && label === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (xAxis == yAxis) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (label === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + - `${selectors.size} ${size}: ${Data.symbolSize}
` + - `${selectors.color} ${data.option["_state"]["fields"]["color"]}: ${Data.itemStyle.colorValue}
` - ); - } - if (size === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + - `${selectors.size} ${size}: ${Data.symbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (xAxis === size) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (yAxis === size) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (xAxis === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
+ ); + } + if (label === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + + `${selectors.size} ${size}: ${Data.symbolSize}
` + + `${selectors.color} ${data.option["_state"]["fields"]["color"]}: ${Data.itemStyle.colorValue}
` + ); + } + if (size === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + + `${selectors.size} ${size}: ${Data.symbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (xAxis === size) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (yAxis === size) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (xAxis === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.size} ${size}: ${Data.symbolSize}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (yAxis === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + - `${selectors.size} ${size}: ${Data.symbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + - `${selectors.size} ${size}: ${Data.symbolSize}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - }; - } - if (label && xAxis && yAxis && color && tooltip) { - return function (params) { - const { data: Data, color: Color } = params; - if ( - xAxis == yAxis && - (xAxis == color || label == color) && - xAxis == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if ( - xAxis == yAxis && - (xAxis == color || label == color) - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
+ ); + } + if (yAxis === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + + `${selectors.size} ${size}: ${Data.symbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + + `${selectors.size} ${size}: ${Data.symbolSize}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + }; + } + if (label && xAxis && yAxis && color && tooltip) { + return (params) => { + const { data: Data, color: Color } = params; + if ( + xAxis == yAxis && + (xAxis == color || label == color) && + xAxis == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if ( + xAxis == yAxis && + (xAxis == color || label == color) + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (xAxis == yAxis && xAxis == tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}` - ); - } - if (xAxis === color && xAxis === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
` - ); - } - if (yAxis === color && yAxis === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[1]}
` - ); - } - if (xAxis === color && yAxis === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
` - ); - } - if (yAxis === color && xAxis === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[1]}
` - ); - } - if (xAxis === tooltip && label === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${tooltip}: ${Data.itemStyle.colorValue}
` - ); - } - if (yAxis === tooltip && label === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${tooltip}: ${Data.itemStyle.colorValue}
` - ); - } - if (xAxis == yAxis) { - return ( - getToolTipContent(Color, Data, apiData) + - ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
+ ); + } + if (xAxis == yAxis && xAxis == tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}` + ); + } + if (xAxis === color && xAxis === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
` + ); + } + if (yAxis === color && yAxis === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[1]}
` + ); + } + if (xAxis === color && yAxis === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
` + ); + } + if (yAxis === color && xAxis === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[1]}
` + ); + } + if (xAxis === tooltip && label === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${tooltip}: ${Data.itemStyle.colorValue}
` + ); + } + if (yAxis === tooltip && label === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${tooltip}: ${Data.itemStyle.colorValue}
` + ); + } + if (xAxis == yAxis) { + return ( + getToolTipContent(Color, Data, apiData) + + ` ${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (label === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
+ ); + } + if (label === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (color === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
+ ); + } + if (color === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (xAxis === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (yAxis === color) { - return ( - getToolTipContent(Color, Data, apiData) + - ` ${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[1]}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (xAxis === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (yAxis === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + - `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - }; - } - if (label && xAxis && yAxis && size && tooltip) { - return function (params) { - const { data: Data, color: Color } = params; - if ( - xAxis == yAxis && - xAxis == size && - xAxis == tooltip - ) { - return getToolTipContent(Color, Data, apiData); - } - if (xAxis == yAxis && xAxis == size) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.tooltip}${tooltip}: ${Data.tooltipValue}
` - ); - } - if ( - (xAxis == yAxis && xAxis == tooltip) || - size == tooltip - ) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
` - ); - } - if (xAxis === size && xAxis === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` - ); - } - if (yAxis === size && yAxis === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` - ); - } - if (xAxis === size && yAxis === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` - ); - } - if (yAxis === size && xAxis === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` - ); - } - if (xAxis == yAxis) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
` + - `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (size === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.size} ${size}: ${Data.symbolSize}
` - ); - } - if (xAxis === size) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.tooltip}${tooltip}: ${Data.value[0]}
` - ); - } - if (yAxis === size) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - } - if (xAxis === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
+ ); + } + if (xAxis === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (yAxis === color) { + return ( + getToolTipContent(Color, Data, apiData) + + ` ${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[1]}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (xAxis === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (yAxis === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + + `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` + ); + }; + } + if (label && xAxis && yAxis && size && tooltip) { + return (params) => { + const { data: Data, color: Color } = params; + if ( + xAxis == yAxis && + xAxis == size && + xAxis == tooltip + ) { + return getToolTipContent(Color, Data, apiData); + } + if (xAxis == yAxis && xAxis == size) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.tooltip}${tooltip}: ${Data.tooltipValue}
` + ); + } + if ( + (xAxis == yAxis && xAxis == tooltip) || + size == tooltip + ) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
` + ); + } + if (xAxis === size && xAxis === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + ); + } + if (yAxis === size && yAxis === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + ); + } + if (xAxis === size && yAxis === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + ); + } + if (yAxis === size && xAxis === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + ); + } + if (xAxis == yAxis) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
` + + `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (size === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.size} ${size}: ${Data.symbolSize}
` + ); + } + if (xAxis === size) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.tooltip}${tooltip}: ${Data.value[0]}
` + ); + } + if (yAxis === size) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` + ); + } + if (xAxis === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.size} ${size}: ${Data.symbolSize}
` - ); - } - if (yAxis === tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
+ ); + } + if (yAxis === tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.size} ${size}: ${Data.symbolSize}
` - ); - } - return ` + ); + } + return ` ${getToolTipContent(Color, Data, apiData)} ${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.size} ${size}: ${Data.symbolSize}
${selectors.tooltip} ${tooltip}: ${ - Data.tooltipValue - }
+ Data.tooltipValue + }
`; - }; - } - if (label && xAxis && yAxis && color) { - return function (params) { - const { data: Data, color: Color } = params; - if ( - xAxis == yAxis && - (xAxis == color || label == color) - ) { - return ` + }; + } + if (label && xAxis && yAxis && color) { + return (params) => { + const { data: Data, color: Color } = params; + if ( + xAxis == yAxis && + (xAxis == color || label == color) + ) { + return ` ${getToolTipContent(Color, Data, apiData)} ${selectors.color} ${color}: ${ - Data.itemStyle.colorValue - }
+ Data.itemStyle.colorValue + }
`; - } - if (xAxis == yAxis) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - if (xAxis === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
+ } + if (xAxis == yAxis) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` + ); + } + if (xAxis === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[0]}
` - ); - } - if (yAxis === color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
+ ); + } + if (yAxis === color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.value[1]}
` - ); - } - if (label == color) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
+ ); + } + if (label == color) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - } - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
+ ); + } + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.color} ${color}: ${Data.itemStyle.colorValue}
` - ); - }; - } - if (label && xAxis && yAxis && size) { - return function (params) { - const { data: Data, color: Color } = params; - if (xAxis == yAxis && xAxis == size) { - return getToolTipContent(Color, Data, apiData); - } - if (xAxis == yAxis) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.size} ${size}: ${Data.symbolSize}
` - ); - } - if (xAxis == size) { - return ( - getToolTipContent(Color, Data, apiData) + - ` + ); + }; + } + if (label && xAxis && yAxis && size) { + return (params) => { + const { data: Data, color: Color } = params; + if (xAxis == yAxis && xAxis == size) { + return getToolTipContent(Color, Data, apiData); + } + if (xAxis == yAxis) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.size} ${size}: ${Data.symbolSize}
` + ); + } + if (xAxis == size) { + return ( + getToolTipContent(Color, Data, apiData) + + ` ${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` - ); - } - if (yAxis == size) { - return ( - getToolTipContent(Color, Data, apiData) + - ` + ); + } + if (yAxis == size) { + return ( + getToolTipContent(Color, Data, apiData) + + ` ${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` - ); - } - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
+ ); + } + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
${selectors.size} ${size}: ${Data.symbolSize}
` - ); - }; - } - if (label && xAxis && yAxis && tooltip) { - return function (params) { - const { data: Data, color: Color } = params; - if (xAxis == yAxis && xAxis == tooltip) { - return getToolTipContent(Color, Data, apiData); - } - if (xAxis == yAxis) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.tooltip} ${yAxis}: ${Data.tooltipValue}
+ ); + }; + } + if (label && xAxis && yAxis && tooltip) { + return (params) => { + const { data: Data, color: Color } = params; + if (xAxis == yAxis && xAxis == tooltip) { + return getToolTipContent(Color, Data, apiData); + } + if (xAxis == yAxis) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.tooltip} ${yAxis}: ${Data.tooltipValue}
` - ); - } - if (xAxis == tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` - ); - } - if (yAxis == tooltip) { - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` - ); - } - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` - ); - }; - } - if (label && xAxis && yAxis) { - if (xAxis == yAxis) { - return function (params) { - const { data: Data, color: Color } = params; - return getToolTipContent(Color, Data, apiData); - }; - } - return function (params) { - const { data: Data, color: Color } = params; - return ( - getToolTipContent(Color, Data, apiData) + - `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` - ); - }; - } - } - return ""; - } - return ""; - } - return ""; + ); + } + if (xAxis == tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + ); + } + if (yAxis == tooltip) { + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + ); + } + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.tooltip} ${tooltip}: ${Data.tooltipValue}
` + ); + }; + } + if (label && xAxis && yAxis) { + if (xAxis == yAxis) { + return (params) => { + const { data: Data, color: Color } = params; + return getToolTipContent(Color, Data, apiData); + }; + } + return (params) => { + const { data: Data, color: Color } = params; + return ( + getToolTipContent(Color, Data, apiData) + + `${selectors.yAxis} ${yAxis}: ${Data.value[1]}
` + ); + }; + } + } + return ""; + } + return ""; + } + return ""; }; diff --git a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/stack-chart/StackChart.tsx b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/stack-chart/StackChart.tsx index 292a5a76c8..7c212efa45 100644 --- a/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/stack-chart/StackChart.tsx +++ b/libs/renderer/src/components/block-defaults/echart-visualization-block/variant/stack-chart/StackChart.tsx @@ -1,733 +1,732 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { useRef, useState } from "react"; -import { observer } from "mobx-react-lite"; -import * as echarts from "echarts/core"; + import { BarChart } from "echarts/charts"; -import EChartsReact, { EChartsOption } from "echarts-for-react"; -import { CanvasRenderer } from "echarts/renderers"; import { TooltipComponent } from "echarts/components"; - +import * as echarts from "echarts/core"; +import { CanvasRenderer } from "echarts/renderers"; +import EChartsReact, { type EChartsOption } from "echarts-for-react"; +import { observer } from "mobx-react-lite"; +import { useRef, useState } from "react"; import { styled } from "@semoss/ui"; - import { useBlock, useFrame } from "../../../../../hooks"; -import { BlockComponent } from "../../../../../store"; +import type { BlockComponent } from "../../../../../store"; import { ChartContextMenu } from "../bar-chart/ChartContextMenu"; const StyledNoDataContainer = styled("div", { - shouldForwardProp: (prop) => prop !== "error", + shouldForwardProp: (prop) => prop !== "error", })<{ error?: boolean }>(({ error = false, theme }) => ({ - height: "100%", - width: "100%", - color: error ? theme.palette.error.main : "unset", + height: "100%", + width: "100%", + color: error ? theme.palette.error.main : "unset", })); export interface EChartColumns { - name: string; - selector: string; - width: string; + name: string; + selector: string; + width: string; } export interface EchartVisualizationBlockDef { - widget: "e-chart"; - data: { - option: {}; - frame: { - name: string; - }; - variation: undefined | string; - columns: EChartColumns[]; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - aggregate: Record; - contextMenu: { - hideUnfilter: boolean; - hideFilter: boolean; - hideExclude: boolean; - }; - }; - listeners: {}; - slots: never; + widget: "e-chart"; + data: { + option: {}; + frame: { + name: string; + }; + variation: undefined | string; + columns: EChartColumns[]; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + aggregate: Record; + contextMenu: { + hideUnfilter: boolean; + hideFilter: boolean; + hideExclude: boolean; + }; + }; + listeners: {}; + slots: never; } export const StackChart: BlockComponent = observer(({ id }) => { - const { data } = useBlock(id); - echarts.use([BarChart, CanvasRenderer, TooltipComponent]); - const [contextMenu, setContextMenu] = useState<{ - mouseX: number; - mouseY: number; - value: unknown; - } | null>(null); + const { data } = useBlock(id); + echarts.use([BarChart, CanvasRenderer, TooltipComponent]); + const [contextMenu, setContextMenu] = useState<{ + mouseX: number; + mouseY: number; + value: unknown; + } | null>(null); - const chartOperationData = useRef({ - brushSelected: [], - contextMenu: null, - yAxisColumn: { name: "", selector: "", width: undefined }, - chartInstance: { setOption: null }, - }); - let fields = "", - xAxis = "", - yAxis = "", - category = "", - tooltip = ""; - if (data.option.hasOwnProperty("_state")) { - fields = data.option["_state"]["fields"]; - xAxis = fields["XAxis"]; - yAxis = fields["YAxis"]; - category = fields["category"]; - tooltip = fields["tooltip"]; - } + const chartOperationData = useRef({ + brushSelected: [], + contextMenu: null, + yAxisColumn: { name: "", selector: "", width: undefined }, + chartInstance: { setOption: null }, + }); + let fields = "", + xAxis = "", + yAxis = "", + category = "", + tooltip = ""; + if (Object.hasOwn(data.option, "_state")) { + fields = data.option["_state"]["fields"]; + xAxis = fields["XAxis"]; + yAxis = fields["YAxis"]; + category = fields["category"]; + tooltip = fields["tooltip"]; + } - /** - * Builds a dynamic query string based on the provided input data. - * @param inputData - An array of tuples where each tuple contains a string and an object mapping field names to aggregation methods. - * @returns A query string that selects and groups by the specified fields with appropriate aggregations. - */ - const buildDynamicQuery = (inputData): string => { - const selectParts: string[] = []; - const aliasParts: string[] = []; - const groupByParts: string[] = []; + /** + * Builds a dynamic query string based on the provided input data. + * @param inputData - An array of tuples where each tuple contains a string and an object mapping field names to aggregation methods. + * @returns A query string that selects and groups by the specified fields with appropriate aggregations. + */ + const buildDynamicQuery = (inputData): string => { + const selectParts: string[] = []; + const aliasParts: string[] = []; + const groupByParts: string[] = []; - inputData.forEach(([_, fields]) => { - for (const field in fields) { - const rawAgg = fields[field]; - if (!aliasParts.includes(field)) aliasParts.push(field); + inputData.forEach(([_, fields]) => { + for (const field in fields) { + const rawAgg = fields[field]; + if (!aliasParts.includes(field)) aliasParts.push(field); - if (rawAgg) { - const cleanedAgg = rawAgg.split(" ").join(""); // Remove spaces (e.g., "Unique Count" → "UniqueCount") - if (!selectParts.includes(`${cleanedAgg}(${field})`)) { - selectParts.push(`${cleanedAgg}(${field})`); - } - } else { - if (!selectParts.includes(field)) { - selectParts.push(field); - groupByParts.push(field); // Only unaggregated fields are grouped - } - } - } - }); + if (rawAgg) { + const cleanedAgg = rawAgg.split(" ").join(""); // Remove spaces (e.g., "Unique Count" → "UniqueCount") + if (!selectParts.includes(`${cleanedAgg}(${field})`)) { + selectParts.push(`${cleanedAgg}(${field})`); + } + } else { + if (!selectParts.includes(field)) { + selectParts.push(field); + groupByParts.push(field); // Only unaggregated fields are grouped + } + } + } + }); - return `Select(${selectParts.join(", ")}).as([${aliasParts.join( - ", ", - )}]) | Group(${groupByParts.join(", ")})`; - }; + return `Select(${selectParts.join(", ")}).as([${aliasParts.join( + ", ", + )}]) | Group(${groupByParts.join(", ")})`; + }; - // useFrame hook to get the frame data - const frame = useFrame(data?.frame?.name, { - selector: buildDynamicQuery(Object.entries(data?.aggregate ?? {})), - }); - // Function to add only new values and avoid duplicates - const updateSelectedIndexes = (selectedIndexes, newIndexes) => { - newIndexes.forEach((index) => { - if (!selectedIndexes.includes(index)) { - selectedIndexes.push(index); // Add only if it's not already present - } - }); - return selectedIndexes; - }; - //Brushing of data points - const echartsLoaded = (chart) => { - chart.on("brushSelected", (params) => { - let selectedDataIndexes = []; + // useFrame hook to get the frame data + const frame = useFrame(data?.frame?.name, { + selector: buildDynamicQuery(Object.entries(data?.aggregate ?? {})), + }); + // Function to add only new values and avoid duplicates + const updateSelectedIndexes = (selectedIndexes, newIndexes) => { + newIndexes.forEach((index) => { + if (!selectedIndexes.includes(index)) { + selectedIndexes.push(index); // Add only if it's not already present + } + }); + return selectedIndexes; + }; + //Brushing of data points + const echartsLoaded = (chart) => { + chart.on("brushSelected", (params) => { + let selectedDataIndexes = []; - params.batch.forEach((batch) => { - batch.selected.forEach((selection) => { - // Extract exact dataIndex for each series - if (selection.dataIndex && selection.dataIndex.length > 0) { - selectedDataIndexes = updateSelectedIndexes( - selectedDataIndexes, - selection.dataIndex, - ); - } - }); - }); - if (selectedDataIndexes.length > 0) { - const currentOption = chart.getOption(); - const xAxisData = - data.option["flipAxis"] === true - ? currentOption.yAxis[0].data - : currentOption.xAxis[0].data; - const filteredXaxis = [...selectedDataIndexes] - .filter((index) => { - return data.option["series"].some((series) => { - const yValue = series.data[index]?.value; - return ( - yValue !== null && - yValue !== 0 && - yValue !== undefined && - yValue !== "NaN" && - yValue !== "" - ); - }); - }) - .map((index) => xAxisData[index]); - handleSelection( - filteredXaxis, - currentOption["_state"]["fields"]["XAxis"], - ); - } - }); - }; - //Brushed Data points selection and pixel expression of brushed data points to send to the server - const handleSelection = (value: any, name: any) => { - // update the frame - frame.filter(`SetFrameFilter(${name}==[${JSON.stringify(value)}])`); - }; + params.batch.forEach((batch) => { + batch.selected.forEach((selection) => { + // Extract exact dataIndex for each series + if (selection.dataIndex && selection.dataIndex.length > 0) { + selectedDataIndexes = updateSelectedIndexes( + selectedDataIndexes, + selection.dataIndex, + ); + } + }); + }); + if (selectedDataIndexes.length > 0) { + const currentOption = chart.getOption(); + const xAxisData = + data.option["flipAxis"] === true + ? currentOption.yAxis[0].data + : currentOption.xAxis[0].data; + const filteredXaxis = [...selectedDataIndexes] + .filter((index) => { + return data.option["series"].some((series) => { + const yValue = series.data[index]?.value; + return ( + yValue !== null && + yValue !== 0 && + yValue !== undefined && + yValue !== "NaN" && + yValue !== "" + ); + }); + }) + .map((index) => xAxisData[index]); + handleSelection( + filteredXaxis, + currentOption["_state"]["fields"]["XAxis"], + ); + } + }); + }; + //Brushed Data points selection and pixel expression of brushed data points to send to the server + const handleSelection = (value: any, name: any) => { + // update the frame + frame.filter(`SetFrameFilter(${name}==[${JSON.stringify(value)}])`); + }; - // Context menu to show on right click - const onClickChart = { - contextmenu: (params) => { - if (params.data) { - const XAxisName = xAxis; - const selectedData = params.dataIndex; - const filteredXaxis = - data.option["flipAxis"] === true - ? data.option["yAxis"]["data"][selectedData] - : data.option["xAxis"]["data"][selectedData]; - setContextMenu( - contextMenu === null - ? { - mouseX: params.event.event.clientX, - mouseY: params.event.event.clientY, - value: { - name: XAxisName, - value: filteredXaxis, - }, - } - : null, - ); - params.event.event.preventDefault(); - } else { - params.event.event.preventDefault(); - } - }, - }; - // Process the API data to render the Stack Chart - const processData = (apiData, data) => { - const xAxisData = []; - const groupedData = {}; - let maxStackSize = 0; - const uniqueCategories = []; - //Reset data before updating - data.option.series = []; - data.option.xAxis.data = []; + // Context menu to show on right click + const onClickChart = { + contextmenu: (params) => { + if (params.data) { + const XAxisName = xAxis; + const selectedData = params.dataIndex; + const filteredXaxis = + data.option["flipAxis"] === true + ? data.option["yAxis"]["data"][selectedData] + : data.option["xAxis"]["data"][selectedData]; + setContextMenu( + contextMenu === null + ? { + mouseX: params.event.event.clientX, + mouseY: params.event.event.clientY, + value: { + name: XAxisName, + value: filteredXaxis, + }, + } + : null, + ); + params.event.event.preventDefault(); + } else { + params.event.event.preventDefault(); + } + }, + }; + // Process the API data to render the Stack Chart + const processData = (apiData, data) => { + const xAxisData = []; + const groupedData = {}; + let maxStackSize = 0; + const uniqueCategories = []; + //Reset data before updating + data.option.series = []; + data.option.xAxis.data = []; - if (apiData["values"]) { - if (data.option.hasOwnProperty("_state")) { - if ( - fields.hasOwnProperty("XAxis") && - fields.hasOwnProperty("YAxis") && - fields.hasOwnProperty("category") && - fields.hasOwnProperty("tooltip") - ) { - if ( - JSON.stringify(xAxis) == JSON.stringify(category) && - JSON.stringify(yAxis) == JSON.stringify(tooltip) - ) { - apiData.values.forEach(([x, y]) => { - if (!groupedData[x]) { - groupedData[x] = []; - xAxisData.push(x); - } - groupedData[x].push({ y, category: x, tooltip: y }); - // Store unique categories for legend - if (x && !uniqueCategories.includes(x)) { - uniqueCategories.push(x); - } - // Calculate max stack size (Max number of bars stacked at any x value) - maxStackSize = Math.max( - ...Object.values(groupedData).map( - (arr: any) => arr.length, - ), - ); - }); - const colorList = data.option["color"]; - const colorCount = colorList.length; + if (apiData["values"]) { + if (Object.hasOwn(data.option, "_state")) { + if ( + Object.hasOwn(fields, "XAxis") && + Object.hasOwn(fields, "YAxis") && + Object.hasOwn(fields, "category") && + Object.hasOwn(fields, "tooltip") + ) { + if ( + JSON.stringify(xAxis) == JSON.stringify(category) && + JSON.stringify(yAxis) == JSON.stringify(tooltip) + ) { + apiData.values.forEach(([x, y]) => { + if (!groupedData[x]) { + groupedData[x] = []; + xAxisData.push(x); + } + groupedData[x].push({ y, category: x, tooltip: y }); + // Store unique categories for legend + if (x && !uniqueCategories.includes(x)) { + uniqueCategories.push(x); + } + // Calculate max stack size (Max number of bars stacked at any x value) + maxStackSize = Math.max( + ...Object.values(groupedData).map( + (arr: any) => arr.length, + ), + ); + }); + const colorList = data.option["color"]; + const colorCount = colorList.length; - // Assign colors to categories - const categoryColorMap = {}; - uniqueCategories.forEach((category, index) => { - categoryColorMap[category] = - colorList[index % colorCount]; // Cycle colors - }); - // Ensure we only create the exact number of stacks needed - const series = uniqueCategories.map( - (category, index) => ({ - type: "bar", - stack: "stack", - name: category.toString(), // Legend name - data: xAxisData.map((x) => { - const point = - groupedData[x].find( - (item) => - item.category === category, - ) || {}; - return { - value: - isNaN(point.y) || - point.y === undefined - ? point.y - : parseFloat(point.y) - .toFixed(2) - .replace(/\.00$/, ""), - category: point.category ?? "", - itemStyle: { - color: categoryColorMap[category], - }, // Assign correct color - tooltipValue: point.tooltip ?? "", // Store tooltip inside each data point - }; - }), - }), - ); - const legendData = uniqueCategories.map(String); - return { xAxisData, series, maxStackSize, legendData }; - } - if (JSON.stringify(xAxis) == JSON.stringify(category)) { - apiData.values.forEach(([x, y, tooltip]) => { - if (!groupedData[x]) { - groupedData[x] = []; - xAxisData.push(x); - } - groupedData[x].push({ y, category: x, tooltip }); + // Assign colors to categories + const categoryColorMap = {}; + uniqueCategories.forEach((category, index) => { + categoryColorMap[category] = + colorList[index % colorCount]; // Cycle colors + }); + // Ensure we only create the exact number of stacks needed + const series = uniqueCategories.map( + (category, index) => ({ + type: "bar", + stack: "stack", + name: category.toString(), // Legend name + data: xAxisData.map((x) => { + const point = + groupedData[x].find( + (item) => + item.category === category, + ) || {}; + return { + value: + isNaN(point.y) || + point.y === undefined + ? point.y + : parseFloat(point.y) + .toFixed(2) + .replace(/\.00$/, ""), + category: point.category ?? "", + itemStyle: { + color: categoryColorMap[category], + }, // Assign correct color + tooltipValue: point.tooltip ?? "", // Store tooltip inside each data point + }; + }), + }), + ); + const legendData = uniqueCategories.map(String); + return { xAxisData, series, maxStackSize, legendData }; + } + if (JSON.stringify(xAxis) == JSON.stringify(category)) { + apiData.values.forEach(([x, y, tooltip]) => { + if (!groupedData[x]) { + groupedData[x] = []; + xAxisData.push(x); + } + groupedData[x].push({ y, category: x, tooltip }); - // Store unique categories for legend - if (x && !uniqueCategories.includes(x)) { - uniqueCategories.push(x); - } + // Store unique categories for legend + if (x && !uniqueCategories.includes(x)) { + uniqueCategories.push(x); + } - // Calculate max stack size (Max number of bars stacked at any x value) - maxStackSize = Math.max( - ...Object.values(groupedData).map( - (arr: any) => arr.length, - ), - ); - }); + // Calculate max stack size (Max number of bars stacked at any x value) + maxStackSize = Math.max( + ...Object.values(groupedData).map( + (arr: any) => arr.length, + ), + ); + }); - const colorList = data.option["color"]; - const colorCount = colorList.length; + const colorList = data.option["color"]; + const colorCount = colorList.length; - // Assign colors to categories - const categoryColorMap = {}; - uniqueCategories.forEach((category, index) => { - categoryColorMap[category] = - colorList[index % colorCount]; // Cycle colors - }); - // Ensure we only create the exact number of stacks needed - const series = uniqueCategories.map( - (category, index) => ({ - type: "bar", - stack: "stack", - name: category.toString(), // Legend name - data: xAxisData.map((x) => { - const point = - groupedData[x].find( - (item) => - item.category === category, - ) || {}; - return { - value: - isNaN(point.y) || - point.y === undefined - ? point.y - : parseFloat(point.y) - .toFixed(2) - .replace(/\.00$/, ""), - category: point.category ?? "", - itemStyle: { - color: categoryColorMap[category], - }, // Assign correct color - tooltipValue: point.tooltip ?? "", // Store tooltip inside each data point - }; - }), - }), - ); - const legendData = uniqueCategories.map(String); - return { xAxisData, series, maxStackSize, legendData }; - } - if (JSON.stringify(yAxis) == JSON.stringify(tooltip)) { - apiData.values.forEach(([x, y, category]) => { - if (!groupedData[x]) { - groupedData[x] = []; - xAxisData.push(x); - } - groupedData[x].push({ y, category, tooltip: y }); - // Store unique categories for legend - if ( - category && - !uniqueCategories.includes(category) - ) { - uniqueCategories.push(category); - } - // Calculate max stack size (Max number of bars stacked at any x value) - maxStackSize = Math.max( - ...Object.values(groupedData).map( - (arr: any) => arr.length, - ), - ); - }); - const colorList = data.option["color"]; - const colorCount = colorList.length; + // Assign colors to categories + const categoryColorMap = {}; + uniqueCategories.forEach((category, index) => { + categoryColorMap[category] = + colorList[index % colorCount]; // Cycle colors + }); + // Ensure we only create the exact number of stacks needed + const series = uniqueCategories.map( + (category, index) => ({ + type: "bar", + stack: "stack", + name: category.toString(), // Legend name + data: xAxisData.map((x) => { + const point = + groupedData[x].find( + (item) => + item.category === category, + ) || {}; + return { + value: + isNaN(point.y) || + point.y === undefined + ? point.y + : parseFloat(point.y) + .toFixed(2) + .replace(/\.00$/, ""), + category: point.category ?? "", + itemStyle: { + color: categoryColorMap[category], + }, // Assign correct color + tooltipValue: point.tooltip ?? "", // Store tooltip inside each data point + }; + }), + }), + ); + const legendData = uniqueCategories.map(String); + return { xAxisData, series, maxStackSize, legendData }; + } + if (JSON.stringify(yAxis) == JSON.stringify(tooltip)) { + apiData.values.forEach(([x, y, category]) => { + if (!groupedData[x]) { + groupedData[x] = []; + xAxisData.push(x); + } + groupedData[x].push({ y, category, tooltip: y }); + // Store unique categories for legend + if ( + category && + !uniqueCategories.includes(category) + ) { + uniqueCategories.push(category); + } + // Calculate max stack size (Max number of bars stacked at any x value) + maxStackSize = Math.max( + ...Object.values(groupedData).map( + (arr: any) => arr.length, + ), + ); + }); + const colorList = data.option["color"]; + const colorCount = colorList.length; - // Assign colors to categories - const categoryColorMap = {}; - uniqueCategories.forEach((category, index) => { - categoryColorMap[category] = - colorList[index % colorCount]; // Cycle colors - }); - // Ensure we only create the exact number of stacks needed - const series = uniqueCategories.map( - (category, index) => ({ - type: "bar", - stack: "stack", - name: category.toString(), // Legend name - data: xAxisData.map((x) => { - const point = - groupedData[x].find( - (item) => - item.category === category, - ) || {}; - return { - value: - isNaN(point.y) || - point.y === undefined - ? point.y - : parseFloat(point.y) - .toFixed(2) - .replace(/\.00$/, ""), - category: point.category ?? "", - itemStyle: { - color: categoryColorMap[category], - }, // Assign correct color - tooltipValue: point.tooltip ?? "", // Store tooltip inside each data point - }; - }), - }), - ); - const legendData = uniqueCategories.map(String); - return { xAxisData, series, maxStackSize, legendData }; - } - apiData.values.forEach(([x, y, category, tooltip]) => { - if (!groupedData[x]) { - groupedData[x] = []; - xAxisData.push(x); - } - groupedData[x].push({ y, category, tooltip }); - // Store unique categories for legend - if (category && !uniqueCategories.includes(category)) { - uniqueCategories.push(category); - } - // Calculate max stack size (Max number of bars stacked at any x value) - maxStackSize = Math.max( - ...Object.values(groupedData).map( - (arr: any) => arr.length, - ), - ); - }); + // Assign colors to categories + const categoryColorMap = {}; + uniqueCategories.forEach((category, index) => { + categoryColorMap[category] = + colorList[index % colorCount]; // Cycle colors + }); + // Ensure we only create the exact number of stacks needed + const series = uniqueCategories.map( + (category, index) => ({ + type: "bar", + stack: "stack", + name: category.toString(), // Legend name + data: xAxisData.map((x) => { + const point = + groupedData[x].find( + (item) => + item.category === category, + ) || {}; + return { + value: + isNaN(point.y) || + point.y === undefined + ? point.y + : parseFloat(point.y) + .toFixed(2) + .replace(/\.00$/, ""), + category: point.category ?? "", + itemStyle: { + color: categoryColorMap[category], + }, // Assign correct color + tooltipValue: point.tooltip ?? "", // Store tooltip inside each data point + }; + }), + }), + ); + const legendData = uniqueCategories.map(String); + return { xAxisData, series, maxStackSize, legendData }; + } + apiData.values.forEach(([x, y, category, tooltip]) => { + if (!groupedData[x]) { + groupedData[x] = []; + xAxisData.push(x); + } + groupedData[x].push({ y, category, tooltip }); + // Store unique categories for legend + if (category && !uniqueCategories.includes(category)) { + uniqueCategories.push(category); + } + // Calculate max stack size (Max number of bars stacked at any x value) + maxStackSize = Math.max( + ...Object.values(groupedData).map( + (arr: any) => arr.length, + ), + ); + }); - const colorList = data.option["color"]; - const colorCount = colorList.length; + const colorList = data.option["color"]; + const colorCount = colorList.length; - // Assign colors to categories - const categoryColorMap = {}; - uniqueCategories.forEach((category, index) => { - categoryColorMap[category] = - colorList[index % colorCount]; // Cycle colors - }); - // Ensure we only create the exact number of stacks needed - const series = uniqueCategories.map((category, index) => ({ - type: "bar", - stack: "stack", - name: category.toString(), // Legend name - data: xAxisData.map((x) => { - const point = - groupedData[x].find( - (item) => item.category === category, - ) || {}; - return { - value: - isNaN(point.y) || point.y === undefined - ? point.y - : parseFloat(point.y) - .toFixed(2) - .replace(/\.00$/, ""), - category: point.category ?? "", - itemStyle: { - color: categoryColorMap[category], - }, // Assign correct color - tooltipValue: point.tooltip ?? "", // Store tooltip inside each data point - }; - }), - })); - const legendData = uniqueCategories.map(String); - return { xAxisData, series, maxStackSize, legendData }; - } - if ( - fields.hasOwnProperty("XAxis") && - fields.hasOwnProperty("YAxis") && - fields.hasOwnProperty("category") - ) { - if (JSON.stringify(xAxis) == JSON.stringify(category)) { - apiData.values.forEach(([x, y]) => { - if (!groupedData[x]) { - groupedData[x] = []; - xAxisData.push(x); - } - groupedData[x].push({ y, category: x }); + // Assign colors to categories + const categoryColorMap = {}; + uniqueCategories.forEach((category, index) => { + categoryColorMap[category] = + colorList[index % colorCount]; // Cycle colors + }); + // Ensure we only create the exact number of stacks needed + const series = uniqueCategories.map((category, index) => ({ + type: "bar", + stack: "stack", + name: category.toString(), // Legend name + data: xAxisData.map((x) => { + const point = + groupedData[x].find( + (item) => item.category === category, + ) || {}; + return { + value: + isNaN(point.y) || point.y === undefined + ? point.y + : parseFloat(point.y) + .toFixed(2) + .replace(/\.00$/, ""), + category: point.category ?? "", + itemStyle: { + color: categoryColorMap[category], + }, // Assign correct color + tooltipValue: point.tooltip ?? "", // Store tooltip inside each data point + }; + }), + })); + const legendData = uniqueCategories.map(String); + return { xAxisData, series, maxStackSize, legendData }; + } + if ( + Object.hasOwn(fields, "XAxis") && + Object.hasOwn(fields, "YAxis") && + Object.hasOwn(fields, "category") + ) { + if (JSON.stringify(xAxis) == JSON.stringify(category)) { + apiData.values.forEach(([x, y]) => { + if (!groupedData[x]) { + groupedData[x] = []; + xAxisData.push(x); + } + groupedData[x].push({ y, category: x }); - // Store unique categories for legend - if (x && !uniqueCategories.includes(x)) { - uniqueCategories.push(x); - } + // Store unique categories for legend + if (x && !uniqueCategories.includes(x)) { + uniqueCategories.push(x); + } - // Calculate max stack size (Max number of bars stacked at any x value) - maxStackSize = Math.max( - ...Object.values(groupedData).map( - (arr: any) => arr.length, - ), - ); - }); - const colorList = data.option["color"]; - const colorCount = colorList.length; + // Calculate max stack size (Max number of bars stacked at any x value) + maxStackSize = Math.max( + ...Object.values(groupedData).map( + (arr: any) => arr.length, + ), + ); + }); + const colorList = data.option["color"]; + const colorCount = colorList.length; - // Assign colors to categories - const categoryColorMap = {}; - uniqueCategories.forEach((category, index) => { - categoryColorMap[category] = - colorList[index % colorCount]; // Cycle colors - }); - // Ensure we only create the exact number of stacks needed - const series = uniqueCategories.map( - (category, index) => ({ - type: "bar", - stack: "stack", - name: category.toString(), // Legend name - data: xAxisData.map((x) => { - const point = - groupedData[x].find( - (item) => - item.category === category, - ) || {}; - return { - value: - isNaN(point.y) || - point.y === undefined - ? point.y - : parseFloat(point.y) - .toFixed(2) - .replace(/\.00$/, ""), - category: point.category ?? "", - itemStyle: { - color: categoryColorMap[category], - }, // Assign correct color - }; - }), - }), - ); - const legendData = uniqueCategories.map(String); - return { xAxisData, series, maxStackSize, legendData }; - } - // Process the API data - apiData.values.forEach(([x, y, category]) => { - if (!groupedData[x]) { - groupedData[x] = []; - xAxisData.push(x); - } - groupedData[x].push({ y, category }); + // Assign colors to categories + const categoryColorMap = {}; + uniqueCategories.forEach((category, index) => { + categoryColorMap[category] = + colorList[index % colorCount]; // Cycle colors + }); + // Ensure we only create the exact number of stacks needed + const series = uniqueCategories.map( + (category, index) => ({ + type: "bar", + stack: "stack", + name: category.toString(), // Legend name + data: xAxisData.map((x) => { + const point = + groupedData[x].find( + (item) => + item.category === category, + ) || {}; + return { + value: + isNaN(point.y) || + point.y === undefined + ? point.y + : parseFloat(point.y) + .toFixed(2) + .replace(/\.00$/, ""), + category: point.category ?? "", + itemStyle: { + color: categoryColorMap[category], + }, // Assign correct color + }; + }), + }), + ); + const legendData = uniqueCategories.map(String); + return { xAxisData, series, maxStackSize, legendData }; + } + // Process the API data + apiData.values.forEach(([x, y, category]) => { + if (!groupedData[x]) { + groupedData[x] = []; + xAxisData.push(x); + } + groupedData[x].push({ y, category }); - // Store unique categories for legend - if (category && !uniqueCategories.includes(category)) { - uniqueCategories.push(category); - } + // Store unique categories for legend + if (category && !uniqueCategories.includes(category)) { + uniqueCategories.push(category); + } - // Calculate max stack size (Max number of bars stacked at any x value) - maxStackSize = Math.max( - ...Object.values(groupedData).map( - (arr: any) => arr.length, - ), - ); - }); + // Calculate max stack size (Max number of bars stacked at any x value) + maxStackSize = Math.max( + ...Object.values(groupedData).map( + (arr: any) => arr.length, + ), + ); + }); - const colorList = data.option["color"]; - const colorCount = colorList.length; + const colorList = data.option["color"]; + const colorCount = colorList.length; - // Assign colors to categories - const categoryColorMap = {}; - uniqueCategories.forEach((category, index) => { - categoryColorMap[category] = - colorList[index % colorCount]; // Cycle colors - }); - // Ensure we only create the exact number of stacks needed - const series = uniqueCategories.map((category, index) => ({ - type: "bar", - stack: "stack", - name: category.toString(), // Legend name - data: xAxisData.map((x) => { - const point = - groupedData[x].find( - (item) => item.category === category, - ) || {}; - return { - value: - isNaN(point.y) || point.y === undefined - ? point.y - : parseFloat(point.y) - .toFixed(2) - .replace(/\.00$/, ""), - category: point.category ?? "", - itemStyle: { - color: categoryColorMap[category], - }, // Assign correct color - }; - }), - })); - const legendData = uniqueCategories.map(String); - return { xAxisData, series, maxStackSize, legendData }; - } - } - } - return { xAxisData: [], series: [], maxStackSize: 0, legendData: [] }; - }; - // this function is used to show the data in tooltip - const formatdatapoints = (apiData, data, maxStackSize) => { - if (apiData["values"]) { - if (data.option.hasOwnProperty("_state")) { - if (data.option["_state"].hasOwnProperty("fields")) { - if ( - fields.hasOwnProperty("XAxis") && - fields.hasOwnProperty("YAxis") && - fields.hasOwnProperty("category") && - fields.hasOwnProperty("tooltip") - ) { - return function (params) { - let tooltipText = `${params[0].axisValue}
`; - const tooltipValues = []; - let totalTooltipValue = 0; - const tooltipPrefix = - data.option["_state"]["fields"][ - "tooltipDataType" - ] === "NUMBER" - ? "Average of" - : "Count of"; - params.forEach((param) => { - const tooltipValue = param.data.tooltipValue; - if (param.data.category !== "") { - tooltipText += `${param.marker} ${param.data.category}: ${param.value}
`; - } - if ( - tooltipValue !== "" && - tooltipValue !== "NaN" && - tooltipValue !== undefined - ) { - tooltipValues.push(Number(tooltipValue)); - totalTooltipValue += - parseFloat(tooltipValue); - } - }); - if (maxStackSize > 0) { - const average = - totalTooltipValue / maxStackSize; - tooltipText += `${tooltipPrefix} ${tooltip}: ${average}
`; - } - return tooltipText.trim(); - }; - } - if ( - fields.hasOwnProperty("XAxis") && - fields.hasOwnProperty("YAxis") && - fields.hasOwnProperty("category") - ) { - return function (params) { - let tooltipText = `${params[0].axisValue}
`; - params.forEach((param) => { - if (param.data.category !== "") { - tooltipText += `${param.marker} ${param.data.category}: ${param.value}
`; - } - }); - return tooltipText.trim(); - }; - } - } - } - } - }; - if (!data.option) { - return ( - - Add JSON to render your visualization - - ); - } - if (typeof data.option === "string") { - try { - return ( - - - - ); - } catch (e) { - return ( - - There was an issue parsing your JSON. - - ); - } - } else { - data.option["series"] = []; - data.option["xAxis"]["data"] = []; - data.option["yAxis"]["data"] = []; - const processedFrameData = processData(frame.data, data); - if ( - processedFrameData && - processedFrameData.hasOwnProperty("xAxisData") && - processedFrameData.hasOwnProperty("series") - ) { - data.option["series"] = processedFrameData.series; - data.option["legend"]["data"] = processedFrameData.legendData; - if (data.option["flipAxis"] === true) { - data.option["xAxis"]["data"] = []; - data.option["yAxis"]["data"] = processedFrameData["xAxisData"]; - } else { - data.option["yAxis"]["data"] = []; - data.option["xAxis"]["data"] = processedFrameData["xAxisData"]; - } - } - if (frame.data.values.length > 0) { - if ( - !data.option["tooltip"].hasOwnProperty("formatter") || - data.option["tooltip"]["formatter"] === "" - ) { - data.option["tooltip"] = { - ...data.option["tooltip"], - formatter: formatdatapoints( - frame.data, - data, - processedFrameData.maxStackSize, - ), - }; - } - } - return ( - - { - echartsLoaded(chart); - }} - onEvents={onClickChart} - /> - { - chartOperationData.current.contextMenu = null; - chartOperationData.current.yAxisColumn = null; - chartOperationData.current.brushSelected = null; - setContextMenu(null); - }} - /> - - ); - } + // Assign colors to categories + const categoryColorMap = {}; + uniqueCategories.forEach((category, index) => { + categoryColorMap[category] = + colorList[index % colorCount]; // Cycle colors + }); + // Ensure we only create the exact number of stacks needed + const series = uniqueCategories.map((category, index) => ({ + type: "bar", + stack: "stack", + name: category.toString(), // Legend name + data: xAxisData.map((x) => { + const point = + groupedData[x].find( + (item) => item.category === category, + ) || {}; + return { + value: + isNaN(point.y) || point.y === undefined + ? point.y + : parseFloat(point.y) + .toFixed(2) + .replace(/\.00$/, ""), + category: point.category ?? "", + itemStyle: { + color: categoryColorMap[category], + }, // Assign correct color + }; + }), + })); + const legendData = uniqueCategories.map(String); + return { xAxisData, series, maxStackSize, legendData }; + } + } + } + return { xAxisData: [], series: [], maxStackSize: 0, legendData: [] }; + }; + // this function is used to show the data in tooltip + const formatdatapoints = (apiData, data, maxStackSize) => { + if (apiData["values"]) { + if (Object.hasOwn(data.option, "_state")) { + if (Object.hasOwn(data.option["_state"], "fields")) { + if ( + Object.hasOwn(fields, "XAxis") && + Object.hasOwn(fields, "YAxis") && + Object.hasOwn(fields, "category") && + Object.hasOwn(fields, "tooltip") + ) { + return (params) => { + let tooltipText = `${params[0].axisValue}
`; + const tooltipValues = []; + let totalTooltipValue = 0; + const tooltipPrefix = + data.option["_state"]["fields"][ + "tooltipDataType" + ] === "NUMBER" + ? "Average of" + : "Count of"; + params.forEach((param) => { + const tooltipValue = param.data.tooltipValue; + if (param.data.category !== "") { + tooltipText += `${param.marker} ${param.data.category}: ${param.value}
`; + } + if ( + tooltipValue !== "" && + tooltipValue !== "NaN" && + tooltipValue !== undefined + ) { + tooltipValues.push(Number(tooltipValue)); + totalTooltipValue += + parseFloat(tooltipValue); + } + }); + if (maxStackSize > 0) { + const average = + totalTooltipValue / maxStackSize; + tooltipText += `${tooltipPrefix} ${tooltip}: ${average}
`; + } + return tooltipText.trim(); + }; + } + if ( + Object.hasOwn(fields, "XAxis") && + Object.hasOwn(fields, "YAxis") && + Object.hasOwn(fields, "category") + ) { + return (params) => { + let tooltipText = `${params[0].axisValue}
`; + params.forEach((param) => { + if (param.data.category !== "") { + tooltipText += `${param.marker} ${param.data.category}: ${param.value}
`; + } + }); + return tooltipText.trim(); + }; + } + } + } + } + }; + if (!data.option) { + return ( + + Add JSON to render your visualization + + ); + } + if (typeof data.option === "string") { + try { + return ( + + + + ); + } catch (e) { + return ( + + There was an issue parsing your JSON. + + ); + } + } else { + data.option["series"] = []; + data.option["xAxis"]["data"] = []; + data.option["yAxis"]["data"] = []; + const processedFrameData = processData(frame.data, data); + if ( + processedFrameData && + Object.hasOwn(processedFrameData, "xAxisData") && + Object.hasOwn(processedFrameData, "series") + ) { + data.option["series"] = processedFrameData.series; + data.option["legend"]["data"] = processedFrameData.legendData; + if (data.option["flipAxis"] === true) { + data.option["xAxis"]["data"] = []; + data.option["yAxis"]["data"] = processedFrameData["xAxisData"]; + } else { + data.option["yAxis"]["data"] = []; + data.option["xAxis"]["data"] = processedFrameData["xAxisData"]; + } + } + if (frame.data.values.length > 0) { + if ( + !Object.hasOwn(data.option["tooltip"], "formatter") || + data.option["tooltip"]["formatter"] === "" + ) { + data.option["tooltip"] = { + ...data.option["tooltip"], + formatter: formatdatapoints( + frame.data, + data, + processedFrameData.maxStackSize, + ), + }; + } + } + return ( + + { + echartsLoaded(chart); + }} + onEvents={onClickChart} + /> + { + chartOperationData.current.contextMenu = null; + chartOperationData.current.yAxisColumn = null; + chartOperationData.current.brushSelected = null; + setContextMenu(null); + }} + /> + + ); + } }); diff --git a/libs/renderer/src/components/block-defaults/flip-card-block/FlipCardBlock.tsx b/libs/renderer/src/components/block-defaults/flip-card-block/FlipCardBlock.tsx index ecb7f456c9..5c36228614 100644 --- a/libs/renderer/src/components/block-defaults/flip-card-block/FlipCardBlock.tsx +++ b/libs/renderer/src/components/block-defaults/flip-card-block/FlipCardBlock.tsx @@ -1,111 +1,110 @@ -import { CSSProperties, useState, useEffect } from "react"; import { observer } from "mobx-react-lite"; +import { type CSSProperties, useEffect, useState } from "react"; import { Card, styled } from "@semoss/ui"; - import { useBlock, useBlocks } from "../../../hooks"; -import { BlockDef, BlockComponent, ListenerActions } from "../../../store"; +import type { BlockComponent, BlockDef, ListenerActions } from "../../../store"; import { Slot } from "../../blocks"; const CardContainer = styled("div")<{ cssStyle: CSSProperties }>( - ({ cssStyle }) => ({ - ...cssStyle, - width: cssStyle.width || "300px", - height: cssStyle.height || "200px", - perspective: "1000px", - border: "none", - }), + ({ cssStyle }) => ({ + ...cssStyle, + width: cssStyle.width || "300px", + height: cssStyle.height || "200px", + perspective: "1000px", + border: "none", + }), ); const CardFlipper = styled("div")<{ flipped: boolean }>(({ flipped }) => ({ - width: "100%", - height: "100%", - position: "relative", - transformStyle: "preserve-3d", - transition: "transform 0.6s", - transform: flipped ? "rotateY(180deg)" : "rotateY(0deg)", + width: "100%", + height: "100%", + position: "relative", + transformStyle: "preserve-3d", + transition: "transform 0.6s", + transform: flipped ? "rotateY(180deg)" : "rotateY(0deg)", })); const sharedFaceStyles: CSSProperties = { - position: "absolute", - width: "100%", - height: "100%", - backfaceVisibility: "hidden", - WebkitBackfaceVisibility: "hidden", - borderRadius: "12px", - boxShadow: "0 4px 8px rgba(0,0,0,0.2)", + position: "absolute", + width: "100%", + height: "100%", + backfaceVisibility: "hidden", + WebkitBackfaceVisibility: "hidden", + borderRadius: "12px", + boxShadow: "0 4px 8px rgba(0,0,0,0.2)", }; const FrontCard = styled(Card)({ - ...sharedFaceStyles, - zIndex: 2, + ...sharedFaceStyles, + zIndex: 2, }); const BackCard = styled(Card)({ - ...sharedFaceStyles, - transform: "rotateY(180deg)", + ...sharedFaceStyles, + transform: "rotateY(180deg)", }); export interface FlipCardBlockDef extends BlockDef<"flip-card"> { - widget: "flip-card"; - data: { - style: CSSProperties; - isFlipped: boolean; - frontBgColor: "#ffffff"; - backBgColor: "#ffffff"; - show: string; - }; - slots: { - front: true; - back: true; - }; - listeners: { - preProcess: { - type: "sync" | "async"; - order: ListenerActions[]; - }; - }; + widget: "flip-card"; + data: { + style: CSSProperties; + isFlipped: boolean; + frontBgColor: "#ffffff"; + backBgColor: "#ffffff"; + show: string; + }; + slots: { + front: true; + back: true; + }; + listeners: { + preProcess: { + type: "sync" | "async"; + order: ListenerActions[]; + }; + }; } export const FlipCardBlock: BlockComponent = observer(({ id }) => { - const { attrs, data, slots, listeners } = useBlock(id); - const { state } = useBlocks(); + const { attrs, data, slots, listeners } = useBlock(id); + const { state } = useBlocks(); - const isStatic = state.mode === "static"; - const { width, height, padding, margin, ...withoutDimensions } = data.style; + const isStatic = state.mode === "static"; + const { width, height, padding, margin, ...withoutDimensions } = data.style; - const [flipped, setFlipped] = useState(false); + const [flipped, setFlipped] = useState(false); - useEffect(() => { - if (listeners.preProcess) { - listeners.preProcess(); - } - }, []); + useEffect(() => { + if (listeners.preProcess) { + listeners.preProcess(); + } + }, []); - return ( - setFlipped(true)} - onMouseLeave={() => setFlipped(false)} - cssStyle={data.style} - {...attrs} - > - - - - - - - - - - ); + return ( + setFlipped(true)} + onMouseLeave={() => setFlipped(false)} + cssStyle={data.style} + {...attrs} + > + + + + + + + + + + ); }); diff --git a/libs/renderer/src/components/block-defaults/flip-card-block/config.tsx b/libs/renderer/src/components/block-defaults/flip-card-block/config.tsx index 7e3c4de560..c91e787739 100644 --- a/libs/renderer/src/components/block-defaults/flip-card-block/config.tsx +++ b/libs/renderer/src/components/block-defaults/flip-card-block/config.tsx @@ -1,6 +1,6 @@ -import { BlockConfig } from "../../../store"; -import { FlipCardBlockDef, FlipCardBlock } from "./FlipCardBlock"; +import type { BlockConfig } from "../../../store"; import { BLOCK_TYPE_LAYOUT } from "../block-defaults.constants"; +import { FlipCardBlock, type FlipCardBlockDef } from "./FlipCardBlock"; // TODO: // ------------------------------------------------------------- @@ -12,29 +12,29 @@ import { BLOCK_TYPE_LAYOUT } from "../block-defaults.constants"; // export the config for the block export const config: BlockConfig = { - widget: "flip-card", - type: BLOCK_TYPE_LAYOUT, - data: { - style: { - display: "flex", - flexDirection: "column", - padding: "4px", - gap: "8px", - }, - frontBgColor: "#ffffff", - backBgColor: "#ffffff", - isFlipped: false, - show: "true", - }, - listeners: { - preProcess: { - type: "sync", - order: [], - }, - }, - slots: { - front: [], - back: [], - }, - render: FlipCardBlock, + widget: "flip-card", + type: BLOCK_TYPE_LAYOUT, + data: { + style: { + display: "flex", + flexDirection: "column", + padding: "4px", + gap: "8px", + }, + frontBgColor: "#ffffff", + backBgColor: "#ffffff", + isFlipped: false, + show: "true", + }, + listeners: { + preProcess: { + type: "sync", + order: [], + }, + }, + slots: { + front: [], + back: [], + }, + render: FlipCardBlock, }; diff --git a/libs/renderer/src/components/block-defaults/grid-block/GridBlock.tsx b/libs/renderer/src/components/block-defaults/grid-block/GridBlock.tsx index 6ea4da0b28..1f0953df4a 100644 --- a/libs/renderer/src/components/block-defaults/grid-block/GridBlock.tsx +++ b/libs/renderer/src/components/block-defaults/grid-block/GridBlock.tsx @@ -1,472 +1,470 @@ -import { useState, useEffect } from "react"; -import { observer } from "mobx-react-lite"; import { styled } from "@mui/material"; import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid"; - +import { observer } from "mobx-react-lite"; +import { useEffect, useState } from "react"; import { useBlock, useFrame, useFrameHeaders } from "../../../hooks"; -import { BlockComponent, BlockDef } from "../../../store"; - -import { GridBlockColumn } from "./grid-block.types"; +import type { BlockComponent, BlockDef } from "../../../store"; import { GridBlockContextMenu } from "./GridBlockContextMenu"; +import type { GridBlockColumn } from "./grid-block.types"; const DEFAULT_HEIGHT = "300px"; const DEFAULT_WIDTH = "500px"; const StyledBlock = styled("div")(() => ({ - display: "flex", - flexDirection: "column", - height: DEFAULT_HEIGHT, - width: DEFAULT_WIDTH, + display: "flex", + flexDirection: "column", + height: DEFAULT_HEIGHT, + width: DEFAULT_WIDTH, })); const StyledTitle = styled("div")(() => ({ - width: "100%", - display: "flex", - justifyContent: "center", + width: "100%", + display: "flex", + justifyContent: "center", })); export interface HeaderBackgroundSettings { - backgroundColor: string; - fontSize: string; - fontColor: string; - selectedColumn: string[]; + backgroundColor: string; + fontSize: string; + fontColor: string; + selectedColumn: string[]; } export interface CellBackgroundSettings { - backgroundColor: string; - fontSize: string; - fontColor: string; - selectedColumn: string[]; + backgroundColor: string; + fontSize: string; + fontColor: string; + selectedColumn: string[]; } export interface ChartTitleSettings { - chartTitle: string; - fontSize: string; - fontColor: string; + chartTitle: string; + fontSize: string; + fontColor: string; } export interface WrapTextSettings { - selectedColumn: string[]; - textWrap: boolean; + selectedColumn: string[]; + textWrap: boolean; } export interface ColorRule { - id: string; - column: string; - comparator: string; - value: string; - valueColumn: string; - color: string; - colorEntireRow: boolean; + id: string; + column: string; + comparator: string; + value: string; + valueColumn: string; + color: string; + colorEntireRow: boolean; } export interface GridBlockDef extends BlockDef<"grid"> { - widget: "grid"; - - /** data associated with the block */ - data: { - /** Bind the grid to a frame */ - frame: { - name: string; - }; - - /** Column Definitions */ - columns: GridBlockColumn[]; - - /** */ - style: { - height: string | undefined; - width: string | undefined; - display: string | undefined; - flexDirection: string | undefined; - padding: string | undefined; - gap: string | undefined; - flexWrap: string | undefined; - }; - option: { - headerBackgroundSettings?: HeaderBackgroundSettings; - cellBackgroundSettings?: CellBackgroundSettings; - chartTitleSettings?: ChartTitleSettings; - wrapTextSettings?: WrapTextSettings; - rowSpanning?: boolean; - colorByValue?: ColorRule[]; - }; - variation: undefined | string; - show: boolean; - - /** Context Menu */ - contextMenu?: { - /** Show the unfilter related options */ - hideUnfilter: boolean; - - /** Show the filter related options */ - hideFilter: boolean; - }; - - view?: { - //TODO: Include limit + offset? - - /** Enable the pagination */ - pagination: boolean; - }; - }; + widget: "grid"; + + /** data associated with the block */ + data: { + /** Bind the grid to a frame */ + frame: { + name: string; + }; + + /** Column Definitions */ + columns: GridBlockColumn[]; + + /** */ + style: { + height: string | undefined; + width: string | undefined; + display: string | undefined; + flexDirection: string | undefined; + padding: string | undefined; + gap: string | undefined; + flexWrap: string | undefined; + }; + option: { + headerBackgroundSettings?: HeaderBackgroundSettings; + cellBackgroundSettings?: CellBackgroundSettings; + chartTitleSettings?: ChartTitleSettings; + wrapTextSettings?: WrapTextSettings; + rowSpanning?: boolean; + colorByValue?: ColorRule[]; + }; + variation: undefined | string; + show: boolean; + + /** Context Menu */ + contextMenu?: { + /** Show the unfilter related options */ + hideUnfilter: boolean; + + /** Show the filter related options */ + hideFilter: boolean; + }; + + view?: { + //TODO: Include limit + offset? + + /** Enable the pagination */ + pagination: boolean; + }; + }; } export const GridBlock: BlockComponent = observer(({ id }) => { - const { attrs, data, setData } = useBlock(id); - const [paginationModel, setPaginationModel] = useState({ - page: 0, - pageSize: 50, - }); - - const [contextMenu, setContextMenu] = useState<{ - mouseX: number; - mouseY: number; - column: GridBlockColumn; - value: unknown; - } | null>(null); - - // create the selector - const selector = `Select(${data.columns - .map((c) => { - return c.selector; - }) - .join(", ")}).as([${data.columns - .map((c) => { - return c.name; - }) - .join(", ")}])`; - - // get the frame - const frame = useFrame(data.frame.name, { - selector: selector, - offset: paginationModel.page * paginationModel.pageSize, - limit: paginationModel.pageSize, - enableCount: true, - }); - - // When headers come from user upload - const frameHeaders = useFrameHeaders(data.frame.name); - - /** - * Anytime our Frame Headers, we need to sync our column block data with our source of truth ^ - */ - useEffect(() => { - if (data.columns.length === 0 && !frameHeaders.isLoading) { - // If no columns are defined, fetch the frame headers - if (frameHeaders.data.list.length > 0) { - syncBlockDataColumns(frameHeaders); - } - } - }, [frameHeaders.data.list]); - - /** - * Updates data.columns - * @param synData - */ - const syncBlockDataColumns = (cols) => { - const columns: GridBlockColumn[] = cols.data.list.map((h) => { - return { - name: h.alias, - width: undefined, - selector: h.header, - }; - }); - // update the data - setData("columns", columns); - }; - - /** - * Handle the callback for the context menu - * @param event - triggered event - * @param column - selected column - * @param row - value - */ - const handleTableCellOnContextMenu = ( - event: React.MouseEvent, - column: GridBlockColumn, - value: unknown, - ) => { - // prevent the default interaction - event.preventDefault(); - - // open the menu and save the data - setContextMenu( - contextMenu === null - ? { - mouseX: event.clientX + 2, - mouseY: event.clientY - 6, - column: column, - value: value, - } - : // repeated contextmenu when it is already open closes it with Chrome 84 on Ubuntu - // Other native context menus might behave different. - // With this behavior we prevent contextmenu from the backdrop to re-locale existing context menus. - null, - ); - }; - - function evaluate( - cellValue: string, - comparator: string, - target: string, - ): boolean { - const a = - typeof cellValue === "number" ? cellValue : parseFloat(cellValue); - const b = typeof target === "number" ? target : parseFloat(target); - switch (comparator) { - case "==": - return a == b; - case "!=": - return a != b; - case ">": - return a > b; - case "<": - return a < b; - case ">=": - return a >= b; - case "<=": - return a <= b; - default: - return false; - } - } - - const columns = data.columns.map((col) => ({ - field: col.name, - headerName: col.name, - sortable: false, - renderHeader: () => ( -
- {col.name} -
- ), - - renderCell: (params) => { - const isWrapEnabled = - wrapTextSettings.textWrap && - wrapTextSettings.selectedColumn.includes(col.name); - - const origionalStyle: React.CSSProperties = { - // Apply style if the column is selected - backgroundColor: cellSettings.selectedColumn.includes(col.name) - ? cellSettings.backgroundColor - : "inherit", - color: cellSettings.selectedColumn.includes(col.name) - ? cellSettings.fontColor - : "inherit", - fontSize: cellSettings.selectedColumn.includes(col.name) - ? `${cellSettings.fontSize}px` - : "inherit", - padding: "8px", - width: "100%", - lineHeight: isWrapEnabled ? "1.5" : "normal", - whiteSpace: - wrapTextSettings.textWrap && - wrapTextSettings.selectedColumn.includes(col.name) - ? "normal" - : "nowrap", - wordBreak: - wrapTextSettings.textWrap && - wrapTextSettings.selectedColumn.includes(col.name) - ? "break-word" - : "normal", - }; - - const matchingRowRules = colorRules.filter((rule) => { - return evaluate( - params.row[rule.column], - rule.comparator, - rule.value, - ); - }); - - const style = { ...origionalStyle }; - for (const rule of matchingRowRules) { - if (rule.colorEntireRow) { - style.backgroundColor = rule.color; - style.color = "#fff"; - break; - } - - if (rule.valueColumn === col.name) { - style.backgroundColor = rule.color; - style.color = "#fff"; - break; - } - } - - return ( -
- handleTableCellOnContextMenu(e, col, params.value) - } - style={{ - ...style, - }} - > - {params.value} -
- ); - }, - })); - - const rows = frame.data.values.map((r, idx) => { - const obj: Record = { id: idx }; - columns.forEach((c, cIdx) => { - obj[c.field] = r[cIdx]; - }); - return obj; - }); - - const handlePaginationModalChange = (newmodel) => { - // if the page size has changed reset the page - if (newmodel.pageSize !== paginationModel.pageSize) { - setPaginationModel({ - page: 0, - pageSize: newmodel.pageSize, - }); - } else { - setPaginationModel(newmodel); - } - }; - - const headerSettings = { - fontSize: "16", - fontColor: "#000000", - selectedColumn: [], - backgroundColor: "white", - ...data.option?.headerBackgroundSettings, - }; - - const cellSettings = { - fontSize: "16", - fontColor: "#000000", - selectedColumn: [], - backgroundColor: "white", - ...data.option?.cellBackgroundSettings, - }; - - const titleSettings = data.option?.chartTitleSettings || { - chartTitle: "", - fontSize: "16", - fontColor: "#000000", - }; - - const wrapTextSettings = { - selectedColumn: [], - textWrap: false, - ...data.option?.wrapTextSettings, - }; - - const colorRules: ColorRule[] = data.option?.colorByValue || []; - - const getRowHeight = (params: any) => { - if (data.option?.rowSpanning) { - return 50; - } - return "auto"; - }; - - const GridToolbar = () => { - return ( - - - {titleSettings.chartTitle} - - - ); - }; - - return ( - -
- -
- setContextMenu(null)} - /> -
- ); + const { attrs, data, setData } = useBlock(id); + const [paginationModel, setPaginationModel] = useState({ + page: 0, + pageSize: 50, + }); + + const [contextMenu, setContextMenu] = useState<{ + mouseX: number; + mouseY: number; + column: GridBlockColumn; + value: unknown; + } | null>(null); + + // create the selector + const selector = `Select(${data.columns + .map((c) => { + return c.selector; + }) + .join(", ")}).as([${data.columns + .map((c) => { + return c.name; + }) + .join(", ")}])`; + + // get the frame + const frame = useFrame(data.frame.name, { + selector: selector, + offset: paginationModel.page * paginationModel.pageSize, + limit: paginationModel.pageSize, + enableCount: true, + }); + + // When headers come from user upload + const frameHeaders = useFrameHeaders(data.frame.name); + + /** + * Anytime our Frame Headers, we need to sync our column block data with our source of truth ^ + */ + useEffect(() => { + if (data.columns.length === 0 && !frameHeaders.isLoading) { + // If no columns are defined, fetch the frame headers + if (frameHeaders.data.list.length > 0) { + syncBlockDataColumns(frameHeaders); + } + } + }, [frameHeaders.data.list]); + + /** + * Updates data.columns + * @param synData + */ + const syncBlockDataColumns = (cols) => { + const columns: GridBlockColumn[] = cols.data.list.map((h) => { + return { + name: h.alias, + width: undefined, + selector: h.header, + }; + }); + // update the data + setData("columns", columns); + }; + + /** + * Handle the callback for the context menu + * @param event - triggered event + * @param column - selected column + * @param row - value + */ + const handleTableCellOnContextMenu = ( + event: React.MouseEvent, + column: GridBlockColumn, + value: unknown, + ) => { + // prevent the default interaction + event.preventDefault(); + + // open the menu and save the data + setContextMenu( + contextMenu === null + ? { + mouseX: event.clientX + 2, + mouseY: event.clientY - 6, + column: column, + value: value, + } + : // repeated contextmenu when it is already open closes it with Chrome 84 on Ubuntu + // Other native context menus might behave different. + // With this behavior we prevent contextmenu from the backdrop to re-locale existing context menus. + null, + ); + }; + + function evaluate( + cellValue: string, + comparator: string, + target: string, + ): boolean { + const a = + typeof cellValue === "number" ? cellValue : parseFloat(cellValue); + const b = typeof target === "number" ? target : parseFloat(target); + switch (comparator) { + case "==": + return a == b; + case "!=": + return a != b; + case ">": + return a > b; + case "<": + return a < b; + case ">=": + return a >= b; + case "<=": + return a <= b; + default: + return false; + } + } + + const columns = data.columns.map((col) => ({ + field: col.name, + headerName: col.name, + sortable: false, + renderHeader: () => ( +
+ {col.name} +
+ ), + + renderCell: (params) => { + const isWrapEnabled = + wrapTextSettings.textWrap && + wrapTextSettings.selectedColumn.includes(col.name); + + const origionalStyle: React.CSSProperties = { + // Apply style if the column is selected + backgroundColor: cellSettings.selectedColumn.includes(col.name) + ? cellSettings.backgroundColor + : "inherit", + color: cellSettings.selectedColumn.includes(col.name) + ? cellSettings.fontColor + : "inherit", + fontSize: cellSettings.selectedColumn.includes(col.name) + ? `${cellSettings.fontSize}px` + : "inherit", + padding: "8px", + width: "100%", + lineHeight: isWrapEnabled ? "1.5" : "normal", + whiteSpace: + wrapTextSettings.textWrap && + wrapTextSettings.selectedColumn.includes(col.name) + ? "normal" + : "nowrap", + wordBreak: + wrapTextSettings.textWrap && + wrapTextSettings.selectedColumn.includes(col.name) + ? "break-word" + : "normal", + }; + + const matchingRowRules = colorRules.filter((rule) => { + return evaluate( + params.row[rule.column], + rule.comparator, + rule.value, + ); + }); + + const style = { ...origionalStyle }; + for (const rule of matchingRowRules) { + if (rule.colorEntireRow) { + style.backgroundColor = rule.color; + style.color = "#fff"; + break; + } + + if (rule.valueColumn === col.name) { + style.backgroundColor = rule.color; + style.color = "#fff"; + break; + } + } + + return ( +
+ handleTableCellOnContextMenu(e, col, params.value) + } + style={{ + ...style, + }} + > + {params.value} +
+ ); + }, + })); + + const rows = frame.data.values.map((r, idx) => { + const obj: Record = { id: idx }; + columns.forEach((c, cIdx) => { + obj[c.field] = r[cIdx]; + }); + return obj; + }); + + const handlePaginationModalChange = (newmodel) => { + // if the page size has changed reset the page + if (newmodel.pageSize !== paginationModel.pageSize) { + setPaginationModel({ + page: 0, + pageSize: newmodel.pageSize, + }); + } else { + setPaginationModel(newmodel); + } + }; + + const headerSettings = { + fontSize: "16", + fontColor: "#000000", + selectedColumn: [], + backgroundColor: "white", + ...data.option?.headerBackgroundSettings, + }; + + const cellSettings = { + fontSize: "16", + fontColor: "#000000", + selectedColumn: [], + backgroundColor: "white", + ...data.option?.cellBackgroundSettings, + }; + + const titleSettings = data.option?.chartTitleSettings || { + chartTitle: "", + fontSize: "16", + fontColor: "#000000", + }; + + const wrapTextSettings = { + selectedColumn: [], + textWrap: false, + ...data.option?.wrapTextSettings, + }; + + const colorRules: ColorRule[] = data.option?.colorByValue || []; + + const getRowHeight = (params: any) => { + if (data.option?.rowSpanning) { + return 50; + } + return "auto"; + }; + + const GridToolbar = () => { + return ( + + + {titleSettings.chartTitle} + + + ); + }; + + return ( + +
+ +
+ setContextMenu(null)} + /> +
+ ); }); diff --git a/libs/renderer/src/components/block-defaults/grid-block/GridBlockContextMenu.tsx b/libs/renderer/src/components/block-defaults/grid-block/GridBlockContextMenu.tsx index 9548ea7ba3..3b77292709 100644 --- a/libs/renderer/src/components/block-defaults/grid-block/GridBlockContextMenu.tsx +++ b/libs/renderer/src/components/block-defaults/grid-block/GridBlockContextMenu.tsx @@ -1,86 +1,84 @@ -import { observer } from "mobx-react-lite"; import { Menu, MenuItem } from "@mui/material"; - -import { useBlock, useFrame } from "../../../hooks"; - -import { GridBlockColumn } from "./grid-block.types"; -import { GridBlockDef } from "./GridBlock"; +import { observer } from "mobx-react-lite"; +import { useBlock, type useFrame } from "../../../hooks"; +import type { GridBlockDef } from "./GridBlock"; +import type { GridBlockColumn } from "./grid-block.types"; export interface GridBlockContextMenuProps { - /** ID of the block */ - id: string; + /** ID of the block */ + id: string; - /** Frame that the user is interacting with */ - frame: ReturnType; + /** Frame that the user is interacting with */ + frame: ReturnType; - /** Context Menu */ - contextMenu: { - mouseX: number; - mouseY: number; - column: GridBlockColumn; - value: unknown; - } | null; + /** Context Menu */ + contextMenu: { + mouseX: number; + mouseY: number; + column: GridBlockColumn; + value: unknown; + } | null; - /** Close the context menu */ - onClose: () => void; + /** Close the context menu */ + onClose: () => void; } export const GridBlockContextMenu: React.FC = - observer( - ({ - id = "", - frame = null, - contextMenu = null, - onClose = () => null, - }) => { - const { data } = useBlock(id); + observer( + ({ + id = "", + frame = null, + contextMenu = null, + onClose = () => null, + }) => { + const { data } = useBlock(id); - return ( - onClose()} - anchorReference="anchorPosition" - anchorPosition={ - contextMenu !== null - ? { - top: contextMenu.mouseY, - left: contextMenu.mouseX, - } - : undefined - } - > - {contextMenu && !data.contextMenu?.hideUnfilter ? ( - { - frame.unfilter(); - onClose(); - }} - > - Unfilter - - ) : null} - {contextMenu && !data.contextMenu?.hideFilter ? ( - { - frame.filter( - `SetFrameFilter(${ - contextMenu.column.selector - }==${JSON.stringify(contextMenu.value)})`, - ); - onClose(); - }} - > - Filter {contextMenu.column.name} == - {typeof contextMenu.value === "string" - ? contextMenu.value - : JSON.stringify(contextMenu.value)} - - ) : null} - - ); - }, - ); + return ( + onClose()} + anchorReference="anchorPosition" + anchorPosition={ + contextMenu !== null + ? { + top: contextMenu.mouseY, + left: contextMenu.mouseX, + } + : undefined + } + > + {contextMenu && !data.contextMenu?.hideUnfilter ? ( + { + frame.unfilter(); + onClose(); + }} + > + Unfilter + + ) : null} + {contextMenu && !data.contextMenu?.hideFilter ? ( + { + frame.filter( + `SetFrameFilter(${ + contextMenu.column.selector + }==${JSON.stringify(contextMenu.value)})`, + ); + onClose(); + }} + > + Filter {contextMenu.column.name} == + {typeof contextMenu.value === "string" + ? contextMenu.value + : JSON.stringify(contextMenu.value)} + + ) : null} + + ); + }, + ); diff --git a/libs/renderer/src/components/block-defaults/grid-block/config.tsx b/libs/renderer/src/components/block-defaults/grid-block/config.tsx index 88adff9228..08f82d00c2 100644 --- a/libs/renderer/src/components/block-defaults/grid-block/config.tsx +++ b/libs/renderer/src/components/block-defaults/grid-block/config.tsx @@ -1,38 +1,38 @@ -import { BlockConfig } from "../../../store"; +import type { BlockConfig } from "../../../store"; import { BLOCK_TYPE_DATA } from "../block-defaults.constants"; -import { GridBlockDef, GridBlock } from "./GridBlock"; +import { GridBlock, type GridBlockDef } from "./GridBlock"; // export the config for the block export const config: BlockConfig = { - widget: "grid", - type: BLOCK_TYPE_DATA, - data: { - frame: { - name: "", - }, - option: {}, - columns: [], - variation: "grid-block", - style: { - display: "flex", - flexDirection: "row", - padding: "", - gap: "", - flexWrap: "wrap", - width: "450px", - height: "350px", - }, - view: { - pagination: true, - }, - contextMenu: { - hideFilter: false, - hideUnfilter: false, - }, - show: true, - }, + widget: "grid", + type: BLOCK_TYPE_DATA, + data: { + frame: { + name: "", + }, + option: {}, + columns: [], + variation: "grid-block", + style: { + display: "flex", + flexDirection: "row", + padding: "", + gap: "", + flexWrap: "wrap", + width: "450px", + height: "350px", + }, + view: { + pagination: true, + }, + contextMenu: { + hideFilter: false, + hideUnfilter: false, + }, + show: true, + }, - listeners: {}, - slots: {}, - render: GridBlock, + listeners: {}, + slots: {}, + render: GridBlock, }; diff --git a/libs/renderer/src/components/block-defaults/grid-block/grid-block.types.ts b/libs/renderer/src/components/block-defaults/grid-block/grid-block.types.ts index 4baad888e6..b3ab9a1e27 100644 --- a/libs/renderer/src/components/block-defaults/grid-block/grid-block.types.ts +++ b/libs/renderer/src/components/block-defaults/grid-block/grid-block.types.ts @@ -1,11 +1,11 @@ /** Column Definition */ export type GridBlockColumn = { - /** Name of the column */ - name: string; + /** Name of the column */ + name: string; - /** Selector for the column */ - selector: string; + /** Selector for the column */ + selector: string; - /** Width of the column */ - width: string; + /** Width of the column */ + width: string; }; diff --git a/libs/renderer/src/components/block-defaults/grid-block/index.ts b/libs/renderer/src/components/block-defaults/grid-block/index.ts index f092efa4a8..d5faa8a7b6 100644 --- a/libs/renderer/src/components/block-defaults/grid-block/index.ts +++ b/libs/renderer/src/components/block-defaults/grid-block/index.ts @@ -1,3 +1,3 @@ -export * from "./grid-block.types"; export * from "./config"; export * from "./GridBlock"; +export * from "./grid-block.types"; diff --git a/libs/renderer/src/components/block-defaults/grid-dynamic-frame-block/GridDynamicFrameBlock.tsx b/libs/renderer/src/components/block-defaults/grid-dynamic-frame-block/GridDynamicFrameBlock.tsx index 8caa5cb0e8..f1083a2b93 100644 --- a/libs/renderer/src/components/block-defaults/grid-dynamic-frame-block/GridDynamicFrameBlock.tsx +++ b/libs/renderer/src/components/block-defaults/grid-dynamic-frame-block/GridDynamicFrameBlock.tsx @@ -1,251 +1,250 @@ -import { observer } from "mobx-react-lite"; import { styled } from "@mui/material"; -import { useState, useEffect, CSSProperties } from "react"; import { DataGrid } from "@mui/x-data-grid"; - +import { observer } from "mobx-react-lite"; +import { type CSSProperties, useEffect, useState } from "react"; import { useBlock, useFrame, useFrameHeaders } from "../../../hooks"; -import { BlockComponent, BlockDef } from "../../../store"; +import type { BlockComponent, BlockDef } from "../../../store"; import { GridBlockContextMenu } from "../grid-block/GridBlockContextMenu"; -import { GridBlockColumn } from "../grid-block/grid-block.types"; +import type { GridBlockColumn } from "../grid-block/grid-block.types"; const DEFAULT_HEIGHT = "300px"; const DEFAULT_WIDTH = "500px"; const StyledBlock = styled("div")(() => ({ - display: "flex", - flexDirection: "column", - height: DEFAULT_HEIGHT, - width: DEFAULT_WIDTH, + display: "flex", + flexDirection: "column", + height: DEFAULT_HEIGHT, + width: DEFAULT_WIDTH, })); const StyledHeader = styled("div")(() => ({ - padding: "8px", + padding: "8px", })); const StyledRow = styled("div")(() => ({ - padding: "8px", + padding: "8px", })); export interface GridDynamicFrameBlockDef - extends BlockDef<"grid-dynamic-frame"> { - widget: "grid-dynamic-frame"; - - /** data associated with the block */ - data: { - /** Bind the grid to a frame */ - frame: { - name: string; - }; - - /** Column Definitions */ - columns: GridBlockColumn[]; - - /** Context Menu */ - contextMenu?: { - /** Show the unfilter related options */ - hideUnfilter: boolean; - - /** Show the filter related options */ - hideFilter: boolean; - }; - - view?: { - //TODO: Include limit + offset? - - /** Enable the pagination */ - pagination: boolean; - }; - - /** - * Hide or show block - */ - show: boolean; - - /** - * width and height - */ - style: CSSProperties; - }; + extends BlockDef<"grid-dynamic-frame"> { + widget: "grid-dynamic-frame"; + + /** data associated with the block */ + data: { + /** Bind the grid to a frame */ + frame: { + name: string; + }; + + /** Column Definitions */ + columns: GridBlockColumn[]; + + /** Context Menu */ + contextMenu?: { + /** Show the unfilter related options */ + hideUnfilter: boolean; + + /** Show the filter related options */ + hideFilter: boolean; + }; + + view?: { + //TODO: Include limit + offset? + + /** Enable the pagination */ + pagination: boolean; + }; + + /** + * Hide or show block + */ + show: boolean; + + /** + * width and height + */ + style: CSSProperties; + }; } export const GridDynamicFrameBlock: BlockComponent = observer(({ id }) => { - const { attrs, data, setData } = useBlock(id); - const [paginationModel, setPaginationModel] = useState({ - page: 0, - pageSize: 50, - }); - - const [contextMenu, setContextMenu] = useState<{ - mouseX: number; - mouseY: number; - column: GridBlockColumn; - value: unknown; - } | null>(null); - - // create the selector - const selector = `Select(${data.columns - .map((c) => { - return c.selector; - }) - .join(", ")}).as([${data.columns - .map((c) => { - return c.name; - }) - .join(", ")}])`; - - // get the frame - const frame = useFrame(data.frame.name, { - selector: selector, - offset: paginationModel.page * paginationModel.pageSize, - limit: paginationModel.pageSize, - enableCount: true, - }); - - // When headers come from user upload - const frameHeaders = useFrameHeaders(data.frame.name); - - /** - * Anytime our Frame Headers, we need to sync our column block data with our source of truth ^ - */ - useEffect(() => { - if (data.columns.length === 0 && !frameHeaders.isLoading) { - // If no columns are defined, fetch the frame headers - if (frameHeaders.data.list.length > 0) { - syncBlockDataColumns(frameHeaders); - } - } - }, [frameHeaders.data.list]); - - /** - * Updates data.columns - * @param synData - */ - const syncBlockDataColumns = (cols) => { - const columns: GridBlockColumn[] = cols.data.list.map((h) => { - return { - name: h.alias, - width: undefined, - selector: h.header, - }; - }); - // update the data - setData("columns", columns); - }; - - /** - * Handle the callback for the context menu - * @param event - triggered event - * @param column - selected column - * @param row - value - */ - const handleTableCellOnContextMenu = ( - event: React.MouseEvent, - column: GridBlockColumn, - value: unknown, - ) => { - // prevent the default interaction - event.preventDefault(); - - // open the menu and save the data - setContextMenu( - contextMenu === null - ? { - mouseX: event.clientX + 2, - mouseY: event.clientY - 6, - column: column, - value: value, - } - : // repeated contextmenu when it is already open closes it with Chrome 84 on Ubuntu - // Other native context menus might behave different. - // With this behavior we prevent contextmenu from the backdrop to re-locale existing context menus. - null, - ); - }; - - const columns = data.columns.map((col) => ({ - field: col.name, - headerName: col.name, - sortable: false, - renderHeader: () => {col.name}, - renderCell: (params) => { - return ( - - handleTableCellOnContextMenu(e, col, params.value) - } - > - {params.value} - - ); - }, - })); - - const rows = frame.data.values.map((r, idx) => { - const obj: Record = { id: idx }; - columns.forEach((c, cIdx) => { - obj[c.field] = r[cIdx]; - }); - return obj; - }); - - const handlePaginationModalChange = (newmodel) => { - // if the page size has changed reset the page - if (newmodel.pageSize !== paginationModel.pageSize) { - setPaginationModel({ - page: 0, - pageSize: newmodel.pageSize, - }); - } else { - setPaginationModel(newmodel); - } - }; - - return ( - -
- -
- setContextMenu(null)} - /> -
- ); + const { attrs, data, setData } = useBlock(id); + const [paginationModel, setPaginationModel] = useState({ + page: 0, + pageSize: 50, + }); + + const [contextMenu, setContextMenu] = useState<{ + mouseX: number; + mouseY: number; + column: GridBlockColumn; + value: unknown; + } | null>(null); + + // create the selector + const selector = `Select(${data.columns + .map((c) => { + return c.selector; + }) + .join(", ")}).as([${data.columns + .map((c) => { + return c.name; + }) + .join(", ")}])`; + + // get the frame + const frame = useFrame(data.frame.name, { + selector: selector, + offset: paginationModel.page * paginationModel.pageSize, + limit: paginationModel.pageSize, + enableCount: true, + }); + + // When headers come from user upload + const frameHeaders = useFrameHeaders(data.frame.name); + + /** + * Anytime our Frame Headers, we need to sync our column block data with our source of truth ^ + */ + useEffect(() => { + if (data.columns.length === 0 && !frameHeaders.isLoading) { + // If no columns are defined, fetch the frame headers + if (frameHeaders.data.list.length > 0) { + syncBlockDataColumns(frameHeaders); + } + } + }, [frameHeaders.data.list]); + + /** + * Updates data.columns + * @param synData + */ + const syncBlockDataColumns = (cols) => { + const columns: GridBlockColumn[] = cols.data.list.map((h) => { + return { + name: h.alias, + width: undefined, + selector: h.header, + }; + }); + // update the data + setData("columns", columns); + }; + + /** + * Handle the callback for the context menu + * @param event - triggered event + * @param column - selected column + * @param row - value + */ + const handleTableCellOnContextMenu = ( + event: React.MouseEvent, + column: GridBlockColumn, + value: unknown, + ) => { + // prevent the default interaction + event.preventDefault(); + + // open the menu and save the data + setContextMenu( + contextMenu === null + ? { + mouseX: event.clientX + 2, + mouseY: event.clientY - 6, + column: column, + value: value, + } + : // repeated contextmenu when it is already open closes it with Chrome 84 on Ubuntu + // Other native context menus might behave different. + // With this behavior we prevent contextmenu from the backdrop to re-locale existing context menus. + null, + ); + }; + + const columns = data.columns.map((col) => ({ + field: col.name, + headerName: col.name, + sortable: false, + renderHeader: () => {col.name}, + renderCell: (params) => { + return ( + + handleTableCellOnContextMenu(e, col, params.value) + } + > + {params.value} + + ); + }, + })); + + const rows = frame.data.values.map((r, idx) => { + const obj: Record = { id: idx }; + columns.forEach((c, cIdx) => { + obj[c.field] = r[cIdx]; + }); + return obj; + }); + + const handlePaginationModalChange = (newmodel) => { + // if the page size has changed reset the page + if (newmodel.pageSize !== paginationModel.pageSize) { + setPaginationModel({ + page: 0, + pageSize: newmodel.pageSize, + }); + } else { + setPaginationModel(newmodel); + } + }; + + return ( + +
+ +
+ setContextMenu(null)} + /> +
+ ); }); diff --git a/libs/renderer/src/components/block-defaults/grid-dynamic-frame-block/config.tsx b/libs/renderer/src/components/block-defaults/grid-dynamic-frame-block/config.tsx index b46cffc97f..d96d91d971 100644 --- a/libs/renderer/src/components/block-defaults/grid-dynamic-frame-block/config.tsx +++ b/libs/renderer/src/components/block-defaults/grid-dynamic-frame-block/config.tsx @@ -1,39 +1,39 @@ +import type { BlockConfig } from "../../../store"; import { BLOCK_TYPE_DATA } from "../block-defaults.constants"; -import { BlockConfig } from "../../../store"; import { - GridDynamicFrameBlockDef, - GridDynamicFrameBlock, + GridDynamicFrameBlock, + type GridDynamicFrameBlockDef, } from "./GridDynamicFrameBlock"; // export the config for the block export const config: BlockConfig = { - widget: "grid-dynamic-frame", - type: BLOCK_TYPE_DATA, - data: { - frame: { - name: "", - }, - columns: [], - style: { - display: "flex", - flexDirection: "row", - padding: "", - gap: "", - flexWrap: "wrap", - width: "450px", - height: "350px", - }, - view: { - pagination: true, - }, - contextMenu: { - hideFilter: false, - hideUnfilter: false, - }, - show: true, - }, + widget: "grid-dynamic-frame", + type: BLOCK_TYPE_DATA, + data: { + frame: { + name: "", + }, + columns: [], + style: { + display: "flex", + flexDirection: "row", + padding: "", + gap: "", + flexWrap: "wrap", + width: "450px", + height: "350px", + }, + view: { + pagination: true, + }, + contextMenu: { + hideFilter: false, + hideUnfilter: false, + }, + show: true, + }, - listeners: {}, - slots: {}, - render: GridDynamicFrameBlock, + listeners: {}, + slots: {}, + render: GridDynamicFrameBlock, }; diff --git a/libs/renderer/src/components/block-defaults/html-block/HTMLBlock.tsx b/libs/renderer/src/components/block-defaults/html-block/HTMLBlock.tsx index 3af8475671..a75ee16225 100644 --- a/libs/renderer/src/components/block-defaults/html-block/HTMLBlock.tsx +++ b/libs/renderer/src/components/block-defaults/html-block/HTMLBlock.tsx @@ -1,52 +1,52 @@ -import { useEffect, useRef } from "react"; +import DOMPurify from "dompurify"; import { observer } from "mobx-react-lite"; -import { useBlock } from "../../../hooks"; -import { BlockDef, BlockComponent } from "../../../store"; +import { useEffect, useRef } from "react"; import { styled } from "@semoss/ui"; -import DOMPurify from "dompurify"; +import { useBlock } from "../../../hooks"; +import type { BlockComponent, BlockDef } from "../../../store"; export interface HTMLBlockDef extends BlockDef<"html"> { - widget: "html"; - data: { - html: string; - }; - slots: never; + widget: "html"; + data: { + html: string; + }; + slots: never; } export const HTMLBlock: BlockComponent = observer(({ id }) => { - const { attrs, data } = useBlock(id); - const shadowRef = useRef(null); + const { attrs, data } = useBlock(id); + const shadowRef = useRef(null); - useEffect(() => { - if (!data.html) { - return; - } + useEffect(() => { + if (!data.html) { + return; + } - const html = DOMPurify.sanitize(data.html); + const html = DOMPurify.sanitize(data.html); - let shadowRoot = shadowRef.current.shadowRoot; + let shadowRoot = shadowRef.current.shadowRoot; - // attach a shadow root if it doesn't exist - if (!shadowRoot) { - shadowRoot = shadowRef.current.attachShadow({ - mode: "open", - }); - } + // attach a shadow root if it doesn't exist + if (!shadowRoot) { + shadowRoot = shadowRef.current.attachShadow({ + mode: "open", + }); + } - /// add the html - shadowRoot.innerHTML = ` + /// add the html + shadowRoot.innerHTML = ` ${html} `; - }, [data.html]); - - if (!data.html) { - return null; - } - - return ( -
- ); + }, [data.html]); + + if (!data.html) { + return null; + } + + return ( +
+ ); }); diff --git a/libs/renderer/src/components/block-defaults/html-block/config.tsx b/libs/renderer/src/components/block-defaults/html-block/config.tsx index f078527c25..60f2ada1ef 100644 --- a/libs/renderer/src/components/block-defaults/html-block/config.tsx +++ b/libs/renderer/src/components/block-defaults/html-block/config.tsx @@ -1,15 +1,15 @@ -import { BlockConfig } from "../../../store"; -import { HTMLBlockDef, HTMLBlock } from "./HTMLBlock"; +import type { BlockConfig } from "../../../store"; import { BLOCK_TYPE_DISPLAY } from "../block-defaults.constants"; +import { HTMLBlock, type HTMLBlockDef } from "./HTMLBlock"; // export the config for the block export const config: BlockConfig = { - widget: "html", - type: BLOCK_TYPE_DISPLAY, - data: { - html: "", - }, - listeners: {}, - slots: {}, - render: HTMLBlock, + widget: "html", + type: BLOCK_TYPE_DISPLAY, + data: { + html: "", + }, + listeners: {}, + slots: {}, + render: HTMLBlock, }; diff --git a/libs/renderer/src/components/block-defaults/icon-block/IconBlock.tsx b/libs/renderer/src/components/block-defaults/icon-block/IconBlock.tsx index e3f7176461..9129a867b8 100644 --- a/libs/renderer/src/components/block-defaults/icon-block/IconBlock.tsx +++ b/libs/renderer/src/components/block-defaults/icon-block/IconBlock.tsx @@ -1,70 +1,70 @@ -import { CSSProperties, useState } from "react"; +import { Badge } from "@mui/material"; import { observer } from "mobx-react-lite"; -import { useBlock } from "../../../hooks"; -import { BlockDef, BlockComponent } from "../../../store"; +import { type CSSProperties, useState } from "react"; import { iconMap } from "../../../constants"; -import { Badge } from "@mui/material"; +import { useBlock } from "../../../hooks"; +import type { BlockComponent, BlockDef } from "../../../store"; export interface IconBlockDef extends BlockDef<"icon"> { - widget: "icon"; - data: { - icon: string; - style: CSSProperties; - src: string; - title: string; - show: string; - badgeContent: number; - color: - | "primary" - | "default" - | "secondary" - | "error" - | "info" - | "success" - | "warning"; - showBadge: boolean; - }; - slots: never; + widget: "icon"; + data: { + icon: string; + style: CSSProperties; + src: string; + title: string; + show: string; + badgeContent: number; + color: + | "primary" + | "default" + | "secondary" + | "error" + | "info" + | "success" + | "warning"; + showBadge: boolean; + }; + slots: never; } export const IconBlock: BlockComponent = observer(({ id }) => { - const { attrs, data } = useBlock(id); + const { attrs, data } = useBlock(id); - const displayIcon = (key: string) => { - const Icon = iconMap[key] || iconMap["Icon"]; - const color = data.style.color || "primary"; - const width = data.style.width ?? null; - const maxWidth = data.style.maxWidth ?? null; - const height = data.style.height ?? null; - const maxHeight = data.style.maxHeight ?? null; - const iconElement = ( - - ); + const displayIcon = (key: string) => { + const Icon = iconMap[key] || iconMap["Icon"]; + const color = data.style.color || "primary"; + const width = data.style.width ?? null; + const maxWidth = data.style.maxWidth ?? null; + const height = data.style.height ?? null; + const maxHeight = data.style.maxHeight ?? null; + const iconElement = ( + + ); - if (data.showBadge && data.badgeContent > 0) { - return ( - - {iconElement} - - ); - } + if (data.showBadge && data.badgeContent > 0) { + return ( + + {iconElement} + + ); + } - return iconElement; - }; + return iconElement; + }; - return ( -
- {displayIcon(data.icon)} -
- ); + return ( +
+ {displayIcon(data.icon)} +
+ ); }); diff --git a/libs/renderer/src/components/block-defaults/icon-block/config.tsx b/libs/renderer/src/components/block-defaults/icon-block/config.tsx index 7a8eb90a28..9f106dca2f 100644 --- a/libs/renderer/src/components/block-defaults/icon-block/config.tsx +++ b/libs/renderer/src/components/block-defaults/icon-block/config.tsx @@ -1,28 +1,28 @@ -import { BlockConfig } from "../../../store"; +import type { BlockConfig } from "../../../store"; import { BLOCK_TYPE_DISPLAY } from "../block-defaults.constants"; -import { IconBlockDef, IconBlock } from "./IconBlock"; +import { IconBlock, type IconBlockDef } from "./IconBlock"; export const config: BlockConfig = { - widget: "icon", - type: BLOCK_TYPE_DISPLAY, - data: { - style: { - display: "flex", - justifyContent: "center", - alignItems: "center", - width: "100%", - height: "200px", - color: "black", - }, - icon: "Home", - src: "", - title: "", - show: "true", - badgeContent: 0, - color: "default", - showBadge: false, - }, - listeners: {}, - slots: {}, - render: IconBlock, + widget: "icon", + type: BLOCK_TYPE_DISPLAY, + data: { + style: { + display: "flex", + justifyContent: "center", + alignItems: "center", + width: "100%", + height: "200px", + color: "black", + }, + icon: "Home", + src: "", + title: "", + show: "true", + badgeContent: 0, + color: "default", + showBadge: false, + }, + listeners: {}, + slots: {}, + render: IconBlock, }; diff --git a/libs/renderer/src/components/block-defaults/iframe-block/IframeBlock.tsx b/libs/renderer/src/components/block-defaults/iframe-block/IframeBlock.tsx index e5866bfd06..1301d6cbc5 100644 --- a/libs/renderer/src/components/block-defaults/iframe-block/IframeBlock.tsx +++ b/libs/renderer/src/components/block-defaults/iframe-block/IframeBlock.tsx @@ -1,58 +1,57 @@ -import { CSSProperties, useEffect } from "react"; import { observer } from "mobx-react-lite"; - +import { type CSSProperties, useEffect } from "react"; import { useBlock } from "../../../hooks"; -import { BlockDef, BlockComponent, ListenerActions } from "../../../store"; +import type { BlockComponent, BlockDef, ListenerActions } from "../../../store"; export interface IframeBlockDef extends BlockDef<"iframe"> { - widget: "iframe"; - data: { - style: CSSProperties; - src: string; - title: string; - enableFrameInteractions: boolean; - show: string; - }; - slots: never; - listeners: { - preProcess: { - type: "sync" | "async"; - order: ListenerActions[]; - }; - }; + widget: "iframe"; + data: { + style: CSSProperties; + src: string; + title: string; + enableFrameInteractions: boolean; + show: string; + }; + slots: never; + listeners: { + preProcess: { + type: "sync" | "async"; + order: ListenerActions[]; + }; + }; } export const IframeBlock: BlockComponent = observer(({ id }) => { - const { attrs, data, listeners } = useBlock(id); + const { attrs, data, listeners } = useBlock(id); - useEffect(() => { - if (listeners.preProcess) { - listeners.preProcess(); - } - }, []); + useEffect(() => { + if (listeners.preProcess) { + listeners.preProcess(); + } + }, []); - return ( - - `; + // create the url + iframe + const base = window.location.href.replace(window.location.hash, "#"); + const path = resolvePath(`./s/${appId}`, base); + const url = path.pathname; + const iframe = ``; - /** - * Copy the content to the clipboard - * @param content - content that will be copied - */ - const copy = (content: string) => { - try { - navigator.clipboard.writeText(content); + /** + * Copy the content to the clipboard + * @param content - content that will be copied + */ + const copy = (content: string) => { + try { + navigator.clipboard.writeText(content); - notification.add({ - color: 'success', - message: 'Succesfully copied to clipboard', - }); - setIsCopied(true); - } catch (e) { - notification.add({ - color: 'error', - message: e.message, - }); - } - }; + notification.add({ + color: "success", + message: "Succesfully copied to clipboard", + }); + setIsCopied(true); + } catch (e) { + notification.add({ + color: "error", + message: e.message, + }); + } + }; - return ( - <> - - - Share - - - - - - - {diffs && ( - }> - Save app prior to sharing to reflect the latest changes - - )} - - { - setShareModalTab(value); - }} - > - - - - {shareModalTab === 0 && ( - - - - - )} - {shareModalTab === 1 && ( - - - Embed the app as an iframe - - - - - - - )} - - - - ); + return ( + <> + + + Share + + + + + + + {diffs && ( + }> + Save app prior to sharing to reflect the latest changes + + )} + + { + setShareModalTab(value); + }} + > + + + + {shareModalTab === 0 && ( + + + + + )} + {shareModalTab === 1 && ( + + + Embed the app as an iframe + + + + + + + )} + + + + ); }); diff --git a/packages/client/src/components/ui/Share/index.ts b/packages/client/src/components/ui/Share/index.ts index 1023112e46..f173a1dc1b 100644 --- a/packages/client/src/components/ui/Share/index.ts +++ b/packages/client/src/components/ui/Share/index.ts @@ -1 +1 @@ -export * from './ShareOverlay'; +export * from "./ShareOverlay"; diff --git a/packages/client/src/components/ui/index.ts b/packages/client/src/components/ui/index.ts index ac8438b2ec..c491ee6d39 100644 --- a/packages/client/src/components/ui/index.ts +++ b/packages/client/src/components/ui/index.ts @@ -1,4 +1,4 @@ -export * from './Filterbox'; -export * from './LoadingScreen'; -export * from './Section'; -export * from './Share'; +export * from "./Filterbox"; +export * from "./LoadingScreen"; +export * from "./Section"; +export * from "./Share"; diff --git a/packages/client/src/components/workspace/PreviewOverlay.tsx b/packages/client/src/components/workspace/PreviewOverlay.tsx index 573f4a0654..ce76f761b6 100644 --- a/packages/client/src/components/workspace/PreviewOverlay.tsx +++ b/packages/client/src/components/workspace/PreviewOverlay.tsx @@ -1,42 +1,41 @@ -import { observer } from 'mobx-react-lite'; -import { Button, Modal, styled } from '@semoss/ui'; +import { observer } from "mobx-react-lite"; +import { Renderer, type SerializedState } from "@semoss/renderer"; +import { Button, Modal, styled } from "@semoss/ui"; -import { Renderer, SerializedState } from '@semoss/renderer'; - -const StyledContainer = styled('div')(({ theme }) => ({ - height: '60vh', - width: '100%', - border: `1px solid ${theme.palette.divider}`, +const StyledContainer = styled("div")(({ theme }) => ({ + height: "60vh", + width: "100%", + border: `1px solid ${theme.palette.divider}`, })); interface PreviewOverlayProps { - /** State to load in the preview */ - state: SerializedState; + /** State to load in the preview */ + state: SerializedState; - /** Method called to close overlay */ - onClose: () => void; + /** Method called to close overlay */ + onClose: () => void; } export const PreviewOverlay = observer((props: PreviewOverlayProps) => { - const { state, onClose = () => null } = props; + const { state, onClose = () => null } = props; - return ( - <> - Preview - - - - - - - - - - ); + return ( + <> + Preview + + + + + + + + + + ); }); diff --git a/packages/client/src/components/workspace/Workspace.tsx b/packages/client/src/components/workspace/Workspace.tsx index 1158502f8f..52b13a7850 100644 --- a/packages/client/src/components/workspace/Workspace.tsx +++ b/packages/client/src/components/workspace/Workspace.tsx @@ -1,8 +1,9 @@ import { RestartAlt } from "@mui/icons-material"; import { observer } from "mobx-react-lite"; -import React, { useEffect, useRef } from "react"; +import type React from "react"; +import { useEffect, useRef } from "react"; import { Link } from "react-router-dom"; - +import { Actions, DockLocation, Layout, TabNode } from "@semoss/shared"; import { Breadcrumbs, IconButton, @@ -11,18 +12,16 @@ import { Tooltip, Typography, } from "@semoss/ui"; -import { Actions, DockLocation, Layout, TabNode } from "@semoss/shared"; - import { ClosePage } from "@/assets/img/ClosePage"; import SEMOSS_BLACK_LOGO from "@/assets/img/SEMOSS_BLACK_LOGO.png"; import { WorkspaceContext } from "@/contexts"; import { SIDEBAR_MENU } from "@/pages/import/import.constants"; -import { WorkspaceOptions, WorkspaceStore } from "@/stores"; +import type { WorkspaceOptions, WorkspaceStore } from "@/stores"; import { NavbarHeader, NavbarLeft, NavbarRight } from "../shared"; import { WorkspaceLoading } from "./WorkspaceLoading"; import { WorkspaceOverlay } from "./WorkspaceOverlay"; -type LayoutType = React.ElementRef +type LayoutType = React.ElementRef; const StyledMain = styled("div")(() => ({ position: "relative", diff --git a/packages/client/src/components/workspace/WorkspaceLoading.tsx b/packages/client/src/components/workspace/WorkspaceLoading.tsx index 5d174a1d66..64d8783838 100644 --- a/packages/client/src/components/workspace/WorkspaceLoading.tsx +++ b/packages/client/src/components/workspace/WorkspaceLoading.tsx @@ -1,17 +1,16 @@ -import { observer } from 'mobx-react-lite'; - -import { useWorkspace } from '@/hooks'; -import { LoadingScreen } from '@/components/ui'; +import { observer } from "mobx-react-lite"; +import { LoadingScreen } from "@/components/ui"; +import { useWorkspace } from "@/hooks"; /** * WorkspaceLoading show the loading screen */ export const WorkspaceLoading = observer((): JSX.Element => { - const { workspace } = useWorkspace(); + const { workspace } = useWorkspace(); - if (workspace.isLoading) { - return ; - } + if (workspace.isLoading) { + return ; + } - return null; + return null; }); diff --git a/packages/client/src/components/workspace/WorkspaceOverlay.tsx b/packages/client/src/components/workspace/WorkspaceOverlay.tsx index c755ba1442..0a8706b676 100644 --- a/packages/client/src/components/workspace/WorkspaceOverlay.tsx +++ b/packages/client/src/components/workspace/WorkspaceOverlay.tsx @@ -1,24 +1,23 @@ -import { observer } from 'mobx-react-lite'; -import { Modal } from '@semoss/ui'; - -import { useWorkspace } from '@/hooks'; +import { observer } from "mobx-react-lite"; +import { Modal } from "@semoss/ui"; +import { useWorkspace } from "@/hooks"; /** * WorkspaceOverlay can update the overlay in the workspace */ export const WorkspaceOverlay = observer((): JSX.Element => { - const { workspace } = useWorkspace(); + const { workspace } = useWorkspace(); - return ( - { - workspace.closeOverlay(); - }} - > - {workspace.overlay.content ? workspace.overlay.content() : null} - - ); + return ( + { + workspace.closeOverlay(); + }} + > + {workspace.overlay.content ? workspace.overlay.content() : null} + + ); }); diff --git a/packages/client/src/components/workspace/index.ts b/packages/client/src/components/workspace/index.ts index 39ab2c3093..b04691e94f 100644 --- a/packages/client/src/components/workspace/index.ts +++ b/packages/client/src/components/workspace/index.ts @@ -1,4 +1,3 @@ -export * from './Workspace'; - -export * from './panels'; -export * from './PreviewOverlay'; +export * from "./PreviewOverlay"; +export * from "./panels"; +export * from "./Workspace"; diff --git a/packages/client/src/components/workspace/panels/EmptyFilePanel.tsx b/packages/client/src/components/workspace/panels/EmptyFilePanel.tsx index cfd6a529af..08c91dfe4e 100644 --- a/packages/client/src/components/workspace/panels/EmptyFilePanel.tsx +++ b/packages/client/src/components/workspace/panels/EmptyFilePanel.tsx @@ -1,64 +1,63 @@ -import { TextEditorCodeGeneration } from '../../common'; -import { Link } from 'react-router-dom'; - -import { Typography, Container, styled } from '@semoss/ui'; +import { Link } from "react-router-dom"; +import { Container, styled, Typography } from "@semoss/ui"; +import { TextEditorCodeGeneration } from "../../common"; const StyledHeaderContainer = styled(Container)(({ theme }) => ({ - gap: theme.spacing(2), - flexDirection: 'column', - display: 'flex', + gap: theme.spacing(2), + flexDirection: "column", + display: "flex", })); -const StyledEmptyFiles = styled('div')(({ theme }) => ({ - padding: theme.spacing(5), - justifyContent: 'space-around', - alignItems: 'normal', - textAlign: 'left', - flexDirection: 'column', - display: 'flex', - height: '100%', - width: '100%', +const StyledEmptyFiles = styled("div")(({ theme }) => ({ + padding: theme.spacing(5), + justifyContent: "space-around", + alignItems: "normal", + textAlign: "left", + flexDirection: "column", + display: "flex", + height: "100%", + width: "100%", })); const StyledTypography = styled(Typography)(({ theme }) => ({ - textAlign: 'left', - display: 'block', + textAlign: "left", + display: "block", })); -const StyledContainer = styled('div')(({ theme }) => ({ - height: '100%', - width: '100%', +const StyledContainer = styled("div")(({ theme }) => ({ + height: "100%", + width: "100%", })); export const EmptyFilePanel = () => { - return ( - - - -
- - Welcome to the Code Editor - - - Get started by selecting a file{' '} - {import.meta.env.DEV && 'or'} - -
- {import.meta.env.DEV && ( -
- -
- )} -
- - Github Documentation -
    -
  • - Code Editor -
  • -
-
-
-
- ); + return ( + + + +
+ + Welcome to the Code Editor + + + Get started by selecting a file{" "} + {import.meta.env.DEV && "or"} + +
+ {import.meta.env.DEV && ( +
+ +
+ )} +
+ + Github Documentation +
    +
  • + Code Editor +
  • +
+
+
+
+ ); }; diff --git a/packages/client/src/components/workspace/panels/FileEditorPanel.tsx b/packages/client/src/components/workspace/panels/FileEditorPanel.tsx index 8d2e074abe..2058e15583 100644 --- a/packages/client/src/components/workspace/panels/FileEditorPanel.tsx +++ b/packages/client/src/components/workspace/panels/FileEditorPanel.tsx @@ -1,158 +1,157 @@ -import { observer } from 'mobx-react-lite'; -import { Actions, TabNode } from 'flexlayout-react'; -import { IconButton, Stack, useNotification } from '@semoss/ui'; - -import { useWorkspace } from '@/hooks'; -import { FileEditor, FileEditorRefDef } from '@/components/common'; -import { Panel } from './Panel'; -import { useRef, useState } from 'react'; -import { ContentCopyOutlined, SaveOutlined } from '@mui/icons-material'; +import { ContentCopyOutlined, SaveOutlined } from "@mui/icons-material"; +import { Actions, TabNode } from "flexlayout-react"; +import { observer } from "mobx-react-lite"; +import { useRef, useState } from "react"; +import { IconButton, Stack, useNotification } from "@semoss/ui"; +import { FileEditor, type FileEditorRefDef } from "@/components/common"; +import { useWorkspace } from "@/hooks"; +import { Panel } from "./Panel"; interface FileEditorPanelProps { - /** Path to the file location */ - path: string; + /** Path to the file location */ + path: string; } export const FileEditorPanel = observer((props: FileEditorPanelProps) => { - const { path } = props; - const { workspace } = useWorkspace(); - const notification = useNotification(); - - const [isModified, setIsModified] = useState(false); - - const fileEditorRef = useRef(null); - - // get the name - const name = path.split('/').pop(); - - /** - * Triggered when a file is changed - * @param isModified - isModified - */ - const onFileEditorChange = (isModified: boolean) => { - try { - // update - setIsModified(isModified); - - // update the tabs - updatePanels(isModified); - } catch (e) { - notification.add({ - color: 'error', - message: e, - }); - } - }; - - /** - * Triggered when a file is changed - * @param isModified - isModified - */ - const updatePanels = (isModified: boolean) => { - try { - // get the model - const model = workspace.model; - if (!model) { - throw new Error('Missing model'); - } - - // visit the notes, and see if it exists - model.visitNodes((node) => { - // check if it is a tabNode - if (node instanceof TabNode) { - // it needs to be a file-editor - const component = node.getComponent(); - if (component !== 'file-editor') { - return; - } - - // path and space need to match - const config = node.getConfig(); - if (path !== config.path) { - return; - } - - const id = node.getId(); - if (isModified) { - model.doAction(Actions.renameTab(id, `${name}*`)); - } else { - model.doAction(Actions.renameTab(id, `${name}`)); - } - } - }); - } catch (e) { - notification.add({ - color: 'error', - message: e, - }); - } - }; - - /** - * Copy the path to the clipboard - */ - const copyPath = async () => { - try { - await navigator.clipboard.writeText(path); - - notification.add({ - color: 'success', - message: 'Successfully copied path', - }); - } catch (e) { - notification.add({ - color: 'error', - message: 'Unable to copy path', - }); - } - }; - - return ( - - { - e.preventDefault(); - e.stopPropagation(); - copyPath(); - }} - > - - -   - { - e.preventDefault(); - e.stopPropagation(); - - // trigger the save - fileEditorRef.current?.saveFile(); - }} - > - - - - } - > - { - onFileEditorChange(isModified); - }} - /> - - ); + const { path } = props; + const { workspace } = useWorkspace(); + const notification = useNotification(); + + const [isModified, setIsModified] = useState(false); + + const fileEditorRef = useRef(null); + + // get the name + const name = path.split("/").pop(); + + /** + * Triggered when a file is changed + * @param isModified - isModified + */ + const onFileEditorChange = (isModified: boolean) => { + try { + // update + setIsModified(isModified); + + // update the tabs + updatePanels(isModified); + } catch (e) { + notification.add({ + color: "error", + message: e, + }); + } + }; + + /** + * Triggered when a file is changed + * @param isModified - isModified + */ + const updatePanels = (isModified: boolean) => { + try { + // get the model + const model = workspace.model; + if (!model) { + throw new Error("Missing model"); + } + + // visit the notes, and see if it exists + model.visitNodes((node) => { + // check if it is a tabNode + if (node instanceof TabNode) { + // it needs to be a file-editor + const component = node.getComponent(); + if (component !== "file-editor") { + return; + } + + // path and space need to match + const config = node.getConfig(); + if (path !== config.path) { + return; + } + + const id = node.getId(); + if (isModified) { + model.doAction(Actions.renameTab(id, `${name}*`)); + } else { + model.doAction(Actions.renameTab(id, `${name}`)); + } + } + }); + } catch (e) { + notification.add({ + color: "error", + message: e, + }); + } + }; + + /** + * Copy the path to the clipboard + */ + const copyPath = async () => { + try { + await navigator.clipboard.writeText(path); + + notification.add({ + color: "success", + message: "Successfully copied path", + }); + } catch (e) { + notification.add({ + color: "error", + message: "Unable to copy path", + }); + } + }; + + return ( + + { + e.preventDefault(); + e.stopPropagation(); + copyPath(); + }} + > + + +   + { + e.preventDefault(); + e.stopPropagation(); + + // trigger the save + fileEditorRef.current?.saveFile(); + }} + > + + + + } + > + { + onFileEditorChange(isModified); + }} + /> + + ); }); diff --git a/packages/client/src/components/workspace/panels/FileExplorerPanel.tsx b/packages/client/src/components/workspace/panels/FileExplorerPanel.tsx index 2ba79ca028..0dd6b264ea 100644 --- a/packages/client/src/components/workspace/panels/FileExplorerPanel.tsx +++ b/packages/client/src/components/workspace/panels/FileExplorerPanel.tsx @@ -1,545 +1,544 @@ -import { useEffect, useState } from 'react'; -import { Actions, DockLocation, Layout, TabNode } from 'flexlayout-react'; import { - useNotification, - IconButton, - Stack, - Tooltip, - styled, - InputAdornment, - TextField, -} from '@semoss/ui'; + CoffeeOutlined, + CreateNewFolderOutlined, + FileUpload, + NoteAddOutlined, + PublishedWithChangesOutlined, + Refresh, + Search, +} from "@mui/icons-material"; +import { Actions, DockLocation, type Layout, TabNode } from "flexlayout-react"; +import { useEffect, useState } from "react"; import { - CreateNewFolderOutlined, - NoteAddOutlined, - FileUpload, - Refresh, - PublishedWithChangesOutlined, - CoffeeOutlined, - Search, -} from '@mui/icons-material'; - -import { useRootStore, useWorkspace } from '@/hooks'; + IconButton, + InputAdornment, + Stack, + styled, + TextField, + Tooltip, + useNotification, +} from "@semoss/ui"; import { - FileExplorer, - AddFileOverlay, - CreateFileOverlay, - DeleteFileOverlay, -} from '@/components/common'; -import { Panel } from './Panel'; + AddFileOverlay, + CreateFileOverlay, + DeleteFileOverlay, + FileExplorer, +} from "@/components/common"; +import { useRootStore, useWorkspace } from "@/hooks"; +import { Panel } from "./Panel"; -const EXPLORER_TYPE = 'app'; +const EXPLORER_TYPE = "app"; interface FileExplorerPanelProps { - title: string; - /** Current layoutobject */ - layout: Layout; + title: string; + /** Current layoutobject */ + layout: Layout; } -const StyledTitle = styled('div')(({ theme }) => ({ - borderRadius: '16px', - background: ' #EBF4FE', - width: 'fit-content', - marginTop: '4px', - paddingRight: theme.spacing(2), - paddingLeft: theme.spacing(2), - marginBottom: '8px', - - backgroundColor: theme.palette.primary.selected, - color: theme.palette.info.dark, +const StyledTitle = styled("div")(({ theme }) => ({ + borderRadius: "16px", + background: " #EBF4FE", + width: "fit-content", + marginTop: "4px", + paddingRight: theme.spacing(2), + paddingLeft: theme.spacing(2), + marginBottom: "8px", + + backgroundColor: theme.palette.primary.selected, + color: theme.palette.info.dark, })); -const StyledFileSpan = styled('span')(({ theme }) => ({ - color: 'var(--Text-Primary, #212121)', - fontFeatureSettings: "'liga' off, 'clig' off", - fontFamily: 'Inter', - fontSize: '16px', - fontStyle: 'normal', - fontWeight: 400, - lineHeight: '150%', // or '24px' if you prefer fixed px value - letterSpacing: '0.15px', +const StyledFileSpan = styled("span")(({ theme }) => ({ + color: "var(--Text-Primary, #212121)", + fontFeatureSettings: "'liga' off, 'clig' off", + fontFamily: "Inter", + fontSize: "16px", + fontStyle: "normal", + fontWeight: 400, + lineHeight: "150%", // or '24px' if you prefer fixed px value + letterSpacing: "0.15px", })); -const StyledTitleSpan = styled('span')(({ theme }) => ({ - color: 'var(--Primary-Dark, #1260DD)', - fontFeatureSettings: "'liga' off, 'clig' off", - fontSize: '13px', - fontFamily: 'Inter', - fontWeight: 400, - fontStyle: 'normal', - letterSpacing: '0.16px', - lineHeight: '18px', - marginBottom: '8px', - marginTop: '8px', +const StyledTitleSpan = styled("span")(({ theme }) => ({ + color: "var(--Primary-Dark, #1260DD)", + fontFeatureSettings: "'liga' off, 'clig' off", + fontSize: "13px", + fontFamily: "Inter", + fontWeight: 400, + fontStyle: "normal", + letterSpacing: "0.16px", + lineHeight: "18px", + marginBottom: "8px", + marginTop: "8px", })); const StyledTextField = styled(TextField)(({ theme }) => ({ - paddingRight: '16px', - paddingLeft: '16px', - marginTop: '8px', - width: '100%', - borderRadius: '8px', + paddingRight: "16px", + paddingLeft: "16px", + marginTop: "8px", + width: "100%", + borderRadius: "8px", })); export const FileExplorerPanel = (props: FileExplorerPanelProps) => { - const { title, layout } = props; - - const { workspace } = useWorkspace(); - const { monolithStore } = useRootStore(); - - const notification = useNotification(); - - const [expandedPaths, setExpandedPaths] = useState([]); - // files to add - const [selectedPath, setSelectedPath] = useState(''); - const [fileUploadPath, setFileUploadPath] = useState(''); - - // temporary fix for dead refresh button should be removed - const [counter, setCounter] = useState(0); - - // set the uploadPath based on the selected item - useEffect(() => { - let path = 'version/assets/'; - - // if selected, get the directory - if (selectedPath) { - if (selectedPath.slice(-1) === '/') { - path = selectedPath; - } else { - // try to remove the file name and get the directory - path = selectedPath.split('/').slice(0, -1).join('/'); - } - } - - setFileUploadPath(path); - }, [selectedPath]); - - /** - * Refresh the files - */ - const refreshFiles = () => { - // increment the counter - setCounter(counter + 1); - }; - - const handleToggleExpand = (path: string) => { - setExpandedPaths((prev) => - prev.includes(path) - ? prev.filter((p) => p !== path) - : [...prev, path], - ); - }; - /** - * Publish the app - */ - const publishApp = async () => { - try { - // turn on loading - workspace.setLoading(true); - - const response = await monolithStore.runQuery( - `PublishProject(project='${workspace.appId}', release=true);`, - ); - - const output = response.pixelReturn[0].output, - type = response.pixelReturn[0].operationType[0]; - - if (type.indexOf('ERROR') > -1) { - notification.add({ - color: 'error', - message: output, - }); - - throw new Error(output.join('')); - } - - notification.add({ - color: 'success', - message: 'Successfully published', - }); - } catch (e) { - notification.add({ - color: 'error', - message: e.message, - }); - } finally { - // turn off loading - workspace.setLoading(false); - } - }; - - /** - * Recompile the app - */ - const recompileApp = async () => { - try { - // turn on loading - workspace.setLoading(true); - - const response = await monolithStore.runQuery( - `ReloadInsightClasses(project='${workspace.appId}', release=false);`, - ); - - const output = response.pixelReturn[0].output, - type = response.pixelReturn[0].operationType[0]; - - if (type.indexOf('ERROR') > -1) { - notification.add({ - color: 'error', - message: output, - }); - - throw new Error(output.join('')); - } - - notification.add({ - color: 'success', - message: - 'Successfully recompiled reactors. Remember to publish changes.', - }); - } catch (e) { - notification.add({ - color: 'error', - message: e.message, - }); - } finally { - // turn off loading - workspace.setLoading(false); - } - }; - - /** - * Open the add modal - */ - const handleOpenAddFile = () => { - workspace.openOverlay(() => ( - { - if (success) { - // create the panel - createPanel(uploadPath); - - // refresh the content - refreshFiles(); - } - - // close the overlay - workspace.closeOverlay(); - }} - uploadPath={fileUploadPath} - /> - )); - }; - - /** - * Open the create file modal - */ - const handleOpenCreateFile = ( - /** Mode of add file */ - mode: 'directory' | 'file', - ) => { - workspace.openOverlay(() => ( - { - if (success) { - // create the panel - createPanel(uploadPath); - - // refresh the content - refreshFiles(); - } - - // close the overlay - workspace.closeOverlay(); - }} - uploadPath={fileUploadPath} - mode={mode} - /> - )); - }; - - /** - * Select a panel and create one if it doesn't exist - * - * path - path to file - */ - const handleOnSelect = (path: string) => { - // try to select a panel, if it doesn't exist create it. Save the path - const IsSelected = selectPanel(path); - if (!IsSelected) { - createPanel(path); - } - - // set the path - setSelectedPath(path); - }; - - /** - * Open the delete modal - */ - const handleOnTrashClick = (fileDeletePath: string) => { - workspace.openOverlay(() => ( - { - if (success) { - // trigger the delete file callback if successful - removePanel(fileDeletePath); - - // refresh the content - refreshFiles(); - } - // close the overlay - workspace.closeOverlay(); - }} - fileDeletePath={fileDeletePath} - /> - )); - }; - - /** - * Handle dragging of an item - * - * event - drag event - * path - path of the file - */ - const handleOnItemDragStart = ( - event: React.DragEvent, - path: string, - ) => { - try { - // can can only drag in files into the workspace - if (path.slice(-1) === '/') { - return; - } - - // get the model - const model = workspace.model; - if (!model) { - throw new Error('Missing model'); - } - - // TODO: altKey key needs to be down for now. event.altKey=false is reserved for panel-to-panel interactions - if (!event.altKey) { - return; - } - - // get the name - const name = path.split('/').pop(); - - // add to layout - layout.addTabWithDragAndDrop(event as unknown as DragEvent, { - type: 'tab', - name: name, - component: 'file-editor', - config: { - path: path, - }, - enableClose: true, - }); - } catch (e) { - notification.add({ - color: 'error', - message: e, - }); - } - }; - - /** Helpers */ - /** - * Create a new panel and highlight it - * - * path - path to file - */ - const createPanel = (path: string): boolean => { - try { - if (!path) { - return false; - } - - // can can only create panels for files - if (path.slice(-1) === '/') { - return false; - } - - // get the model - const model = workspace.model; - if (!model) { - throw new Error('Missing model'); - } - - // where to add the node - const addId = - model.getActiveTabset()?.getId() || - model.getRoot().getChildren()[0]?.getId() || - ''; - - // get the name - const name = path.split('/').pop(); - - // create and select the panel - model.doAction( - Actions.addNode( - { - type: 'tab', - name: name, - component: 'file-editor', - config: { - path: path, - }, - enableClose: true, - }, - addId, - DockLocation.CENTER, - -1, - true, - ), - ); - } catch (e) { - notification.add({ - color: 'error', - message: e, - }); - - return false; - } - - return true; - }; - - /** - * Select a panel if it is there. Return false if not selected. - * - * path - path to file - */ - const selectPanel = (path: string): boolean => { - try { - if (!path) { - return false; - } - - // can can only select files - if (path.slice(-1) === '/') { - return false; - } - - let selectedNode: TabNode | null = null; - - // get the model - const model = workspace.model; - if (!model) { - throw new Error('Missing model'); - } - - // visit the notes, and see if it exists - model.visitNodes((node) => { - // check if it is a tabNode - if (node instanceof TabNode) { - // it needs to be a file-editor - const component = node.getComponent(); - if (component !== 'file-editor') { - return; - } - - // path and space need to match - const config = node.getConfig(); - if (path !== config.path) { - return; - } - - selectedNode = node; - } - }); - - // create a new panel if there is no node - if (!selectedNode) { - return false; - } - - const selectedNodeId = selectedNode.getId(); - model.doAction(Actions.selectTab(selectedNodeId)); - } catch (e) { - notification.add({ - color: 'error', - message: e, - }); - - return false; - } - - return true; - }; - - /** - * Remove a panel - */ - const removePanel = (path: string) => { - try { - if (!path) { - return; - } - - const nodesToBeRemoved: TabNode[] = []; - - // get the model - const model = workspace.model; - if (!model) { - throw new Error('Missing model'); - } - - // visit the notes, and see if it exists - model.visitNodes((node) => { - // check if it is a tabNode - if (node instanceof TabNode) { - // it needs to be a file-editor - const component = node.getComponent(); - if (component !== 'file-editor') { - return; - } - - // path and space need to match - const config = node.getConfig(); - if (config.path.indexOf(path) !== 0) { - return; - } - - nodesToBeRemoved.push(node); - } - }); - - // delete the tabs - for (const n of nodesToBeRemoved) { - const id = n.getId(); - model.doAction(Actions.deleteTab(id)); - } - } catch (e) { - notification.add({ - color: 'error', - message: e, - }); - } - }; - - return ( - - - - {title} - - {/* TODO: Implement Search functionality and remove the comments */} - {/* ([]); + // files to add + const [selectedPath, setSelectedPath] = useState(""); + const [fileUploadPath, setFileUploadPath] = useState(""); + + // temporary fix for dead refresh button should be removed + const [counter, setCounter] = useState(0); + + // set the uploadPath based on the selected item + useEffect(() => { + let path = "version/assets/"; + + // if selected, get the directory + if (selectedPath) { + if (selectedPath.slice(-1) === "/") { + path = selectedPath; + } else { + // try to remove the file name and get the directory + path = selectedPath.split("/").slice(0, -1).join("/"); + } + } + + setFileUploadPath(path); + }, [selectedPath]); + + /** + * Refresh the files + */ + const refreshFiles = () => { + // increment the counter + setCounter(counter + 1); + }; + + const handleToggleExpand = (path: string) => { + setExpandedPaths((prev) => + prev.includes(path) + ? prev.filter((p) => p !== path) + : [...prev, path], + ); + }; + /** + * Publish the app + */ + const publishApp = async () => { + try { + // turn on loading + workspace.setLoading(true); + + const response = await monolithStore.runQuery( + `PublishProject(project='${workspace.appId}', release=true);`, + ); + + const output = response.pixelReturn[0].output, + type = response.pixelReturn[0].operationType[0]; + + if (type.indexOf("ERROR") > -1) { + notification.add({ + color: "error", + message: output, + }); + + throw new Error(output.join("")); + } + + notification.add({ + color: "success", + message: "Successfully published", + }); + } catch (e) { + notification.add({ + color: "error", + message: e.message, + }); + } finally { + // turn off loading + workspace.setLoading(false); + } + }; + + /** + * Recompile the app + */ + const recompileApp = async () => { + try { + // turn on loading + workspace.setLoading(true); + + const response = await monolithStore.runQuery( + `ReloadInsightClasses(project='${workspace.appId}', release=false);`, + ); + + const output = response.pixelReturn[0].output, + type = response.pixelReturn[0].operationType[0]; + + if (type.indexOf("ERROR") > -1) { + notification.add({ + color: "error", + message: output, + }); + + throw new Error(output.join("")); + } + + notification.add({ + color: "success", + message: + "Successfully recompiled reactors. Remember to publish changes.", + }); + } catch (e) { + notification.add({ + color: "error", + message: e.message, + }); + } finally { + // turn off loading + workspace.setLoading(false); + } + }; + + /** + * Open the add modal + */ + const handleOpenAddFile = () => { + workspace.openOverlay(() => ( + { + if (success) { + // create the panel + createPanel(uploadPath); + + // refresh the content + refreshFiles(); + } + + // close the overlay + workspace.closeOverlay(); + }} + uploadPath={fileUploadPath} + /> + )); + }; + + /** + * Open the create file modal + */ + const handleOpenCreateFile = ( + /** Mode of add file */ + mode: "directory" | "file", + ) => { + workspace.openOverlay(() => ( + { + if (success) { + // create the panel + createPanel(uploadPath); + + // refresh the content + refreshFiles(); + } + + // close the overlay + workspace.closeOverlay(); + }} + uploadPath={fileUploadPath} + mode={mode} + /> + )); + }; + + /** + * Select a panel and create one if it doesn't exist + * + * path - path to file + */ + const handleOnSelect = (path: string) => { + // try to select a panel, if it doesn't exist create it. Save the path + const IsSelected = selectPanel(path); + if (!IsSelected) { + createPanel(path); + } + + // set the path + setSelectedPath(path); + }; + + /** + * Open the delete modal + */ + const handleOnTrashClick = (fileDeletePath: string) => { + workspace.openOverlay(() => ( + { + if (success) { + // trigger the delete file callback if successful + removePanel(fileDeletePath); + + // refresh the content + refreshFiles(); + } + // close the overlay + workspace.closeOverlay(); + }} + fileDeletePath={fileDeletePath} + /> + )); + }; + + /** + * Handle dragging of an item + * + * event - drag event + * path - path of the file + */ + const handleOnItemDragStart = ( + event: React.DragEvent, + path: string, + ) => { + try { + // can can only drag in files into the workspace + if (path.slice(-1) === "/") { + return; + } + + // get the model + const model = workspace.model; + if (!model) { + throw new Error("Missing model"); + } + + // TODO: altKey key needs to be down for now. event.altKey=false is reserved for panel-to-panel interactions + if (!event.altKey) { + return; + } + + // get the name + const name = path.split("/").pop(); + + // add to layout + layout.addTabWithDragAndDrop(event as unknown as DragEvent, { + type: "tab", + name: name, + component: "file-editor", + config: { + path: path, + }, + enableClose: true, + }); + } catch (e) { + notification.add({ + color: "error", + message: e, + }); + } + }; + + /** Helpers */ + /** + * Create a new panel and highlight it + * + * path - path to file + */ + const createPanel = (path: string): boolean => { + try { + if (!path) { + return false; + } + + // can can only create panels for files + if (path.slice(-1) === "/") { + return false; + } + + // get the model + const model = workspace.model; + if (!model) { + throw new Error("Missing model"); + } + + // where to add the node + const addId = + model.getActiveTabset()?.getId() || + model.getRoot().getChildren()[0]?.getId() || + ""; + + // get the name + const name = path.split("/").pop(); + + // create and select the panel + model.doAction( + Actions.addNode( + { + type: "tab", + name: name, + component: "file-editor", + config: { + path: path, + }, + enableClose: true, + }, + addId, + DockLocation.CENTER, + -1, + true, + ), + ); + } catch (e) { + notification.add({ + color: "error", + message: e, + }); + + return false; + } + + return true; + }; + + /** + * Select a panel if it is there. Return false if not selected. + * + * path - path to file + */ + const selectPanel = (path: string): boolean => { + try { + if (!path) { + return false; + } + + // can can only select files + if (path.slice(-1) === "/") { + return false; + } + + let selectedNode: TabNode | null = null; + + // get the model + const model = workspace.model; + if (!model) { + throw new Error("Missing model"); + } + + // visit the notes, and see if it exists + model.visitNodes((node) => { + // check if it is a tabNode + if (node instanceof TabNode) { + // it needs to be a file-editor + const component = node.getComponent(); + if (component !== "file-editor") { + return; + } + + // path and space need to match + const config = node.getConfig(); + if (path !== config.path) { + return; + } + + selectedNode = node; + } + }); + + // create a new panel if there is no node + if (!selectedNode) { + return false; + } + + const selectedNodeId = selectedNode.getId(); + model.doAction(Actions.selectTab(selectedNodeId)); + } catch (e) { + notification.add({ + color: "error", + message: e, + }); + + return false; + } + + return true; + }; + + /** + * Remove a panel + */ + const removePanel = (path: string) => { + try { + if (!path) { + return; + } + + const nodesToBeRemoved: TabNode[] = []; + + // get the model + const model = workspace.model; + if (!model) { + throw new Error("Missing model"); + } + + // visit the notes, and see if it exists + model.visitNodes((node) => { + // check if it is a tabNode + if (node instanceof TabNode) { + // it needs to be a file-editor + const component = node.getComponent(); + if (component !== "file-editor") { + return; + } + + // path and space need to match + const config = node.getConfig(); + if (config.path.indexOf(path) !== 0) { + return; + } + + nodesToBeRemoved.push(node); + } + }); + + // delete the tabs + for (const n of nodesToBeRemoved) { + const id = n.getId(); + model.doAction(Actions.deleteTab(id)); + } + } catch (e) { + notification.add({ + color: "error", + message: e, + }); + } + }; + + return ( + + + + {title} + + {/* TODO: Implement Search functionality and remove the comments */} + {/* { // ), }} /> */} - - Files - - - { - e.stopPropagation(); - publishApp(); - }} - > - - - - - { - e.stopPropagation(); - recompileApp(); - }} - > - - - - - { - e.stopPropagation(); - handleOpenAddFile(); - }} - > - - - - - { - e.stopPropagation(); - handleOpenCreateFile('file'); - }} - > - - - - - { - e.stopPropagation(); - handleOpenCreateFile('directory'); - }} - > - - - - - - - - } - > - { - handleOnSelect(path); - }} - onTrashClick={(e, path) => { - handleOnTrashClick(path); - }} - onDragStart={(e, path) => { - handleOnItemDragStart(e, path); - }} - expandedPaths={expandedPaths} - onToggleExpand={handleToggleExpand} - /> - - ); + + Files + + + { + e.stopPropagation(); + publishApp(); + }} + > + + + + + { + e.stopPropagation(); + recompileApp(); + }} + > + + + + + { + e.stopPropagation(); + handleOpenAddFile(); + }} + > + + + + + { + e.stopPropagation(); + handleOpenCreateFile("file"); + }} + > + + + + + { + e.stopPropagation(); + handleOpenCreateFile("directory"); + }} + > + + + + + + + + } + > + { + handleOnSelect(path); + }} + onTrashClick={(e, path) => { + handleOnTrashClick(path); + }} + onDragStart={(e, path) => { + handleOnItemDragStart(e, path); + }} + expandedPaths={expandedPaths} + onToggleExpand={handleToggleExpand} + /> + + ); }; diff --git a/packages/client/src/components/workspace/panels/GraphPanel.tsx b/packages/client/src/components/workspace/panels/GraphPanel.tsx index 1479b3b4ab..089f34458e 100644 --- a/packages/client/src/components/workspace/panels/GraphPanel.tsx +++ b/packages/client/src/components/workspace/panels/GraphPanel.tsx @@ -1,22 +1,21 @@ -import { observer } from 'mobx-react-lite'; - -import { Typography, useNotification } from '@semoss/ui'; -import { Panel } from './Panel'; -import { ReactFlow } from '@xyflow/react'; -import { useBlocks } from '@semoss/renderer'; +import { ReactFlow } from "@xyflow/react"; +import { observer } from "mobx-react-lite"; +import { useBlocks } from "@semoss/renderer"; +import { Typography, useNotification } from "@semoss/ui"; +import { Panel } from "./Panel"; export const GraphPanel: React.FC = observer(() => { - const notification = useNotification(); + const notification = useNotification(); - const { state } = useBlocks(); + const { state } = useBlocks(); - return ( - - - - ); + return ( + + + + ); }); diff --git a/packages/client/src/components/workspace/panels/Panel.tsx b/packages/client/src/components/workspace/panels/Panel.tsx index b8e98c689c..8a21be0345 100644 --- a/packages/client/src/components/workspace/panels/Panel.tsx +++ b/packages/client/src/components/workspace/panels/Panel.tsx @@ -1,67 +1,67 @@ -import React from 'react'; -import { styled, Stack } from '@semoss/ui'; +import type React from "react"; +import { Stack, styled } from "@semoss/ui"; const StyledPanel = styled(Stack)(({ theme }) => ({ - height: '100%', - width: '100%', - overflow: 'hidden', + height: "100%", + width: "100%", + overflow: "hidden", })); const StyledPanelActions = styled(Stack)(({ theme }) => ({ - width: '100%', - backgroundColor: '#FFF', - padding: theme.spacing(0.5), + width: "100%", + backgroundColor: "#FFF", + padding: theme.spacing(0.5), })); const StyledPanelContent = styled(Stack)(({ theme }) => ({ - height: '100%', - width: '100%', - overflow: 'hidden', - backgroundColor: theme.palette.background.paper, + height: "100%", + width: "100%", + overflow: "hidden", + backgroundColor: theme.palette.background.paper, })); const StyledPanelFooter = styled(Stack)(({ theme }) => ({ - width: '100%', - backgroundColor: '#FFF', - padding: theme.spacing(0.5), + width: "100%", + backgroundColor: "#FFF", + padding: theme.spacing(0.5), })); interface PanelProps { - /** Children */ - children: React.ReactNode; + /** Children */ + children: React.ReactNode; - /** Actions to render */ - actions?: React.ReactNode; + /** Actions to render */ + actions?: React.ReactNode; - /** Footer to render */ - footer?: React.ReactNode; + /** Footer to render */ + footer?: React.ReactNode; } export const Panel: React.FC = ({ - children, - actions = null, - footer = null, + children, + actions = null, + footer = null, }) => { - return ( - - {actions ? ( - - {actions} - - ) : null} - {children} - {footer ? ( - - {footer} - - ) : null} - - ); + return ( + + {actions ? ( + + {actions} + + ) : null} + {children} + {footer ? ( + + {footer} + + ) : null} + + ); }; diff --git a/packages/client/src/components/workspace/panels/SettingsPanel.tsx b/packages/client/src/components/workspace/panels/SettingsPanel.tsx index 62732c2beb..307e90185d 100644 --- a/packages/client/src/components/workspace/panels/SettingsPanel.tsx +++ b/packages/client/src/components/workspace/panels/SettingsPanel.tsx @@ -1,194 +1,193 @@ -import { useEffect, useState } from 'react'; -import { useNavigate } from 'react-router-dom'; +import { GetAppRounded } from "@mui/icons-material"; +import { useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; import { - styled, - ToggleTabsGroup, - Container, - Stack, - IconButton, - useNotification, - Tooltip, -} from '@semoss/ui'; - -import { useRootStore, useWorkspace } from '@/hooks'; + Container, + IconButton, + Stack, + styled, + ToggleTabsGroup, + Tooltip, + useNotification, +} from "@semoss/ui"; +import { AppSettings } from "@/components/app"; import { - PendingMembersTable, - MembersTable, - SettingsTiles, -} from '@/components/settings'; -import { AppSettings } from '@/components/app'; -import { SettingsContext } from '@/contexts'; -import { GetAppRounded } from '@mui/icons-material'; -import { Panel } from './Panel'; + MembersTable, + PendingMembersTable, + SettingsTiles, +} from "@/components/settings"; +import { SettingsContext } from "@/contexts"; +import { useRootStore, useWorkspace } from "@/hooks"; +import { Panel } from "./Panel"; -const StyledContainer = styled('div')(({ theme }) => ({ - width: '100%', - display: 'flex', - alignSelf: 'stretch', - flexDirection: 'column', - alignItems: 'flex-start', - gap: theme.spacing(2), - paddingTop: theme.spacing(5), +const StyledContainer = styled("div")(({ theme }) => ({ + width: "100%", + display: "flex", + alignSelf: "stretch", + flexDirection: "column", + alignItems: "flex-start", + gap: theme.spacing(2), + paddingTop: theme.spacing(5), })); -const StyledContent = styled('div')(({ theme }) => ({ - display: 'flex', - width: '100%', - flexDirection: 'column', - alignItems: 'flex-start', - gap: theme.spacing(2), - flexShrink: '0', +const StyledContent = styled("div")(({ theme }) => ({ + display: "flex", + width: "100%", + flexDirection: "column", + alignItems: "flex-start", + gap: theme.spacing(2), + flexShrink: "0", })); -type VIEW = 'CURRENT' | 'PENDING' | 'APP'; +type VIEW = "CURRENT" | "PENDING" | "APP"; export const SettingsPanel = () => { - const { configStore, monolithStore } = useRootStore(); - const notification = useNotification(); - const { workspace } = useWorkspace(); - const navigate = useNavigate(); + const { configStore, monolithStore } = useRootStore(); + const notification = useNotification(); + const { workspace } = useWorkspace(); + const navigate = useNavigate(); - const [view, setView] = useState('CURRENT'); + const [view, setView] = useState("CURRENT"); - /** - * Method that is called to export the app - */ - const exportApp = async () => { - // turn on loading - workspace.setLoading(true); + /** + * Method that is called to export the app + */ + const exportApp = async () => { + // turn on loading + workspace.setLoading(true); - try { - // export the app - const response = await monolithStore.runQuery<[string]>( - `ExportProjectApp(project=["${workspace.appId}"]);`, - ); + try { + // export the app + const response = await monolithStore.runQuery<[string]>( + `ExportProjectApp(project=["${workspace.appId}"]);`, + ); - // throw an error if there is no key - const key = response.pixelReturn[0].output; - if (!key) { - throw new Error('Error exporting app'); - } + // throw an error if there is no key + const key = response.pixelReturn[0].output; + if (!key) { + throw new Error("Error exporting app"); + } - await monolithStore.download(configStore.store.insightID, key); + await monolithStore.download(configStore.store.insightID, key); - notification.add({ - color: 'success', - message: 'Success', - }); - } catch (e) { - console.error(e); + notification.add({ + color: "success", + message: "Success", + }); + } catch (e) { + console.error(e); - notification.add({ - color: 'error', - message: e.message, - }); - } finally { - // turn of loading - workspace.setLoading(false); - } - }; + notification.add({ + color: "error", + message: e.message, + }); + } finally { + // turn of loading + workspace.setLoading(false); + } + }; - return ( - - - - - {workspace.role === 'EDITOR' || - workspace.role === 'OWNER' ? ( - -
- - { - exportApp(); - }} - > - - - -
-
- ) : null} - {workspace.role === 'OWNER' ? ( - { - if ( - location.pathname.startsWith( - '/settings/app/', - ) - ) { - // If in app settings - navigate('/settings/app'); - } else { - // If in App Library - navigate('/'); - } - }} - /> - ) : null} - - setView(v as VIEW)} - > - - - - - {view === 'CURRENT' && ( - console.log('TODO')} - /> - )} - {view === 'PENDING' && ( - - )} - {view === 'APP' && ( - - )} - -
-
-
-
- ); + return ( + + + + + {workspace.role === "EDITOR" || + workspace.role === "OWNER" ? ( + +
+ + { + exportApp(); + }} + > + + + +
+
+ ) : null} + {workspace.role === "OWNER" ? ( + { + if ( + location.pathname.startsWith( + "/settings/app/", + ) + ) { + // If in app settings + navigate("/settings/app"); + } else { + // If in App Library + navigate("/"); + } + }} + /> + ) : null} + + setView(v as VIEW)} + > + + + + + {view === "CURRENT" && ( + console.log("TODO")} + /> + )} + {view === "PENDING" && ( + + )} + {view === "APP" && ( + + )} + +
+
+
+
+ ); }; diff --git a/packages/client/src/components/workspace/panels/TerminalPanel.tsx b/packages/client/src/components/workspace/panels/TerminalPanel.tsx index feda2ba2d9..d4b3ea1953 100644 --- a/packages/client/src/components/workspace/panels/TerminalPanel.tsx +++ b/packages/client/src/components/workspace/panels/TerminalPanel.tsx @@ -1,259 +1,256 @@ -import { useState } from 'react'; -import { observer } from 'mobx-react-lite'; - +import { CodeRounded, TerminalRounded } from "@mui/icons-material"; +import { observer } from "mobx-react-lite"; +import { useState } from "react"; import { - buildTable, - Button, - Stack, - styled, - Terminal, - TerminalProps, - ToggleButton, - ToggleButtonGroup, - useNotification, -} from '@semoss/ui'; -import { CodeRounded, TerminalRounded } from '@mui/icons-material'; - -import PythonLogo from '@/assets/img/Python-logo.svg'; -import RLogo from '@/assets/img/R-logo.svg'; - -import { Panel } from './Panel'; -import { useWorkspace } from '@/hooks'; + Button, + buildTable, + Stack, + styled, + Terminal, + type TerminalProps, + ToggleButton, + ToggleButtonGroup, + useNotification, +} from "@semoss/ui"; +import PythonLogo from "@/assets/img/Python-logo.svg"; +import RLogo from "@/assets/img/R-logo.svg"; +import { useWorkspace } from "@/hooks"; +import { Panel } from "./Panel"; -const StyledImage = styled('img')(({ theme }) => ({ - height: '13px', - wdith: '13px', +const StyledImage = styled("img")(({ theme }) => ({ + height: "13px", + wdith: "13px", })); const LANGUAGE = { - PIXEL: 'Pixel', - PYTHON: 'Python', - R: 'R', - SHELL: 'Shell', + PIXEL: "Pixel", + PYTHON: "Python", + R: "R", + SHELL: "Shell", } as const; interface FrameHeaders { - headerInfo: { - headers: { - alias: string; - header: string; - dataType: string; - adtlType: string; - qsName: unknown; - }[]; - joins: unknown[]; - }; + headerInfo: { + headers: { + alias: string; + header: string; + dataType: string; + adtlType: string; + qsName: unknown; + }[]; + joins: unknown[]; + }; } interface TaskData { - headerInfo?: { - alias: string; - }[]; - data: { - values: unknown[][]; - }; + headerInfo?: { + alias: string; + }[]; + data: { + values: unknown[][]; + }; } export const TerminalPanel: React.FC = observer(() => { - const notification = useNotification(); + const notification = useNotification(); - const [history, setHistory] = useState([]); - const [isLoading, setIsLoading] = useState(false); - const { workspace } = useWorkspace(); + const [history, setHistory] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const { workspace } = useWorkspace(); - const [command, setCommand] = useState(''); - const [language, setLanguage] = useState('PIXEL'); + const [command, setCommand] = useState(""); + const [language, setLanguage] = useState("PIXEL"); - /** - * Get instructions based on the language - * @param language - current language - * @returns instructions - */ - const getInstructions = (language: string, prefix = '', postfix = '') => { - let instructions = ''; - if (language === 'PIXEL') { - instructions = `${prefix}\x1b[34mPixel\x1b[0m${postfix}`; - } else if (language === 'SHELL') { - instructions = `${prefix}\x1b[33mShell\x1b[0m${postfix}`; - } else if (language === 'PYTHON') { - instructions = `${prefix}\x1b[32mPython\x1b[0m${postfix}`; - } else if (language === 'R') { - instructions = `${prefix}\x1b[36mR\x1b[0m${postfix}`; - } + /** + * Get instructions based on the language + * @param language - current language + * @returns instructions + */ + const getInstructions = (language: string, prefix = "", postfix = "") => { + let instructions = ""; + if (language === "PIXEL") { + instructions = `${prefix}\x1b[34mPixel\x1b[0m${postfix}`; + } else if (language === "SHELL") { + instructions = `${prefix}\x1b[33mShell\x1b[0m${postfix}`; + } else if (language === "PYTHON") { + instructions = `${prefix}\x1b[32mPython\x1b[0m${postfix}`; + } else if (language === "R") { + instructions = `${prefix}\x1b[36mR\x1b[0m${postfix}`; + } - return instructions; - }; + return instructions; + }; - /** - * Run a command - * @param command - command to run - * @param id - ID of the file - * @param path - path to the file - */ - const runCommand = async () => { - try { - setIsLoading(true); + /** + * Run a command + * @param command - command to run + * @param id - ID of the file + * @param path - path to the file + */ + const runCommand = async () => { + try { + setIsLoading(true); - const cleaned = command.trim(); - if (!cleaned) { - throw new Error(`No Command`); - } + const cleaned = command.trim(); + if (!cleaned) { + throw new Error(`No Command`); + } - let pixel = ''; - if (language === 'PIXEL') { - pixel = cleaned; - } else if (language === 'SHELL') { - pixel = `Command("${cleaned}");`; - } else if (language === 'PYTHON') { - pixel = `Py("${cleaned}");`; - } + let pixel = ""; + if (language === "PIXEL") { + pixel = cleaned; + } else if (language === "SHELL") { + pixel = `Command("${cleaned}");`; + } else if (language === "PYTHON") { + pixel = `Py("${cleaned}");`; + } - // run the pixel - // TODO: We need to fix workspace.store so we just call runWorkspacePixel - const response = await workspace.runWorkspacePixel(pixel); + // run the pixel + // TODO: We need to fix workspace.store so we just call runWorkspacePixel + const response = await workspace.runWorkspacePixel(pixel); - const updatedHistory = [...history]; - for (const r of response.pixelReturn) { - const { output, operationType, timeToRun } = r; + const updatedHistory = [...history]; + for (const r of response.pixelReturn) { + const { output, operationType, timeToRun } = r; - let postfix = ''; - // only show if longer than 5 seconds - if (timeToRun > 5000) { - const seconds = Math.floor(timeToRun / 1000); // seconds - const minutes = Math.floor(timeToRun / 60); - postfix = ` in ${minutes - .toString() - .padStart(2, '0')}:${seconds - .toString() - .padStart(2, '0')}`; - } + let postfix = ""; + // only show if longer than 5 seconds + if (timeToRun > 5000) { + const seconds = Math.floor(timeToRun / 1000); // seconds + const minutes = Math.floor(timeToRun / 60); + postfix = ` in ${minutes + .toString() + .padStart(2, "0")}:${seconds + .toString() + .padStart(2, "0")}`; + } - let formatted: unknown = output; - if (operationType.indexOf('TASK_DATA') > -1) { - const data = output as TaskData; + let formatted: unknown = output; + if (operationType.indexOf("TASK_DATA") > -1) { + const data = output as TaskData; - if (data.headerInfo) { - const headers = data.headerInfo.reduce( - (acc, val, idx) => { - acc[idx] = val.alias; - return acc; - }, - {}, - ); + if (data.headerInfo) { + const headers = data.headerInfo.reduce( + (acc, val, idx) => { + acc[idx] = val.alias; + return acc; + }, + {}, + ); - const table = data.data.values.map((row) => { - return row.reduce((acc, val, idx) => { - acc[headers[idx]] = val; - return acc; - }, {}) as Record; - }); + const table = data.data.values.map((row) => { + return row.reduce((acc, val, idx) => { + acc[headers[idx]] = val; + return acc; + }, {}) as Record; + }); - formatted = buildTable(table); - } else { - formatted = buildTable(data.data.values); - } - } else if (operationType.indexOf('FRAME_HEADERSf') > -1) { - const data = output as FrameHeaders; + formatted = buildTable(table); + } else { + formatted = buildTable(data.data.values); + } + } else if (operationType.indexOf("FRAME_HEADERSf") > -1) { + const data = output as FrameHeaders; - formatted = buildTable(data.headerInfo.headers); - } else if (operationType.indexOf('CODE_EXECUTION') > -1) { - if ( - Array.isArray(output) && - output[0] && - output[0].hasOwnProperty('output') - ) { - formatted = output[0].output; - } - } else if (operationType.indexOf('INVALID_SYNTAX') > -1) { - formatted = `\x1b[31mInvalid Syntax: ${output}\x1b[0m`; - } else if (operationType.indexOf('ERROR') > -1) { - formatted = `\x1b[31mError: ${output}\x1b[0m`; - } + formatted = buildTable(data.headerInfo.headers); + } else if (operationType.indexOf("CODE_EXECUTION") > -1) { + if ( + Array.isArray(output) && + output[0] && + Object.hasOwn(output[0], "output") + ) { + formatted = output[0].output; + } + } else if (operationType.indexOf("INVALID_SYNTAX") > -1) { + formatted = `\x1b[31mInvalid Syntax: ${output}\x1b[0m`; + } else if (operationType.indexOf("ERROR") > -1) { + formatted = `\x1b[31mError: ${output}\x1b[0m`; + } - updatedHistory.push({ - instructions: getInstructions( - language, - 'Executed ', - postfix, - ), - command: command, - response: - typeof formatted !== 'string' - ? JSON.stringify(formatted, null, 2) - : formatted, - }); - } + updatedHistory.push({ + instructions: getInstructions( + language, + "Executed ", + postfix, + ), + command: command, + response: + typeof formatted !== "string" + ? JSON.stringify(formatted, null, 2) + : formatted, + }); + } - // update the history - setHistory(updatedHistory); - } catch (e) { - notification.add({ - color: 'error', - message: e, - }); + // update the history + setHistory(updatedHistory); + } catch (e) { + notification.add({ + color: "error", + message: e, + }); - console.error(e); - } finally { - setIsLoading(false); - } - }; + console.error(e); + } finally { + setIsLoading(false); + } + }; - return ( - - - {Object.entries(LANGUAGE).map(([value, name]) => { - return ( - { - setCommand(""); - setLanguage(value); - }} - > - {value === 'PIXEL' && ( - - )} - {value === 'PYTHON' && ( - - )} - {value === 'R' && ( - - )} - {value === 'SHELL' && ( - - )} - - ); - })} - -   - - - } - > - runCommand()} - onCommand={(c) => setCommand(c)} - /> - - ); + return ( + + + {Object.entries(LANGUAGE).map(([value, name]) => { + return ( + { + setCommand(""); + setLanguage(value); + }} + > + {value === "PIXEL" && ( + + )} + {value === "PYTHON" && ( + + )} + {value === "R" && ( + + )} + {value === "SHELL" && ( + + )} + + ); + })} + +   + + + } + > + runCommand()} + onCommand={(c) => setCommand(c)} + /> + + ); }); diff --git a/packages/client/src/components/workspace/panels/index.tsx b/packages/client/src/components/workspace/panels/index.tsx index 1cd0d76a46..ef0b3be63f 100644 --- a/packages/client/src/components/workspace/panels/index.tsx +++ b/packages/client/src/components/workspace/panels/index.tsx @@ -1,7 +1,6 @@ -export * from './Panel'; - -export * from './SettingsPanel'; -export * from './EmptyFilePanel'; -export * from './FileExplorerPanel'; -export * from './FileEditorPanel'; -export * from './TerminalPanel'; +export * from "./EmptyFilePanel"; +export * from "./FileEditorPanel"; +export * from "./FileExplorerPanel"; +export * from "./Panel"; +export * from "./SettingsPanel"; +export * from "./TerminalPanel"; diff --git a/packages/client/src/constants.ts b/packages/client/src/constants.ts index abc1095c3f..6edd6d603d 100644 --- a/packages/client/src/constants.ts +++ b/packages/client/src/constants.ts @@ -1,47 +1,47 @@ -import { ALL_TYPES } from './types'; -import Logo from '@/assets/logo.svg'; +import Logo from "@/assets/logo.svg"; +import type { ALL_TYPES } from "./types"; export const THEME_TITLE = import.meta.env.VITE_THEME_TITLE; export const DOCUMENTATION_URL = import.meta.env.VITE_DOCUMENTATION_URL; export const THEME = { - name: THEME_TITLE || 'SEMOSS', - logo: Logo, + name: THEME_TITLE || "SEMOSS", + logo: Logo, }; export const PERMISSION_DESCRIPTION_MAP: Record< - ALL_TYPES, - Record + ALL_TYPES, + Record > = { - APP: { - author: 'Ability to hide or delete the data app, provision other authors and all editor permissions', - editor: 'Ability to edit the data app code, provision other users as editors and read only users, and all read-only permissions', - readonly: - 'Ability to view the data app. User still requires permission to all dependent databases, models, remote storage, vector databases, etc', - }, - FUNCTION: { - author: 'Ability to hide or delete the function, provision other authors, and all editor permissions', - editor: 'Ability to edit the function code, provision other users as editors and read-only users, and all read-only permissions', - readonly: 'Ability to execute the function', - }, - MODEL: { - author: 'Ability to edit the model connection details, set the model as discoverable, delete the model, provision other authors, and all editor permissions', - editor: 'Ability to edit the model details, provision other users as editors and read-only users, and all read-only permissions', - readonly: 'Ability to run the model', - }, - STORAGE: { - author: 'Ability to hide or delete the remote storage, provision other authors, and all editor permissions', - editor: 'Ability to push and delete files from the remote storage, and all read-only permissions', - readonly: 'Ability to view and pull files from the remote storage', - }, - DATABASE: { - author: 'Ability to edit the database connection details, set the database as discoverable, delete the database, provision other authors, and all editor permissions', - editor: 'Ability to edit the database structure, provision other users as editors and read-only users, and all read-only permissions', - readonly: 'Ability to query and read data from the database', - }, - VECTOR: { - author: 'Ability to hide or delete the vector database, provision other authors, and all editor permissions', - editor: 'Ability to add and remove files from the vector database, and all read-only permissions', - readonly: 'Ability to query against the vector database', - }, + APP: { + author: "Ability to hide or delete the data app, provision other authors and all editor permissions", + editor: "Ability to edit the data app code, provision other users as editors and read only users, and all read-only permissions", + readonly: + "Ability to view the data app. User still requires permission to all dependent databases, models, remote storage, vector databases, etc", + }, + FUNCTION: { + author: "Ability to hide or delete the function, provision other authors, and all editor permissions", + editor: "Ability to edit the function code, provision other users as editors and read-only users, and all read-only permissions", + readonly: "Ability to execute the function", + }, + MODEL: { + author: "Ability to edit the model connection details, set the model as discoverable, delete the model, provision other authors, and all editor permissions", + editor: "Ability to edit the model details, provision other users as editors and read-only users, and all read-only permissions", + readonly: "Ability to run the model", + }, + STORAGE: { + author: "Ability to hide or delete the remote storage, provision other authors, and all editor permissions", + editor: "Ability to push and delete files from the remote storage, and all read-only permissions", + readonly: "Ability to view and pull files from the remote storage", + }, + DATABASE: { + author: "Ability to edit the database connection details, set the database as discoverable, delete the database, provision other authors, and all editor permissions", + editor: "Ability to edit the database structure, provision other users as editors and read-only users, and all read-only permissions", + readonly: "Ability to query and read data from the database", + }, + VECTOR: { + author: "Ability to hide or delete the vector database, provision other authors, and all editor permissions", + editor: "Ability to add and remove files from the vector database, and all read-only permissions", + readonly: "Ability to query against the vector database", + }, }; diff --git a/packages/client/src/contexts/DesignerContext.tsx b/packages/client/src/contexts/DesignerContext.tsx index ecedeb639e..7e6a48a1fc 100644 --- a/packages/client/src/contexts/DesignerContext.tsx +++ b/packages/client/src/contexts/DesignerContext.tsx @@ -1,13 +1,12 @@ -import { createContext } from 'react'; - -import { DesignerStore } from '@/stores'; +import { createContext } from "react"; +import type { DesignerStore } from "@/stores"; /** * Value */ export type DesignerContextType = { - /** Store holding designer information */ - designer: DesignerStore; + /** Store holding designer information */ + designer: DesignerStore; }; /** diff --git a/packages/client/src/contexts/EngineContext.tsx b/packages/client/src/contexts/EngineContext.tsx index 5511f116e9..9c9e60fe25 100644 --- a/packages/client/src/contexts/EngineContext.tsx +++ b/packages/client/src/contexts/EngineContext.tsx @@ -1,37 +1,36 @@ -import { createContext } from 'react'; - -import { Role, ENGINE_TYPES } from '@/types'; +import { createContext } from "react"; +import type { ENGINE_TYPES, Role } from "@/types"; /** * Value */ export type EngineContextType = { - /** Type of the engine */ - type: ENGINE_TYPES; + /** Type of the engine */ + type: ENGINE_TYPES; - /** Name of the type */ - name: string; + /** Name of the type */ + name: string; - /** Path of the type */ - path: string; + /** Path of the type */ + path: string; - /** Active engine information */ - active: { - /** ID of the engine to load */ - id: string; + /** Active engine information */ + active: { + /** ID of the engine to load */ + id: string; - /** User's role associated with the engine */ - role: Role; + /** User's role associated with the engine */ + role: Role; - /** Name of the engine */ - name: string; + /** Name of the engine */ + name: string; - /** metadata to show on detail pages */ - metadata: Record; + /** metadata to show on detail pages */ + metadata: Record; - /** refreshes metadata for the active engine */ - refresh: () => void; - }; + /** refreshes metadata for the active engine */ + refresh: () => void; + }; }; /** diff --git a/packages/client/src/contexts/LLMContext.tsx b/packages/client/src/contexts/LLMContext.tsx index 75611a9826..8084e5feb4 100644 --- a/packages/client/src/contexts/LLMContext.tsx +++ b/packages/client/src/contexts/LLMContext.tsx @@ -1,12 +1,12 @@ -import { createContext } from 'react'; +import { createContext } from "react"; export type LLMContextType = { - /** id to use for code generation */ - modelId: string; - /** model options for code generation */ - modelOptions: { app_id: string; app_name: string }[]; - /** set model to use */ - setModel?: (id: string) => void; + /** id to use for code generation */ + modelId: string; + /** model options for code generation */ + modelOptions: { app_id: string; app_name: string }[]; + /** set model to use */ + setModel?: (id: string) => void; }; /** diff --git a/packages/client/src/contexts/MetamodelContext.tsx b/packages/client/src/contexts/MetamodelContext.tsx index dce600cb29..70d21157b0 100644 --- a/packages/client/src/contexts/MetamodelContext.tsx +++ b/packages/client/src/contexts/MetamodelContext.tsx @@ -1,17 +1,17 @@ -import { createContext } from 'react'; +import { createContext } from "react"; /** * Value */ export type MetamodelContextType = { - /** ID of the selected node */ - selectedNodeId: string; - /** Selected a new node by Id */ - onSelectNodeId: (id: string) => void; - /** Boolean to determine if metamodel is interactive aka editable */ - isInteractive: boolean; - /** update metamodel state */ - updateData: (nodeData: any, action: string) => void; + /** ID of the selected node */ + selectedNodeId: string; + /** Selected a new node by Id */ + onSelectNodeId: (id: string) => void; + /** Boolean to determine if metamodel is interactive aka editable */ + isInteractive: boolean; + /** update metamodel state */ + updateData: (nodeData: any, action: string) => void; }; /** diff --git a/packages/client/src/contexts/PageContext.tsx b/packages/client/src/contexts/PageContext.tsx index 8b5131cd61..ff0f4fae89 100644 --- a/packages/client/src/contexts/PageContext.tsx +++ b/packages/client/src/contexts/PageContext.tsx @@ -1,18 +1,17 @@ -import { createContext } from 'react'; - -import { PageStore } from '@/stores'; +import { createContext } from "react"; +import type { PageStore } from "@/stores"; /** * Value */ export type PageContextType = { - /** Page store*/ - page: PageStore; + /** Page store*/ + page: PageStore; }; /** * Context */ export const PageContext = createContext( - undefined, + undefined, ); diff --git a/packages/client/src/contexts/RootStoreContext.tsx b/packages/client/src/contexts/RootStoreContext.tsx index 1addff808b..78a47850c2 100644 --- a/packages/client/src/contexts/RootStoreContext.tsx +++ b/packages/client/src/contexts/RootStoreContext.tsx @@ -1,6 +1,5 @@ -import { createContext } from 'react'; - -import { RootStore } from '@/stores'; +import { createContext } from "react"; +import type { RootStore } from "@/stores"; /** * Value diff --git a/packages/client/src/contexts/SettingsContext.tsx b/packages/client/src/contexts/SettingsContext.tsx index 941cadb2f0..d2758ee54f 100644 --- a/packages/client/src/contexts/SettingsContext.tsx +++ b/packages/client/src/contexts/SettingsContext.tsx @@ -1,8 +1,8 @@ -import { createContext } from 'react'; +import { createContext } from "react"; export type SettingsContextType = { - /** True if the Settings is in admin mode */ - adminMode: boolean; + /** True if the Settings is in admin mode */ + adminMode: boolean; }; /** diff --git a/packages/client/src/contexts/StepperContext.tsx b/packages/client/src/contexts/StepperContext.tsx index c5a6db5309..da680e6b55 100644 --- a/packages/client/src/contexts/StepperContext.tsx +++ b/packages/client/src/contexts/StepperContext.tsx @@ -1,64 +1,64 @@ -import { createContext } from 'react'; +import { createContext } from "react"; export interface Step { - /** Title of the step */ - title: string; + /** Title of the step */ + title: string; - /** Description of the step */ - description: string; + /** Description of the step */ + description: string; - /** Data associated with the step */ - data: object | any; + /** Data associated with the step */ + data: object | any; - /** ID For particular step */ - id?: string; + /** ID For particular step */ + id?: string; } /** * Value */ export type StepperContextType = { - /** - * List of the current steps - */ - steps: Step[]; + /** + * List of the current steps + */ + steps: Step[]; - /** - * Active step index - */ - activeStepIdx: number; + /** + * Active step index + */ + activeStepIdx: number; - /** - * Active step info - */ - activeStep: Step | null; + /** + * Active step info + */ + activeStep: Step | null; - /** - * Track if the import is loading - */ - isLoading: boolean; + /** + * Track if the import is loading + */ + isLoading: boolean; - /** - * Update the steps in the flow - * - * step - step to add - * activeStepIdx - new active step - */ - setSteps: (steps: Step[], activeStepIdx: number) => void; + /** + * Update the steps in the flow + * + * step - step to add + * activeStepIdx - new active step + */ + setSteps: (steps: Step[], activeStepIdx: number) => void; - /** - * Update the steps in the flow - * - * activeStepIdx - new active step - */ - setActiveStep: (index: number) => void; + /** + * Update the steps in the flow + * + * activeStepIdx - new active step + */ + setActiveStep: (index: number) => void; - /** - * Set the loading boolean - * - * isLoading - toggle the loading true or false - */ - setIsLoading: (isLoading: boolean) => void; + /** + * Set the loading boolean + * + * isLoading - toggle the loading true or false + */ + setIsLoading: (isLoading: boolean) => void; }; /** diff --git a/packages/client/src/contexts/WorkspaceContext.tsx b/packages/client/src/contexts/WorkspaceContext.tsx index ac6cfdd33c..0efc19969d 100644 --- a/packages/client/src/contexts/WorkspaceContext.tsx +++ b/packages/client/src/contexts/WorkspaceContext.tsx @@ -1,18 +1,17 @@ -import { createContext } from 'react'; - -import { WorkspaceStore } from '@/stores'; +import { createContext } from "react"; +import type { WorkspaceStore } from "@/stores"; /** * Value */ export type WorkspaceContextType = { - /** Widgets available to all of the blocks */ - workspace: WorkspaceStore; + /** Widgets available to all of the blocks */ + workspace: WorkspaceStore; }; /** * Context */ export const WorkspaceContext = createContext( - undefined, + undefined, ); diff --git a/packages/client/src/contexts/index.ts b/packages/client/src/contexts/index.ts index 6811a6cdcf..74c7fd49d1 100644 --- a/packages/client/src/contexts/index.ts +++ b/packages/client/src/contexts/index.ts @@ -1,33 +1,42 @@ -import { DesignerContextType, DesignerContext } from './DesignerContext'; -import { EngineContextType, EngineContext } from './EngineContext'; -import { LLMContext, LLMContextType } from './LLMContext'; -import { MetamodelContextType, MetamodelContext } from './MetamodelContext'; -import { SettingsContextType, SettingsContext } from './SettingsContext'; -import { RootStoreContextType, RootStoreContext } from './RootStoreContext'; -import { StepperContext, StepperContextType } from './StepperContext'; -import { PageContextType, PageContext } from './PageContext'; -import { WorkspaceContextType, WorkspaceContext } from './WorkspaceContext'; +import { DesignerContext, type DesignerContextType } from "./DesignerContext"; +import { EngineContext, type EngineContextType } from "./EngineContext"; +import { LLMContext, type LLMContextType } from "./LLMContext"; +import { + MetamodelContext, + type MetamodelContextType, +} from "./MetamodelContext"; +import { PageContext, type PageContextType } from "./PageContext"; +import { + RootStoreContext, + type RootStoreContextType, +} from "./RootStoreContext"; +import { SettingsContext, type SettingsContextType } from "./SettingsContext"; +import { StepperContext, type StepperContextType } from "./StepperContext"; +import { + WorkspaceContext, + type WorkspaceContextType, +} from "./WorkspaceContext"; export type { - DesignerContextType, - EngineContextType, - LLMContextType, - MetamodelContextType, - RootStoreContextType, - SettingsContextType, - StepperContextType, - PageContextType, - WorkspaceContextType, + DesignerContextType, + EngineContextType, + LLMContextType, + MetamodelContextType, + RootStoreContextType, + SettingsContextType, + StepperContextType, + PageContextType, + WorkspaceContextType, }; export { - DesignerContext, - EngineContext, - LLMContext, - MetamodelContext, - RootStoreContext, - SettingsContext, - StepperContext, - PageContext, - WorkspaceContext, + DesignerContext, + EngineContext, + LLMContext, + MetamodelContext, + RootStoreContext, + SettingsContext, + StepperContext, + PageContext, + WorkspaceContext, }; diff --git a/packages/client/src/global.d.ts b/packages/client/src/global.d.ts index e40a7d9d4d..970b19301f 100644 --- a/packages/client/src/global.d.ts +++ b/packages/client/src/global.d.ts @@ -1,35 +1,35 @@ -declare module '*.png' { - const value: any; - export = value; +declare module "*.png" { + const value: any; + export = value; } -declare module '*.svg' { - const value: any; - export = value; +declare module "*.svg" { + const value: any; + export = value; } -declare module '*.jpg' { - const value: any; - export = value; +declare module "*.jpg" { + const value: any; + export = value; } -declare module '*.jpeg' { - const value: any; - export = value; +declare module "*.jpeg" { + const value: any; + export = value; } -declare module '*.gif' { - const value: any; - export = value; +declare module "*.gif" { + const value: any; + export = value; } -declare module '!!raw-loader!*' { - const contents: string; - export = contents; +declare module "!!raw-loader!*" { + const contents: string; + export = contents; } type DeepPartial = T extends object - ? { - [P in keyof T]?: DeepPartial; - } - : T; + ? { + [P in keyof T]?: DeepPartial; + } + : T; diff --git a/packages/client/src/hooks/index.ts b/packages/client/src/hooks/index.ts index 7d3bb1505c..2be0ef6528 100644 --- a/packages/client/src/hooks/index.ts +++ b/packages/client/src/hooks/index.ts @@ -1,29 +1,29 @@ -import { useAPI } from './useAPI'; -import { useCacheState } from './useCacheState'; -import { useEngine } from './useEngine'; -import { useLLM } from './useLLM'; -import { useMetamodel } from './useMetamodel'; -import { useRootStore } from './useRootStore'; -import { useSettings } from './useSettings'; -import { usePixel } from './usePixel'; -import { useDesigner } from './useDesigner'; -import { useStepper } from './useStepper'; -import { useWorkspace } from './useWorkspace'; -import { usePage } from './usePage'; -import { useBlockSettings } from './useBlockSettings'; +import { useAPI } from "./useAPI"; +import { useBlockSettings } from "./useBlockSettings"; +import { useCacheState } from "./useCacheState"; +import { useDesigner } from "./useDesigner"; +import { useEngine } from "./useEngine"; +import { useLLM } from "./useLLM"; +import { useMetamodel } from "./useMetamodel"; +import { usePage } from "./usePage"; +import { usePixel } from "./usePixel"; +import { useRootStore } from "./useRootStore"; +import { useSettings } from "./useSettings"; +import { useStepper } from "./useStepper"; +import { useWorkspace } from "./useWorkspace"; export { - useAPI, - useBlockSettings, - useCacheState, - useEngine, - useLLM, - useMetamodel, - useRootStore, - useSettings, - usePixel, - useDesigner, - useStepper, - useWorkspace, - usePage, + useAPI, + useBlockSettings, + useCacheState, + useEngine, + useLLM, + useMetamodel, + useRootStore, + useSettings, + usePixel, + useDesigner, + useStepper, + useWorkspace, + usePage, }; diff --git a/packages/client/src/hooks/useAPI.ts b/packages/client/src/hooks/useAPI.ts index 6b3a6db12f..b70dc7ad4d 100644 --- a/packages/client/src/hooks/useAPI.ts +++ b/packages/client/src/hooks/useAPI.ts @@ -1,29 +1,28 @@ -import { useState, useEffect, useCallback, useMemo } from 'react'; -import { useNotification } from '@semoss/ui'; - -import * as API from '@/api'; +import { useCallback, useEffect, useMemo, useState } from "react"; +import { useNotification } from "@semoss/ui"; +import * as API from "@/api"; type ApiType = typeof API; interface APIState { - /** Status of the api call */ - status: 'INITIAL' | 'LOADING' | 'SUCCESS' | 'ERROR'; - /** Data returned from the api call */ - data?: Awaited>; - /** Error returned from the api call */ - error?: Error; + /** Status of the api call */ + status: "INITIAL" | "LOADING" | "SUCCESS" | "ERROR"; + /** Data returned from the api call */ + data?: Awaited>; + /** Error returned from the api call */ + error?: Error; } interface APIConfig { - /** Initial Data */ - data: APIState['data']; + /** Initial Data */ + data: APIState["data"]; } interface useAPI extends APIState { - /** Refresh and reexecute the api */ - refresh: () => void; - /** Update the data with new information */ - update: (data: APIState['data']) => void; + /** Refresh and reexecute the api */ + refresh: () => void; + /** Update the data with new information */ + update: (data: APIState["data"]) => void; } /** @@ -34,117 +33,117 @@ interface useAPI extends APIState { * @returns Information about the api response */ export function useAPI( - api: [A, ...Parameters], - config?: Partial>, + api: [A, ...Parameters], + config?: Partial>, ): useAPI { - const notification = useNotification(); - - // store the initial config options - const options: APIConfig = useMemo(() => { - return { - data: undefined, - ...config, - }; - }, [config]); - - // store the state - const [count, setCount] = useState(0); - const [state, setState] = useState>(() => { - const s: APIState = { - status: 'INITIAL', - }; - - if (options.data !== undefined) { - s.data = options.data; - } - - return s; - }); - - /** - * Increment the count, triggering a refresh of the api - */ - const refresh = useCallback(() => { - setCount(count + 1); - }, [count]); - - /** - * Update the data with new data - */ - const update = useCallback( - (data: APIState['data']) => { - setState({ - ...state, - data: data, - }); - }, - [state], - ); - - // get the data - useEffect(() => { - // track if it has been cancelled - let isCancelled = false; - - const run = async () => { - // no api reset it - if (!api || api.length === 0) { - setState({ - status: 'INITIAL', - data: options.data, - }); - - return; - } - - setState({ - status: 'LOADING', - }); - - try { - const [func, ...args] = api; - - const response = await API[func].apply(null, args); - - // ignore if its cancelled - if (isCancelled) { - return; - } - - // set as success - setState({ - status: 'SUCCESS', - data: response, - }); - } catch (error) { - // ignore if its cancelled - if (isCancelled) { - return; - } - - notification.add({ - color: 'error', - message: error.message, - }); - - setState({ - status: 'ERROR', - error: error, - }); - } - }; - - // run it - run(); - - return () => { - isCancelled = true; - }; - }, [JSON.stringify(api), count]); - - return { - ...state, - refresh: refresh, - update: update, - }; + const notification = useNotification(); + + // store the initial config options + const options: APIConfig = useMemo(() => { + return { + data: undefined, + ...config, + }; + }, [config]); + + // store the state + const [count, setCount] = useState(0); + const [state, setState] = useState>(() => { + const s: APIState = { + status: "INITIAL", + }; + + if (options.data !== undefined) { + s.data = options.data; + } + + return s; + }); + + /** + * Increment the count, triggering a refresh of the api + */ + const refresh = useCallback(() => { + setCount(count + 1); + }, [count]); + + /** + * Update the data with new data + */ + const update = useCallback( + (data: APIState["data"]) => { + setState({ + ...state, + data: data, + }); + }, + [state], + ); + + // get the data + useEffect(() => { + // track if it has been cancelled + let isCancelled = false; + + const run = async () => { + // no api reset it + if (!api || api.length === 0) { + setState({ + status: "INITIAL", + data: options.data, + }); + + return; + } + + setState({ + status: "LOADING", + }); + + try { + const [func, ...args] = api; + + const response = await API[func].apply(null, args); + + // ignore if its cancelled + if (isCancelled) { + return; + } + + // set as success + setState({ + status: "SUCCESS", + data: response, + }); + } catch (error) { + // ignore if its cancelled + if (isCancelled) { + return; + } + + notification.add({ + color: "error", + message: error.message, + }); + + setState({ + status: "ERROR", + error: error, + }); + } + }; + + // run it + run(); + + return () => { + isCancelled = true; + }; + }, [JSON.stringify(api), count]); + + return { + ...state, + refresh: refresh, + update: update, + }; } diff --git a/packages/client/src/hooks/useBlockSettings.tsx b/packages/client/src/hooks/useBlockSettings.tsx index c0f5ce6ea0..b2b30c8e56 100644 --- a/packages/client/src/hooks/useBlockSettings.tsx +++ b/packages/client/src/hooks/useBlockSettings.tsx @@ -1,138 +1,137 @@ -import { useCallback } from 'react'; - +import { useCallback } from "react"; import { - Paths, - PathValue, - ActionMessages, - Block, - BlockDef, - ListenerActions, - useBlocks, -} from '@semoss/renderer'; + ActionMessages, + type Block, + type BlockDef, + type ListenerActions, + type Paths, + type PathValue, + useBlocks, +} from "@semoss/renderer"; /** * useBlockSettingsReturn */ interface useBlockSettingsReturn { - /** Data for the block */ - data: Block['data']; + /** Data for the block */ + data: Block["data"]; - /** Data for the block */ - listeners: Block['listeners']; + /** Data for the block */ + listeners: Block["listeners"]; - /** - * Dispatch a message to set data - * @param path - path of the data to set - * @param value - value of the data to set - */ - setData:

['data'], 4>>( - path: P, - value: PathValue, - ) => void; + /** + * Dispatch a message to set data + * @param path - path of the data to set + * @param value - value of the data to set + */ + setData:

["data"], 4>>( + path: P, + value: PathValue, + ) => void; - /** - * Dispatch a message to delete data - * @param path - path of the data to delete - */ - deleteData:

['data'], 4>>(path: P) => void; + /** + * Dispatch a message to delete data + * @param path - path of the data to delete + */ + deleteData:

["data"], 4>>(path: P) => void; - /** - * Dispatch a message to set the listeners - * @param listeners - listeners to attach to the block - */ - setListener: ( - listener: keyof Block['listeners'], - actions: ListenerActions[], - type?: 'sync' | 'async', - ) => void; + /** + * Dispatch a message to set the listeners + * @param listeners - listeners to attach to the block + */ + setListener: ( + listener: keyof Block["listeners"], + actions: ListenerActions[], + type?: "sync" | "async", + ) => void; } /** * Access methods for the block */ export const useBlockSettings = ( - id: string, + id: string, ): useBlockSettingsReturn => { - // get the store - const { state } = useBlocks(); + // get the store + const { state } = useBlocks(); - // get the block - const block = state.getBlock(id); + // get the block + const block = state.getBlock(id); - // get block - if (!block) { - throw Error(`Cannot find block ${id}`); - } + // get block + if (!block) { + throw Error(`Cannot find block ${id}`); + } - /** - * Dispatch a message to set data - * @param path - path of the data to set - * @param value - value of the data to set - */ - const setData = useCallback( -

['data'], 4>>( - path: P | null, - value: PathValue['data'], P>, - ): void => { - state.dispatch({ - message: ActionMessages.SET_BLOCK_DATA, - payload: { - id: id, - path: path, - value: value, - }, - }); - }, - [id], - ); + /** + * Dispatch a message to set data + * @param path - path of the data to set + * @param value - value of the data to set + */ + const setData = useCallback( +

["data"], 4>>( + path: P | null, + value: PathValue["data"], P>, + ): void => { + state.dispatch({ + message: ActionMessages.SET_BLOCK_DATA, + payload: { + id: id, + path: path, + value: value, + }, + }); + }, + [id], + ); - /** - * Dispatch a message to delete data - * @param path - path of the data to delete - */ - const deleteData = useCallback( -

['data'], 4>>(path: P | null): void => { - state.dispatch({ - message: ActionMessages.DELETE_BLOCK_DATA, - payload: { - id: id, - path: path, - }, - }); - }, - [], - ); + /** + * Dispatch a message to delete data + * @param path - path of the data to delete + */ + const deleteData = useCallback( +

["data"], 4>>(path: P | null): void => { + state.dispatch({ + message: ActionMessages.DELETE_BLOCK_DATA, + payload: { + id: id, + path: path, + }, + }); + }, + [], + ); - /** - * Dispatch a message to set the listeners - * @param listener - listener to add to the block - * @param actions - actions to add to the block - * - */ - const setListener = useCallback( - ( - listener: keyof Block['listeners'], - actions: ListenerActions[], - type: 'sync' | 'async', - ): void => { - state.dispatch({ - message: ActionMessages.SET_LISTENER, - payload: { - id: id, - listener: listener as string, - actions: actions, - type: type, - }, - }); - }, - [], - ); + /** + * Dispatch a message to set the listeners + * @param listener - listener to add to the block + * @param actions - actions to add to the block + * + */ + const setListener = useCallback( + ( + listener: keyof Block["listeners"], + actions: ListenerActions[], + type: "sync" | "async", + ): void => { + state.dispatch({ + message: ActionMessages.SET_LISTENER, + payload: { + id: id, + listener: listener as string, + actions: actions, + type: type, + }, + }); + }, + [], + ); - return { - data: block.data || {}, - listeners: block.listeners || {}, - setData: setData, - deleteData: deleteData, - setListener: setListener, - }; + return { + data: block.data || {}, + listeners: block.listeners || {}, + setData: setData, + deleteData: deleteData, + setListener: setListener, + }; }; diff --git a/packages/client/src/hooks/useCacheState.ts b/packages/client/src/hooks/useCacheState.ts index d8807de11d..93bafdd679 100644 --- a/packages/client/src/hooks/useCacheState.ts +++ b/packages/client/src/hooks/useCacheState.ts @@ -1,46 +1,46 @@ -import { useState } from 'react'; +import { useState } from "react"; type CacheState = { - state: T; + state: T; }; /** * Access state from the cache */ export const useCacheState = (initialState: T, name: string) => { - const key = `smss--${name}`; - - // set the data - const [state, setState] = useState(() => { - try { - const item = localStorage.getItem(key); - if (item) { - // try to get the state - const data = JSON.parse(item) as CacheState; - return data.state; - } - } catch (e) { - console.error(e); - } - - // return the inital state if not set from local storage - return initialState; - }); - - /** - * Handle changing of the data - */ - const onChange = (data: T) => { - // save to cache - const item: CacheState = { - state: data, - }; - - localStorage.setItem(key, JSON.stringify(item)); - - // update the state - setState(data); - }; - - return [state, onChange] as const; + const key = `smss--${name}`; + + // set the data + const [state, setState] = useState(() => { + try { + const item = localStorage.getItem(key); + if (item) { + // try to get the state + const data = JSON.parse(item) as CacheState; + return data.state; + } + } catch (e) { + console.error(e); + } + + // return the inital state if not set from local storage + return initialState; + }); + + /** + * Handle changing of the data + */ + const onChange = (data: T) => { + // save to cache + const item: CacheState = { + state: data, + }; + + localStorage.setItem(key, JSON.stringify(item)); + + // update the state + setState(data); + }; + + return [state, onChange] as const; }; diff --git a/packages/client/src/hooks/useDesigner.ts b/packages/client/src/hooks/useDesigner.ts index ab9e82f9a0..39423798fb 100644 --- a/packages/client/src/hooks/useDesigner.ts +++ b/packages/client/src/hooks/useDesigner.ts @@ -1,16 +1,15 @@ -import { useContext } from 'react'; - -import { DesignerContext, DesignerContextType } from '@/contexts'; +import { useContext } from "react"; +import { DesignerContext, type DesignerContextType } from "@/contexts"; /** * Access the current Engine Context * @returns the Engine Context */ export function useDesigner(): DesignerContextType { - const context = useContext(DesignerContext); - if (context === undefined) { - throw new Error('useDesigner must be used within DesignerProvider'); - } + const context = useContext(DesignerContext); + if (context === undefined) { + throw new Error("useDesigner must be used within DesignerProvider"); + } - return context; + return context; } diff --git a/packages/client/src/hooks/useEngine.tsx b/packages/client/src/hooks/useEngine.tsx index 79fd340c8a..243e29f6e3 100644 --- a/packages/client/src/hooks/useEngine.tsx +++ b/packages/client/src/hooks/useEngine.tsx @@ -1,16 +1,15 @@ -import { useContext } from 'react'; - -import { EngineContext, EngineContextType } from '@/contexts'; +import { useContext } from "react"; +import { EngineContext, type EngineContextType } from "@/contexts"; /** * Access the current Engine Context * @returns the Engine Context */ export function useEngine(): EngineContextType { - const context = useContext(EngineContext); - if (context === undefined) { - throw new Error('useEngine must be used within EngineContext.Provider'); - } + const context = useContext(EngineContext); + if (context === undefined) { + throw new Error("useEngine must be used within EngineContext.Provider"); + } - return context; + return context; } diff --git a/packages/client/src/hooks/useLLM.tsx b/packages/client/src/hooks/useLLM.tsx index 9f82bf480f..f8ad05f766 100644 --- a/packages/client/src/hooks/useLLM.tsx +++ b/packages/client/src/hooks/useLLM.tsx @@ -1,16 +1,15 @@ -import { useContext } from 'react'; - -import { LLMContext, LLMContextType } from '@/contexts'; +import { useContext } from "react"; +import { LLMContext, type LLMContextType } from "@/contexts"; /** * Access the current LLM Context * @returns the LLM Context */ export function useLLM(): LLMContextType { - const context = useContext(LLMContext); - if (context === undefined) { - throw new Error('useLLM must be used within LLMProvider'); - } + const context = useContext(LLMContext); + if (context === undefined) { + throw new Error("useLLM must be used within LLMProvider"); + } - return context; + return context; } diff --git a/packages/client/src/hooks/useMetamodel.ts b/packages/client/src/hooks/useMetamodel.ts index 693b347b87..72031d6e4a 100644 --- a/packages/client/src/hooks/useMetamodel.ts +++ b/packages/client/src/hooks/useMetamodel.ts @@ -1,16 +1,15 @@ -import { useContext } from 'react'; - -import { MetamodelContext, MetamodelContextType } from '@/contexts'; +import { useContext } from "react"; +import { MetamodelContext, type MetamodelContextType } from "@/contexts"; /** * Access the current Metamodel Context * @returns the Metamodel Context */ export function useMetamodel(): MetamodelContextType { - const context = useContext(MetamodelContext); - if (context === undefined) { - throw new Error('useMetamodel must be used within MetamodelProvider'); - } + const context = useContext(MetamodelContext); + if (context === undefined) { + throw new Error("useMetamodel must be used within MetamodelProvider"); + } - return context; + return context; } diff --git a/packages/client/src/hooks/usePage.ts b/packages/client/src/hooks/usePage.ts index d18d2ece2a..c0f30f6ce5 100644 --- a/packages/client/src/hooks/usePage.ts +++ b/packages/client/src/hooks/usePage.ts @@ -1,17 +1,16 @@ -import { useContext, useEffect } from 'react'; - -import { PageContext, PageContextType } from '@/contexts'; +import { useContext, useEffect } from "react"; +import { PageContext, type PageContextType } from "@/contexts"; interface usePageOptions { - /** - * Show the navbar logo - */ - showNavbarLogo?: boolean; - - /** - * Show the navbar logo - */ - showNavbarSearch?: boolean; + /** + * Show the navbar logo + */ + showNavbarLogo?: boolean; + + /** + * Show the navbar logo + */ + showNavbarSearch?: boolean; } /** @@ -19,36 +18,36 @@ interface usePageOptions { * @returns the Page Context */ export function usePage(options: usePageOptions = {}): PageContextType { - const context = useContext(PageContext); - if (context === undefined) { - throw new Error('usePage must be used within PageContext.Provider'); - } - - // show the logo if set - useEffect(() => { - if (!options || !options.hasOwnProperty('showNavbarLogo')) { - return; - } - - context.page.updateNavbarLogo(options.showNavbarLogo); - return () => { - // reset when navigating away - context.page.updateNavbarLogo(true); - }; - }, [options ? options.showNavbarLogo : null]); - - // show the search if set - useEffect(() => { - if (!options || !options.hasOwnProperty('showNavbarSearch')) { - return; - } - - context.page.updateNavbarSearch(options.showNavbarSearch); - return () => { - // reset when navigating away - context.page.updateNavbarSearch(true); - }; - }, [options ? options.showNavbarSearch : null]); - - return context; + const context = useContext(PageContext); + if (context === undefined) { + throw new Error("usePage must be used within PageContext.Provider"); + } + + // show the logo if set + useEffect(() => { + if (!options || !Object.hasOwn(options, "showNavbarLogo")) { + return; + } + + context.page.updateNavbarLogo(options.showNavbarLogo); + return () => { + // reset when navigating away + context.page.updateNavbarLogo(true); + }; + }, [options ? options.showNavbarLogo : null]); + + // show the search if set + useEffect(() => { + if (!options || !Object.hasOwn(options, "showNavbarSearch")) { + return; + } + + context.page.updateNavbarSearch(options.showNavbarSearch); + return () => { + // reset when navigating away + context.page.updateNavbarSearch(true); + }; + }, [options ? options.showNavbarSearch : null]); + + return context; } diff --git a/packages/client/src/hooks/usePixel.ts b/packages/client/src/hooks/usePixel.ts index 22cca4a597..654124b66e 100644 --- a/packages/client/src/hooks/usePixel.ts +++ b/packages/client/src/hooks/usePixel.ts @@ -1,30 +1,29 @@ -import { useState, useEffect, useCallback, useMemo } from 'react'; -import { useNotification } from '@semoss/ui'; - -import { useRootStore } from './useRootStore'; +import { useCallback, useEffect, useMemo, useState } from "react"; +import { useNotification } from "@semoss/ui"; +import { useRootStore } from "./useRootStore"; interface PixelState { - /** Status of the pixel call */ - status: 'INITIAL' | 'LOADING' | 'SUCCESS' | 'ERROR'; - /** Data returned from the pixel call */ - data?: D; - /** Error returned from the pixel call */ - error?: Error; + /** Status of the pixel call */ + status: "INITIAL" | "LOADING" | "SUCCESS" | "ERROR"; + /** Data returned from the pixel call */ + data?: D; + /** Error returned from the pixel call */ + error?: Error; } export interface PixelConfig { - /** Initial Data */ - data: D; + /** Initial Data */ + data: D; - /** Mangually process errors. Does not throw notifications */ - silent: boolean; + /** Mangually process errors. Does not throw notifications */ + silent: boolean; } interface usePixel extends PixelState { - /** Refresh and reexecute the pixel */ - refresh: () => void; - /** Update the data with new information */ - update: (data: D) => void; + /** Refresh and reexecute the pixel */ + refresh: () => void; + /** Update the data with new information */ + update: (data: D) => void; } /** @@ -35,127 +34,127 @@ interface usePixel extends PixelState { * @returns Information about the pixel response */ export function usePixel( - pixel: string, - config?: Partial>, - insightId?: string, + pixel: string, + config?: Partial>, + insightId?: string, ): usePixel { - const { monolithStore } = useRootStore(); - const notification = useNotification(); - - // store the initial config options - const options: PixelConfig = useMemo(() => { - return { - data: undefined, - silent: false, - ...config, - }; - }, [config]); - - // store the state - const [count, setCount] = useState(0); - const [state, setState] = useState>(() => { - const s: PixelState = { - status: 'INITIAL', - }; - - if (options.data !== undefined) { - s.data = options.data; - } - - return s; - }); - - /** - * Increment the count, triggering a refresh of the pixel - */ - const refresh = useCallback(() => { - setCount(count + 1); - }, [count]); - - /** - * Update the data with new data - */ - const update = useCallback( - (data: D) => { - setState({ - ...state, - data: data, - }); - }, - [state], - ); - - // get the data - useEffect(() => { - // no command reset it - if (!pixel) { - setState({ - status: 'INITIAL', - data: options.data, - }); - - return; - } - - // track if it has been cancelled - let isCancelled = false; - - setState({ - status: 'LOADING', - }); - - monolithStore - .runQuery(pixel, insightId) - .then((response) => { - // ignore if its cancelled - if (isCancelled) { - return; - } - - const { output, operationType } = response.pixelReturn[0]; - - // track the errors - if (operationType.indexOf('ERROR') > -1) { - const error = output as string; - - throw new Error(error); - } - - // set as success - setState({ - status: 'SUCCESS', - data: output as D, - }); - }) - .catch((error) => { - // ignore if its cancelled - if (isCancelled) { - return; - } - - if (!options.silent) { - notification.add({ - color: 'error', - message: error.message, - }); - } else { - console.log(error.message); - } - - setState({ - status: 'ERROR', - error: error, - }); - }); - - return () => { - isCancelled = true; - }; - }, [pixel, count]); - - return { - ...state, - refresh: refresh, - update: update, - }; + const { monolithStore } = useRootStore(); + const notification = useNotification(); + + // store the initial config options + const options: PixelConfig = useMemo(() => { + return { + data: undefined, + silent: false, + ...config, + }; + }, [config]); + + // store the state + const [count, setCount] = useState(0); + const [state, setState] = useState>(() => { + const s: PixelState = { + status: "INITIAL", + }; + + if (options.data !== undefined) { + s.data = options.data; + } + + return s; + }); + + /** + * Increment the count, triggering a refresh of the pixel + */ + const refresh = useCallback(() => { + setCount(count + 1); + }, [count]); + + /** + * Update the data with new data + */ + const update = useCallback( + (data: D) => { + setState({ + ...state, + data: data, + }); + }, + [state], + ); + + // get the data + useEffect(() => { + // no command reset it + if (!pixel) { + setState({ + status: "INITIAL", + data: options.data, + }); + + return; + } + + // track if it has been cancelled + let isCancelled = false; + + setState({ + status: "LOADING", + }); + + monolithStore + .runQuery(pixel, insightId) + .then((response) => { + // ignore if its cancelled + if (isCancelled) { + return; + } + + const { output, operationType } = response.pixelReturn[0]; + + // track the errors + if (operationType.indexOf("ERROR") > -1) { + const error = output as string; + + throw new Error(error); + } + + // set as success + setState({ + status: "SUCCESS", + data: output as D, + }); + }) + .catch((error) => { + // ignore if its cancelled + if (isCancelled) { + return; + } + + if (!options.silent) { + notification.add({ + color: "error", + message: error.message, + }); + } else { + console.log(error.message); + } + + setState({ + status: "ERROR", + error: error, + }); + }); + + return () => { + isCancelled = true; + }; + }, [pixel, count]); + + return { + ...state, + refresh: refresh, + update: update, + }; } diff --git a/packages/client/src/hooks/useRootStore.ts b/packages/client/src/hooks/useRootStore.ts index 052220b76a..012b3a0294 100644 --- a/packages/client/src/hooks/useRootStore.ts +++ b/packages/client/src/hooks/useRootStore.ts @@ -1,16 +1,15 @@ -import { useContext } from 'react'; - -import { RootStoreContext, RootStoreContextType } from '@/contexts'; +import { useContext } from "react"; +import { RootStoreContext, type RootStoreContextType } from "@/contexts"; /** * Access the current RootStore * @returns the RootStore */ export function useRootStore(): RootStoreContextType { - const context = useContext(RootStoreContext); - if (context === undefined) { - throw new Error('useRootStore must be used within RootStoreProvider'); - } + const context = useContext(RootStoreContext); + if (context === undefined) { + throw new Error("useRootStore must be used within RootStoreProvider"); + } - return context; + return context; } diff --git a/packages/client/src/hooks/useSettings.ts b/packages/client/src/hooks/useSettings.ts index aa1b119cb3..24f49508ab 100644 --- a/packages/client/src/hooks/useSettings.ts +++ b/packages/client/src/hooks/useSettings.ts @@ -1,16 +1,15 @@ -import { useContext } from 'react'; - -import { SettingsContext, SettingsContextType } from '@/contexts'; +import { useContext } from "react"; +import { SettingsContext, type SettingsContextType } from "@/contexts"; /** * Access the current Settings Context * @returns the Settings Context */ export function useSettings(): SettingsContextType { - const context = useContext(SettingsContext); - if (context === undefined) { - throw new Error('useSettings must be used within SettingsProvider'); - } + const context = useContext(SettingsContext); + if (context === undefined) { + throw new Error("useSettings must be used within SettingsProvider"); + } - return context; + return context; } diff --git a/packages/client/src/hooks/useStepper.ts b/packages/client/src/hooks/useStepper.ts index 8d6174f6f1..c14ae5f439 100644 --- a/packages/client/src/hooks/useStepper.ts +++ b/packages/client/src/hooks/useStepper.ts @@ -1,18 +1,17 @@ -import { useContext } from 'react'; - -import { StepperContext, StepperContextType } from '@/contexts'; +import { useContext } from "react"; +import { StepperContext, type StepperContextType } from "@/contexts"; /** * Access the current Stepper Context * @returns the Stepper Context */ export function useStepper(): StepperContextType { - const context = useContext(StepperContext); - if (context === undefined) { - throw new Error( - 'useStepper must be used within Stepper Context Provider', - ); - } + const context = useContext(StepperContext); + if (context === undefined) { + throw new Error( + "useStepper must be used within Stepper Context Provider", + ); + } - return context; + return context; } diff --git a/packages/client/src/hooks/useWorkspace.ts b/packages/client/src/hooks/useWorkspace.ts index d1c8f49749..6ec0a91cf6 100644 --- a/packages/client/src/hooks/useWorkspace.ts +++ b/packages/client/src/hooks/useWorkspace.ts @@ -1,18 +1,17 @@ -import { useContext } from 'react'; - -import { WorkspaceContext, WorkspaceContextType } from '@/contexts'; +import { useContext } from "react"; +import { WorkspaceContext, type WorkspaceContextType } from "@/contexts"; /** * Access the Workspace Context * @returns the Workspace Context */ export function useWorkspace(): WorkspaceContextType { - const context = useContext(WorkspaceContext); - if (context === undefined) { - throw new Error( - 'useWorkspace must be used within WorkspaceContext.Provider', - ); - } + const context = useContext(WorkspaceContext); + if (context === undefined) { + throw new Error( + "useWorkspace must be used within WorkspaceContext.Provider", + ); + } - return context; + return context; } diff --git a/packages/client/src/main.tsx b/packages/client/src/main.tsx index b61f4debc4..7049b13252 100644 --- a/packages/client/src/main.tsx +++ b/packages/client/src/main.tsx @@ -1,20 +1,19 @@ -import React from 'react'; -import { createRoot } from 'react-dom/client'; +import React from "react"; +import { createRoot } from "react-dom/client"; +import { App } from "./App"; +import { ErrorBoundary } from "./components/common"; -import { App } from './App'; -import { ErrorBoundary } from './components/common'; - -const container = document.getElementById('root'); +const container = document.getElementById("root"); const root = createRoot(container); root.render( - // - - - , - // , + > + + , + // , ); diff --git a/packages/client/src/pages/AuthenticatedLayout.tsx b/packages/client/src/pages/AuthenticatedLayout.tsx index 3bbe9ce201..156d51f514 100644 --- a/packages/client/src/pages/AuthenticatedLayout.tsx +++ b/packages/client/src/pages/AuthenticatedLayout.tsx @@ -1,23 +1,22 @@ -import { observer } from 'mobx-react-lite'; -import { Outlet, Navigate, useLocation } from 'react-router-dom'; - -import { useRootStore } from '@/hooks/'; +import { observer } from "mobx-react-lite"; +import { Navigate, Outlet, useLocation } from "react-router-dom"; +import { useRootStore } from "@/hooks/"; /** * Wrap the database routes and add additional funcitonality */ export const AuthenticatedLayout = observer(() => { - const { configStore } = useRootStore(); - const location = useLocation(); + const { configStore } = useRootStore(); + const location = useLocation(); - // wait till the config is authenticated to load the view - if (configStore.store.status === 'MISSING AUTHENTICATION') { - return ; - } + // wait till the config is authenticated to load the view + if (configStore.store.status === "MISSING AUTHENTICATION") { + return ; + } - return ( - <> - - - ); + return ( + <> + + + ); }); diff --git a/packages/client/src/pages/ErrorPage.tsx b/packages/client/src/pages/ErrorPage.tsx index ba6dacbd80..ca72cfcb2e 100644 --- a/packages/client/src/pages/ErrorPage.tsx +++ b/packages/client/src/pages/ErrorPage.tsx @@ -1,21 +1,21 @@ -import { useEffect, useRef, useState } from 'react'; -import { useLocation, useNavigate } from 'react-router-dom'; -import { Stack, Typography, styled } from '@semoss/ui'; -import Error from '@/assets/img/Error.svg'; +import { useEffect, useRef, useState } from "react"; +import { useLocation, useNavigate } from "react-router-dom"; +import { Stack, styled, Typography } from "@semoss/ui"; +import Error from "@/assets/img/Error.svg"; -const StyledContainer = styled('div')(({ theme }) => ({ - width: '100vw', - height: '100vh', - display: 'flex', - flexDirection: 'column', - gap: theme.spacing(1), - alignItems: 'center', - justifyContent: 'center', +const StyledContainer = styled("div")(({ theme }) => ({ + width: "100vw", + height: "100vh", + display: "flex", + flexDirection: "column", + gap: theme.spacing(1), + alignItems: "center", + justifyContent: "center", })); -const StyledImg = styled('img')(() => ({ - height: '25%', - maxHeight: '200px', +const StyledImg = styled("img")(() => ({ + height: "25%", + maxHeight: "200px", })); /** @@ -23,42 +23,42 @@ const StyledImg = styled('img')(() => ({ * Displays when there is an error that prevents the FE from loading and redirects back to the homepage */ export const ErrorPage = () => { - const [countdown, setCountdown] = useState(10); - const timer = useRef(); - const navigate = useNavigate(); - const { pathname } = useLocation(); + const [countdown, setCountdown] = useState(10); + const timer = useRef(); + const navigate = useNavigate(); + const { pathname } = useLocation(); - const isOnHomepage = pathname == '' || pathname == '/'; + const isOnHomepage = pathname == "" || pathname == "/"; - useEffect(() => { - if (!isOnHomepage) { - timer.current = setInterval(() => { - setCountdown((countdown) => countdown - 1); - }, 1000); - } - }, []); + useEffect(() => { + if (!isOnHomepage) { + timer.current = setInterval(() => { + setCountdown((countdown) => countdown - 1); + }, 1000); + } + }, []); - useEffect(() => { - if (countdown < 1) { - clearInterval(timer.current); - navigate('/'); - } - }, [countdown]); + useEffect(() => { + if (countdown < 1) { + clearInterval(timer.current); + navigate("/"); + } + }, [countdown]); - return ( - - - Something went wrong! - - We're working hard to fix it. If the issue persists, please - reach out and let us know. - - {!isOnHomepage && ( - - Taking you back to the home page in {countdown} second - {countdown == 1 ? '' : 's'}... - - )} - - ); + return ( + + + Something went wrong! + + We're working hard to fix it. If the issue persists, please + reach out and let us know. + + {!isOnHomepage && ( + + Taking you back to the home page in {countdown} second + {countdown == 1 ? "" : "s"}... + + )} + + ); }; diff --git a/packages/client/src/pages/LoginPage.tsx b/packages/client/src/pages/LoginPage.tsx index 06fa5c1f9d..1e6ede0d68 100644 --- a/packages/client/src/pages/LoginPage.tsx +++ b/packages/client/src/pages/LoginPage.tsx @@ -1,1358 +1,1347 @@ -import { useEffect, useState } from 'react'; -import { observer } from 'mobx-react-lite'; -import { Navigate, useLocation, Location } from 'react-router-dom'; -import { useForm, Controller } from 'react-hook-form'; -import GIF from '@/assets/img/login-gif.gif'; - +import { observer } from "mobx-react-lite"; +import { useEffect, useState } from "react"; +import { Controller, useForm } from "react-hook-form"; +import { type Location, Navigate, useLocation } from "react-router-dom"; import { - styled, - Alert, - Button, - Stack, - Snackbar, - LinearProgress, - TextField, - Typography, - Divider, - Box, - ButtonGroup, - Modal, - Tooltip, -} from '@semoss/ui'; - -import { useRootStore } from '@/hooks'; + Alert, + Box, + Button, + ButtonGroup, + Divider, + LinearProgress, + Modal, + Snackbar, + Stack, + styled, + TextField, + Tooltip, + Typography, +} from "@semoss/ui"; +import GIF from "@/assets/img/login-gif.gif"; +import { useRootStore } from "@/hooks"; -const StyledMain = styled('div')(({ theme }) => ({ - display: 'flex', - flexDirection: 'column', - height: '100vh', - width: '100vw', - background: theme.palette.background.paper, +const StyledMain = styled("div")(({ theme }) => ({ + display: "flex", + flexDirection: "column", + height: "100vh", + width: "100vw", + background: theme.palette.background.paper, })); -const StyledRow = styled('div')(() => ({ - flex: '1', - display: 'flex', - flexDirection: 'row', - position: 'relative', - width: '100%', - overflow: 'hidden', +const StyledRow = styled("div")(() => ({ + flex: "1", + display: "flex", + flexDirection: "row", + position: "relative", + width: "100%", + overflow: "hidden", })); const StyledProgress = styled(LinearProgress)(() => ({ - width: '100%', + width: "100%", })); -const StyledScroll = styled('div')(({ theme }) => ({ - flexShrink: 0, - position: 'relative', - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - zIndex: 1, - background: theme.palette.background.paper, - overflowY: 'auto', - overflowX: 'hidden', - [theme.breakpoints.down('md')]: { - height: '100%', - width: '100%', - }, +const StyledScroll = styled("div")(({ theme }) => ({ + flexShrink: 0, + position: "relative", + display: "flex", + flexDirection: "column", + alignItems: "center", + zIndex: 1, + background: theme.palette.background.paper, + overflowY: "auto", + overflowX: "hidden", + [theme.breakpoints.down("md")]: { + height: "100%", + width: "100%", + }, })); -const StyledContent = styled('div')(({ theme }) => ({ - display: 'flex', - flexDirection: 'column', - gap: theme.spacing(3), - width: '610px', - marginTop: theme.spacing(18), // 144px - marginBottom: theme.spacing(2), // 16px - marginLeft: theme.spacing(13.5), // 108px - marginRight: theme.spacing(13.5), // 108px - [theme.breakpoints.down('md')]: { - margin: 0, - padding: theme.spacing(4), - maxWidth: '610px', - width: '100%', - }, +const StyledContent = styled("div")(({ theme }) => ({ + display: "flex", + flexDirection: "column", + gap: theme.spacing(3), + width: "610px", + marginTop: theme.spacing(18), // 144px + marginBottom: theme.spacing(2), // 16px + marginLeft: theme.spacing(13.5), // 108px + marginRight: theme.spacing(13.5), // 108px + [theme.breakpoints.down("md")]: { + margin: 0, + padding: theme.spacing(4), + maxWidth: "610px", + width: "100%", + }, })); -const StyledGradient = styled('div')(({ theme }) => ({ - height: '100%', - width: theme.spacing(42), // 336px - background: - 'linear-gradient(90deg, #FFF 0%, rgba(255, 255, 255, 0.00) 100%)', - zIndex: 1, +const StyledGradient = styled("div")(({ theme }) => ({ + height: "100%", + width: theme.spacing(42), // 336px + background: + "linear-gradient(90deg, #FFF 0%, rgba(255, 255, 255, 0.00) 100%)", + zIndex: 1, })); -const StyledImageHolder = styled('div')(() => ({ - position: 'absolute', - top: '0px', - right: '0px', - bottom: '0px', - overflow: 'hidden', - zIndex: 0, +const StyledImageHolder = styled("div")(() => ({ + position: "absolute", + top: "0px", + right: "0px", + bottom: "0px", + overflow: "hidden", + zIndex: 0, })); -const StyledImage = styled('img')(() => ({ - height: '100%', - // width: '100%', - objectFit: 'cover', +const StyledImage = styled("img")(() => ({ + height: "100%", + // width: '100%', + objectFit: "cover", })); const StyledAction = styled(Button)({ - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - overflow: 'hidden', + display: "flex", + alignItems: "center", + justifyContent: "center", + overflow: "hidden", }); -const StyledActionBox = styled('div')({ - display: 'flex', - alignItems: 'center', - gap: '16px', - padding: '4px', +const StyledActionBox = styled("div")({ + display: "flex", + alignItems: "center", + gap: "16px", + padding: "4px", }); // const StyledActionImage = styled('img')(({ theme }) => ({ // height: theme.spacing(3), // })); -const StyledActionText = styled('span')(() => ({ - fontFamily: 'Inter', - fontSize: '14px', - fontStyle: 'normal', - fontWeight: 500, - lineHeight: '24px', - letterSpacing: '0.4px', - color: '#000', +const StyledActionText = styled("span")(() => ({ + fontFamily: "Inter", + fontSize: "14px", + fontStyle: "normal", + fontWeight: 500, + lineHeight: "24px", + letterSpacing: "0.4px", + color: "#000", })); const StyledDivider = styled(Divider)({ - background: 'transparent', + background: "transparent", }); const StyledDividerBox = styled(Box)({ - color: '#000', - fontFeatureSettings: '"clig" off, "liga" off', - fontFamily: 'Inter', - fontSize: '16px', - fontStyle: 'normal', - fontWeight: 700, - lineHeight: '150%' /* 24px */, - letterSpacing: ' 0.15px', + color: "#000", + fontFeatureSettings: '"clig" off, "liga" off', + fontFamily: "Inter", + fontSize: "16px", + fontStyle: "normal", + fontWeight: 700, + lineHeight: "150%" /* 24px */, + letterSpacing: " 0.15px", }); const StyledButtonGroup = styled(ButtonGroup)({ - '.MuiButtonGroup-grouped': { - borderColor: '#fff', - }, + ".MuiButtonGroup-grouped": { + borderColor: "#fff", + }, }); const StyledButtonGroupItem = styled(ButtonGroup.Item, { - shouldForwardProp: (prop) => prop !== 'selected', + shouldForwardProp: (prop) => prop !== "selected", })<{ - /** Track if Button is selected */ - selected: boolean; + /** Track if Button is selected */ + selected: boolean; }>(({ theme, selected }) => ({ - color: selected ? theme.palette.common.white : theme.palette.primary.main, - backgroundColor: selected - ? theme.palette.primary.main - : theme.palette.common.white, - '&:hover': { - backgroundColor: selected ? theme.palette.primary.dark : '', - borderColor: theme.palette.common.white, - }, + color: selected ? theme.palette.common.white : theme.palette.primary.main, + backgroundColor: selected + ? theme.palette.primary.main + : theme.palette.common.white, + "&:hover": { + backgroundColor: selected ? theme.palette.primary.dark : "", + borderColor: theme.palette.common.white, + }, })); const StyledRegisterNowBox = styled(Box)({ - display: 'flex', - align: 'center', - alignItems: 'center', - justifyContent: 'center', + display: "flex", + align: "center", + alignItems: "center", + justifyContent: "center", }); const StyledLogoContainer = styled(Stack)(({ theme }) => ({ - marginBottom: theme.spacing(1), + marginBottom: theme.spacing(1), })); const StyledTitle = styled(Typography)(({ theme }) => ({ - marginBottom: theme.spacing(1), + marginBottom: theme.spacing(1), })); const StyledInstructions = styled(Typography)(({ theme }) => ({ - marginBottom: theme.spacing(4), + marginBottom: theme.spacing(4), })); const StyledButtonText = styled(Button)({ - fontFamily: 'Inter', - fontSize: '15px', - fontStyle: 'normal', - fontWeight: 600, - lineHeight: '26px' /* 173.333% */, - letterSpacing: '0.46px', + fontFamily: "Inter", + fontSize: "15px", + fontStyle: "normal", + fontWeight: 600, + lineHeight: "26px" /* 173.333% */, + letterSpacing: "0.46px", }); const StyledGoBackBox = styled(Box)({ - display: 'flex', - justifyContent: 'space-between', + display: "flex", + justifyContent: "space-between", }); interface TypeUserLogin { - USERNAME: string; - PASSWORD: string; - REMEMBER_LOGIN: boolean; - OTP_CONFIRM: string; + USERNAME: string; + PASSWORD: string; + REMEMBER_LOGIN: boolean; + OTP_CONFIRM: string; } interface TypeUserRegister { - FIRST_NAME: ''; - LAST_NAME: ''; - USERNAME: ''; - EMAIL: ''; - PHONE: ''; - EXTENTION: ''; - COUNTRY_CODE: ''; - PASSWORD: ''; - PASSWORD_CONFIRMATION: ''; + FIRST_NAME: ""; + LAST_NAME: ""; + USERNAME: ""; + EMAIL: ""; + PHONE: ""; + EXTENTION: ""; + COUNTRY_CODE: ""; + PASSWORD: ""; + PASSWORD_CONFIRMATION: ""; } /** * LoginPage */ export const LoginPage = observer(() => { - const { configStore } = useRootStore(); - const location = useLocation(); + const { configStore } = useRootStore(); + const location = useLocation(); - const [forgotPassword, setForgotPassword] = useState(false); - const [loginType, setLoginType] = useState< - 'native' | 'ldap' | 'linotp' | '' - >(''); - const [register, setRegister] = useState(false); - const [showOTPCodeField, setShowOTPCodeField] = useState(false); - const [snackbar, setSnackbar] = useState<{ - open: boolean; - message: string; - color: 'success' | 'info' | 'warning' | 'error'; - }>({ - open: false, - message: '', - color: 'success', - }); - const [error, setError] = useState(''); - const [success, setSuccess] = useState(''); - const [isLoading, setIsLoading] = useState(false); + const [forgotPassword, setForgotPassword] = useState(false); + const [loginType, setLoginType] = useState< + "native" | "ldap" | "linotp" | "" + >(""); + const [register, setRegister] = useState(false); + const [showOTPCodeField, setShowOTPCodeField] = useState(false); + const [snackbar, setSnackbar] = useState<{ + open: boolean; + message: string; + color: "success" | "info" | "warning" | "error"; + }>({ + open: false, + message: "", + color: "success", + }); + const [error, setError] = useState(""); + const [success, setSuccess] = useState(""); + const [isLoading, setIsLoading] = useState(false); - const { - control, - handleSubmit, - formState: { errors: formErrors }, - } = useForm({ - mode: 'onChange', - defaultValues: { - USERNAME: '', - PASSWORD: '', - REMEMBER_LOGIN: false, - OTP_CONFIRM: '', - }, - }); + const { + control, + handleSubmit, + formState: { errors: formErrors }, + } = useForm({ + mode: "onChange", + defaultValues: { + USERNAME: "", + PASSWORD: "", + REMEMBER_LOGIN: false, + OTP_CONFIRM: "", + }, + }); - const { - control: registerControl, - handleSubmit: registerSubmit, - watch, - formState: { errors }, - reset, - } = useForm({ - mode: 'onChange', - defaultValues: { - FIRST_NAME: '', - LAST_NAME: '', - USERNAME: '', - EMAIL: '', - PHONE: '', - EXTENTION: '', - COUNTRY_CODE: '', - PASSWORD: '', - PASSWORD_CONFIRMATION: '', - }, - }); + const { + control: registerControl, + handleSubmit: registerSubmit, + watch, + formState: { errors }, + reset, + } = useForm({ + mode: "onChange", + defaultValues: { + FIRST_NAME: "", + LAST_NAME: "", + USERNAME: "", + EMAIL: "", + PHONE: "", + EXTENTION: "", + COUNTRY_CODE: "", + PASSWORD: "", + PASSWORD_CONFIRMATION: "", + }, + }); - const regPassword = watch('PASSWORD'); + const regPassword = watch("PASSWORD"); - const regPasswordRules = { - length: regPassword.length >= 8, - upper: /[A-Z]/.test(regPassword), - lower: /[a-z]/.test(regPassword), - special: /[!@#$%^&*]/.test(regPassword), - }; + const regPasswordRules = { + length: regPassword.length >= 8, + upper: /[A-Z]/.test(regPassword), + lower: /[a-z]/.test(regPassword), + special: /[!@#$%^&*]/.test(regPassword), + }; - const passwordTooltipContent = ( - - • At least 8 characters - • One uppercase letter - • One lowercase letter - - • One special character [!, @, #, $, %, ^, &, *] - - - ); + const passwordTooltipContent = ( + + • At least 8 characters + • One uppercase letter + • One lowercase letter + + • One special character [!, @, #, $, %, ^, &, *] + + + ); - // get a map of all providers - const availableProvidersMap: Record< - string, - { - provider: string; - label: string; - name: string; - isOauth: boolean; - } - > = configStore.store.config.availableProviders.reduce((acc, val) => { - acc[val.provider] = acc; + // get a map of all providers + const availableProvidersMap: Record< + string, + { + provider: string; + label: string; + name: string; + isOauth: boolean; + } + > = configStore.store.config.availableProviders.reduce((acc, val) => { + acc[val.provider] = acc; - return acc; - }, {}); + return acc; + }, {}); - // check if there is oAuth - const hasOAuth = configStore.store.config.availableProviders.some( - (val) => val.isOauth, - ); + // check if there is oAuth + const hasOAuth = configStore.store.config.availableProviders.some( + (val) => val.isOauth, + ); - const isNative = Object.prototype.hasOwnProperty.call( - availableProvidersMap, - 'native', - ), - isLdap = Object.prototype.hasOwnProperty.call( - availableProvidersMap, - 'ldap', - ), - isLinOTP = Object.prototype.hasOwnProperty.call( - availableProvidersMap, - 'linotp', - ); + const isNative = Object.hasOwn(availableProvidersMap, "native"), + isLdap = Object.hasOwn(availableProvidersMap, "ldap"), + isLinOTP = Object.hasOwn(availableProvidersMap, "linotp"); - // check if it requires username or password - const hasUsernamePassword = isNative || isLdap || isLinOTP; + // check if it requires username or password + const hasUsernamePassword = isNative || isLdap || isLinOTP; - const hasMoreThanOneUserNamePassword = - (isNative && isLdap) || (isNative && isLinOTP) || (isLdap && isLinOTP); + const hasMoreThanOneUserNamePassword = + (isNative && isLdap) || (isNative && isLinOTP) || (isLdap && isLinOTP); - // set initial selected login type from config. - useEffect(() => { - if (isNative) { - setLoginType('native'); - } else if (isLdap) { - setLoginType('ldap'); - } else if (isLinOTP) { - setLoginType('linotp'); - } - }, [isNative, isLdap, isLinOTP]); + // set initial selected login type from config. + useEffect(() => { + if (isNative) { + setLoginType("native"); + } else if (isLdap) { + setLoginType("ldap"); + } else if (isLinOTP) { + setLoginType("linotp"); + } + }, [isNative, isLdap, isLinOTP]); - /** - * Allow the user to login - */ - const login = handleSubmit( - async (data: TypeUserLogin): Promise => { - // turn on loading - setIsLoading(true); - setSuccess(''); + /** + * Allow the user to login + */ + const login = handleSubmit( + async (data: TypeUserLogin): Promise => { + // turn on loading + setIsLoading(true); + setSuccess(""); - if (!data.USERNAME || !data.PASSWORD) { - setError('Username and Password is Required'); - return; - } + if (!data.USERNAME || !data.PASSWORD) { + setError("Username and Password is Required"); + return; + } - if (!showOTPCodeField) { - if (loginType === 'native') { - await configStore - .login(data.USERNAME, data.PASSWORD) - .then(() => { - // noop - }) - .catch((error) => { - setError(error.message); - }) - .finally(() => { - // turn off loading - setIsLoading(false); - }); - } - if (loginType === 'ldap') { - await configStore - .loginLDAP(data.USERNAME, data.PASSWORD) - .then(() => { - // noop - }) - .catch((error) => { - setError(error.message); - }) - .finally(() => { - // turn off loading - setIsLoading(false); - }); - } - if (loginType === 'linotp') { - await configStore - .loginOTP(data.USERNAME, data.PASSWORD) - .then(() => { - // noop - setShowOTPCodeField(true); - }) - .catch((error) => { - setError(error.message); - }) - .finally(() => { - // turn off loading - setIsLoading(false); - }); - } - } - if (showOTPCodeField) { - await configStore - .confirmOTP(data.OTP_CONFIRM) - .then(() => { - // noop - }) - .catch((error) => { - setError(error.message); - }) - .finally(() => { - // turn off loading - setIsLoading(false); - }); - setShowOTPCodeField(true); - } - }, - ); + if (!showOTPCodeField) { + if (loginType === "native") { + await configStore + .login(data.USERNAME, data.PASSWORD) + .then(() => { + // noop + }) + .catch((error) => { + setError(error.message); + }) + .finally(() => { + // turn off loading + setIsLoading(false); + }); + } + if (loginType === "ldap") { + await configStore + .loginLDAP(data.USERNAME, data.PASSWORD) + .then(() => { + // noop + }) + .catch((error) => { + setError(error.message); + }) + .finally(() => { + // turn off loading + setIsLoading(false); + }); + } + if (loginType === "linotp") { + await configStore + .loginOTP(data.USERNAME, data.PASSWORD) + .then(() => { + // noop + setShowOTPCodeField(true); + }) + .catch((error) => { + setError(error.message); + }) + .finally(() => { + // turn off loading + setIsLoading(false); + }); + } + } + if (showOTPCodeField) { + await configStore + .confirmOTP(data.OTP_CONFIRM) + .then(() => { + // noop + }) + .catch((error) => { + setError(error.message); + }) + .finally(() => { + // turn off loading + setIsLoading(false); + }); + setShowOTPCodeField(true); + } + }, + ); - /** - * Allow the user to login - */ - const registerAccount = registerSubmit( - async (data: TypeUserRegister): Promise => { - // turn on loading - setIsLoading(true); + /** + * Allow the user to login + */ + const registerAccount = registerSubmit( + async (data: TypeUserRegister): Promise => { + // turn on loading + setIsLoading(true); - if ( - !data.USERNAME || - !data.PASSWORD || - !data.PASSWORD_CONFIRMATION || - !data.FIRST_NAME || - !data.LAST_NAME || - !data.EMAIL - ) { - setError( - 'Username, password, password confirmation, email, first and last name are required', - ); - setIsLoading(false); - return; - } + if ( + !data.USERNAME || + !data.PASSWORD || + !data.PASSWORD_CONFIRMATION || + !data.FIRST_NAME || + !data.LAST_NAME || + !data.EMAIL + ) { + setError( + "Username, password, password confirmation, email, first and last name are required", + ); + setIsLoading(false); + return; + } - if (data.PASSWORD !== data.PASSWORD_CONFIRMATION) { - setError('Passwords do not match'); - setIsLoading(false); - return; - } + if (data.PASSWORD !== data.PASSWORD_CONFIRMATION) { + setError("Passwords do not match"); + setIsLoading(false); + return; + } - await configStore - .register( - `${data.FIRST_NAME} ${data.LAST_NAME}`, - data.USERNAME, - data.EMAIL, - data.PASSWORD, - data.PHONE, - data.EXTENTION, - data.COUNTRY_CODE, - ) - .then((res) => { - if (res) { - setError(''); - setRegister(false); - setSuccess( - 'Account registration successful. Log in below.', - ); - reset(); - } - }) - .catch((error) => { - setIsLoading(false); - setError(error.message); - }) - .finally(() => { - // turn off loading - setIsLoading(false); - }); - }, - ); + await configStore + .register( + `${data.FIRST_NAME} ${data.LAST_NAME}`, + data.USERNAME, + data.EMAIL, + data.PASSWORD, + data.PHONE, + data.EXTENTION, + data.COUNTRY_CODE, + ) + .then((res) => { + if (res) { + setError(""); + setRegister(false); + setSuccess( + "Account registration successful. Log in below.", + ); + reset(); + } + }) + .catch((error) => { + setIsLoading(false); + setError(error.message); + }) + .finally(() => { + // turn off loading + setIsLoading(false); + }); + }, + ); - /** - * Login with oauth - * @param provider - provider to oauth with - */ - const oauth = async (provider: string) => { - // turn on loading - setIsLoading(true); + /** + * Login with oauth + * @param provider - provider to oauth with + */ + const oauth = async (provider: string) => { + // turn on loading + setIsLoading(true); - await configStore - .oauth(provider) - .then(() => { - // turn off loading - setIsLoading(false); + await configStore + .oauth(provider) + .then(() => { + // turn off loading + setIsLoading(false); - // noop - // (handled by the configStore) + // noop + // (handled by the configStore) - setSnackbar({ - open: true, - message: `Successfully logged in`, - color: 'success', - }); - }) - .catch((error) => { - // turn off loading - setIsLoading(false); + setSnackbar({ + open: true, + message: `Successfully logged in`, + color: "success", + }); + }) + .catch((error) => { + // turn off loading + setIsLoading(false); - setError(error.message); + setError(error.message); - setSnackbar({ - open: true, - message: error.message, - color: 'error', - }); - }); - }; + setSnackbar({ + open: true, + message: error.message, + color: "error", + }); + }); + }; - // get the path the user is coming from - const path = (location.state as { from: Location })?.from?.pathname || '/'; + // get the path the user is coming from + const path = (location.state as { from: Location })?.from?.pathname || "/"; - // navigate if already logged in - if (configStore.store.status === 'SUCCESS') { - return ; - } + // navigate if already logged in + if (configStore.store.status === "SUCCESS") { + return ; + } - return ( - <> - { - setSnackbar({ - open: false, - message: '', - color: 'success', - }); - }} - > - - {snackbar.message} - - - - - - -

- - {configStore.theme.logo ? ( - - ) : null} - - {configStore.theme.name} - - - Welcome! - - {register - ? 'Register below' - : 'Log in below'} - -
- {!register && hasMoreThanOneUserNamePassword && ( - - {isNative && ( - { - setLoginType('native'); - setSuccess(''); - setError(''); - }} - selected={loginType === 'native'} - data-testid={ - 'loginPage-button-native' - } - > - Native - - )} - {isLdap && ( - { - setLoginType('ldap'); - setSuccess(''); - setError(''); - }} - selected={loginType === 'ldap'} - data-testid={ - 'loginPage-button-ldap' - } - > - LDAP - - )} - {isLinOTP && ( - { - setLoginType('linotp'); - setSuccess(''); - setError(''); - }} - selected={loginType === 'linotp'} - data-testid={ - 'loginPage-button-linotp' - } - > - LinOTP - - )} - - )} - {error && ( - - {error} - - )} - {success && ( - - {success} - - )} -
- - {hasUsernamePassword && ( - <> - {!showOTPCodeField && register && ( - <> - { - return ( - - field.onChange( - e - .target - .value, - ) - } - inputProps={{ - 'data-testid': - 'loginPage-textField-firstNameRegister', - }} - error={ - !!errors.FIRST_NAME - } - helperText={ - errors - .FIRST_NAME - ?.message - } - /> - ); - }} - /> - { - return ( - - field.onChange( - e - .target - .value, - ) - } - inputProps={{ - 'data-testid': - 'loginPage-textField-lastNameRegister', - }} - error={ - !!errors.LAST_NAME - } - helperText={ - errors - .LAST_NAME - ?.message - } - /> - ); - }} - /> - { - return ( - - field.onChange( - e - .target - .value, - ) - } - inputProps={{ - 'data-testid': - 'loginPage-textField-usernameRegister', - }} - error={ - !!errors.USERNAME - } - helperText={ - errors - .USERNAME - ?.message - } - /> - ); - }} - /> - { - return ( - - field.onChange( - e - .target - .value, - ) - } - inputProps={{ - 'data-testid': - 'loginPage-textField-emailRegister', - }} - error={ - !!errors.EMAIL - } - helperText={ - errors - .EMAIL - ?.message - } - /> - ); - }} - /> - { - return ( - - field.onChange( - e - .target - .value, - ) - } - inputProps={{ - 'data-testid': - 'loginPage-textField-phone', - }} - error={ - !!errors.PHONE - } - helperText={ - errors - .PHONE - ?.message - } - /> - ); - }} - /> - { - return ( - - field.onChange( - e - .target - .value, - ) - } - inputProps={{ - 'data-testid': - 'loginPage-textField-extension', - }} - /> - ); - }} - /> - { - return ( - - field.onChange( - e - .target - .value, - ) - } - inputProps={{ - 'data-testid': - 'loginPage-textField-countryCode', - }} - /> - ); - }} - /> - { - if ( - !regPasswordRules.length - ) - return 'Minimum 8 characters'; - if ( - !regPasswordRules.upper - ) - return 'At least one uppercase letter'; - if ( - !regPasswordRules.lower - ) - return 'At least one lowercase letter'; - if ( - !regPasswordRules.special - ) - return 'At least one special character'; - return true; - }, - }} - render={({ field }) => { - return ( - - - field.onChange( - e - .target - .value, - ) - } - inputProps={{ - 'data-testid': - 'loginPage-textField-passwordRegister', - }} - /> - - ); - }} - /> - - value === - regPassword || - 'Passwords do not match', - }} - render={({ field }) => { - return ( - - field.onChange( - e - .target - .value, - ) - } - inputProps={{ - 'data-testid': - 'loginPage-textField-passwordConfirm', - }} - /> - ); - }} - /> - - - - - - )} - {!showOTPCodeField && !register && ( - <> - { - return ( - - field.onChange( - e - .target - .value, - ) - } - inputProps={{ - 'data-testid': - 'loginPage-textField-username', - }} - error={ - !!formErrors.USERNAME - } - helperText={ - formErrors - .USERNAME - ?.message - } - /> - ); - }} - /> - { - return ( - - field.onChange( - e - .target - .value, - ) - } - inputProps={{ - 'data-testid': - 'loginPage-textField-password', - }} - error={ - !!formErrors.PASSWORD - } - helperText={ - formErrors - .PASSWORD - ?.message - } - /> - ); - }} - /> - - )} - {showOTPCodeField && ( - { - return ( - - field.onChange( - e.target - .value, - ) - } - inputProps={{ - 'data-testid': - 'loginPage-textField-otpCode', - }} - /> - ); - }} - /> - )} - {!register && ( - <> - - {configStore.store.config - .nativeRegistration && ( - - Don't have an - account?{' '} - { - setRegister( - true, - ); - setError( - '', - ); - }} - data-testid={ - 'loginPage-button-registerPage' - } - > - Register Now - - - )} - - )} - - )} - {!register && ( - <> - {hasUsernamePassword && - hasOAuth && ( - <> - - - or - - - - )} - {configStore.store.config.availableProviders.map( - (p) => { - // skip ones that aren't oauth - if (!p.isOauth) { - return null; - } + return ( + <> + { + setSnackbar({ + open: false, + message: "", + color: "success", + }); + }} + > + + {snackbar.message} + + + + + + +
+ + {configStore.theme.logo ? ( + + ) : null} + + {configStore.theme.name} + + + Welcome! + + {register + ? "Register below" + : "Log in below"} + +
+ {!register && hasMoreThanOneUserNamePassword && ( + + {isNative && ( + { + setLoginType("native"); + setSuccess(""); + setError(""); + }} + selected={loginType === "native"} + data-testid={ + "loginPage-button-native" + } + > + Native + + )} + {isLdap && ( + { + setLoginType("ldap"); + setSuccess(""); + setError(""); + }} + selected={loginType === "ldap"} + data-testid={ + "loginPage-button-ldap" + } + > + LDAP + + )} + {isLinOTP && ( + { + setLoginType("linotp"); + setSuccess(""); + setError(""); + }} + selected={loginType === "linotp"} + data-testid={ + "loginPage-button-linotp" + } + > + LinOTP + + )} + + )} + {error && ( + + {error} + + )} + {success && ( + + {success} + + )} + + + {hasUsernamePassword && ( + <> + {!showOTPCodeField && register && ( + <> + { + return ( + + field.onChange( + e + .target + .value, + ) + } + inputProps={{ + "data-testid": + "loginPage-textField-firstNameRegister", + }} + error={ + !!errors.FIRST_NAME + } + helperText={ + errors + .FIRST_NAME + ?.message + } + /> + ); + }} + /> + { + return ( + + field.onChange( + e + .target + .value, + ) + } + inputProps={{ + "data-testid": + "loginPage-textField-lastNameRegister", + }} + error={ + !!errors.LAST_NAME + } + helperText={ + errors + .LAST_NAME + ?.message + } + /> + ); + }} + /> + { + return ( + + field.onChange( + e + .target + .value, + ) + } + inputProps={{ + "data-testid": + "loginPage-textField-usernameRegister", + }} + error={ + !!errors.USERNAME + } + helperText={ + errors + .USERNAME + ?.message + } + /> + ); + }} + /> + { + return ( + + field.onChange( + e + .target + .value, + ) + } + inputProps={{ + "data-testid": + "loginPage-textField-emailRegister", + }} + error={ + !!errors.EMAIL + } + helperText={ + errors + .EMAIL + ?.message + } + /> + ); + }} + /> + { + return ( + + field.onChange( + e + .target + .value, + ) + } + inputProps={{ + "data-testid": + "loginPage-textField-phone", + }} + error={ + !!errors.PHONE + } + helperText={ + errors + .PHONE + ?.message + } + /> + ); + }} + /> + { + return ( + + field.onChange( + e + .target + .value, + ) + } + inputProps={{ + "data-testid": + "loginPage-textField-extension", + }} + /> + ); + }} + /> + { + return ( + + field.onChange( + e + .target + .value, + ) + } + inputProps={{ + "data-testid": + "loginPage-textField-countryCode", + }} + /> + ); + }} + /> + { + if ( + !regPasswordRules.length + ) + return "Minimum 8 characters"; + if ( + !regPasswordRules.upper + ) + return "At least one uppercase letter"; + if ( + !regPasswordRules.lower + ) + return "At least one lowercase letter"; + if ( + !regPasswordRules.special + ) + return "At least one special character"; + return true; + }, + }} + render={({ field }) => { + return ( + + + field.onChange( + e + .target + .value, + ) + } + inputProps={{ + "data-testid": + "loginPage-textField-passwordRegister", + }} + /> + + ); + }} + /> + + value === + regPassword || + "Passwords do not match", + }} + render={({ field }) => { + return ( + + field.onChange( + e + .target + .value, + ) + } + inputProps={{ + "data-testid": + "loginPage-textField-passwordConfirm", + }} + /> + ); + }} + /> + + + + + + )} + {!showOTPCodeField && !register && ( + <> + { + return ( + + field.onChange( + e + .target + .value, + ) + } + inputProps={{ + "data-testid": + "loginPage-textField-username", + }} + error={ + !!formErrors.USERNAME + } + helperText={ + formErrors + .USERNAME + ?.message + } + /> + ); + }} + /> + { + return ( + + field.onChange( + e + .target + .value, + ) + } + inputProps={{ + "data-testid": + "loginPage-textField-password", + }} + error={ + !!formErrors.PASSWORD + } + helperText={ + formErrors + .PASSWORD + ?.message + } + /> + ); + }} + /> + + )} + {showOTPCodeField && ( + { + return ( + + field.onChange( + e.target + .value, + ) + } + inputProps={{ + "data-testid": + "loginPage-textField-otpCode", + }} + /> + ); + }} + /> + )} + {!register && ( + <> + + {configStore.store.config + .nativeRegistration && ( + + Don't have an + account?{" "} + { + setRegister( + true, + ); + setError( + "", + ); + }} + data-testid={ + "loginPage-button-registerPage" + } + > + Register Now + + + )} + + )} + + )} + {!register && ( + <> + {hasUsernamePassword && + hasOAuth && ( + <> + + + or + + + + )} + {configStore.store.config.availableProviders.map( + (p) => { + // skip ones that aren't oauth + if (!p.isOauth) { + return null; + } - return ( - { - oauth( - p.provider, - ); - }} - fullWidth - > - - {/* { + oauth( + p.provider, + ); + }} + fullWidth + > + + {/* */} - - {p.name} - - - - ); - }, - )} - - )} - - -
-
- - - - -
- {isLoading && } -
- { - setForgotPassword(false); - }} - > - Forgot your password? - - - Please contact your administrator to reset password. - - - - - - - - ); + + {p.name} + + + + ); + }, + )} + + )} +
+ + + + + + + + + {isLoading && } + + { + setForgotPassword(false); + }} + > + Forgot your password? + + + Please contact your administrator to reset password. + + + + + + + + ); }); diff --git a/packages/client/src/pages/PageLayout.tsx b/packages/client/src/pages/PageLayout.tsx index cf5c9f4492..dc7912bf0b 100644 --- a/packages/client/src/pages/PageLayout.tsx +++ b/packages/client/src/pages/PageLayout.tsx @@ -1,36 +1,35 @@ -import { useMemo } from 'react'; -import { observer } from 'mobx-react-lite'; -import { Outlet } from 'react-router-dom'; - -import { ErrorBoundary } from '@/components/common'; -import { ErrorPage } from './ErrorPage'; -import { PageStore } from '@/stores'; -import { PageContext } from '@/contexts'; -import { Page } from '@/components/shared/Page'; +import { observer } from "mobx-react-lite"; +import { useMemo } from "react"; +import { Outlet } from "react-router-dom"; +import { ErrorBoundary } from "@/components/common"; +import { Page } from "@/components/shared/Page"; +import { PageContext } from "@/contexts"; +import { PageStore } from "@/stores"; +import { ErrorPage } from "./ErrorPage"; /** * Wrap the routes with a side navigation */ export const PageLayout = observer(() => { - const page = useMemo(() => { - return new PageStore(); - }, []); + const page = useMemo(() => { + return new PageStore(); + }, []); - if (!page) { - return null; - } + if (!page) { + return null; + } - return ( - }> - - - - - - - ); + return ( + }> + + + + + + + ); }); diff --git a/packages/client/src/pages/Router.tsx b/packages/client/src/pages/Router.tsx index 942c625c6c..23c57f3c09 100644 --- a/packages/client/src/pages/Router.tsx +++ b/packages/client/src/pages/Router.tsx @@ -1,79 +1,72 @@ -import { Routes, Route, Navigate } from 'react-router-dom'; -import { observer } from 'mobx-react-lite'; - -import { useRootStore } from '@/hooks'; -import { LoadingScreen } from '@/components/ui'; - +import { observer } from "mobx-react-lite"; +import { Navigate, Route, Routes } from "react-router-dom"; +import { LoadingScreen } from "@/components/ui"; +import { useRootStore } from "@/hooks"; +import { AuthenticatedLayout } from "./AuthenticatedLayout"; import { - AppCatalogPage, - AppMarketplacePage, - AppDetailPage, - ViewAppPage, - NewPromptBuilderAppPage, - CreateAppPage, - EditAppPage, -} from './app'; - -import { EngineRouter } from './engine'; -import { PromptRouter } from './prompt'; -import { SettingsRouter } from './settings'; - -import { AuthenticatedLayout } from './AuthenticatedLayout'; -import { PageLayout } from './PageLayout'; - -import { LoginPage } from './LoginPage'; -import { SharePage } from './SharePage'; - -import { CookieNotice } from './legal/CookieNotice'; -import { PrivacyNotice } from './legal/PrivacyNotice'; - -import { LandingPage } from './LandingPage'; + AppCatalogPage, + AppDetailPage, + AppMarketplacePage, + CreateAppPage, + EditAppPage, + NewPromptBuilderAppPage, + ViewAppPage, +} from "./app"; +import { EngineRouter } from "./engine"; +import { LandingPage } from "./LandingPage"; +import { LoginPage } from "./LoginPage"; +import { CookieNotice } from "./legal/CookieNotice"; +import { PrivacyNotice } from "./legal/PrivacyNotice"; +import { PageLayout } from "./PageLayout"; +import { PromptRouter } from "./prompt"; +import { SharePage } from "./SharePage"; +import { SettingsRouter } from "./settings"; export const Router = observer(() => { - const { configStore } = useRootStore(); + const { configStore } = useRootStore(); - // don't load anything if it is pending - if (configStore.store.status === 'INITIALIZING') { - return ; - } + // don't load anything if it is pending + if (configStore.store.status === "INITIALIZING") { + return ; + } - const showCookieNotice = !!configStore.theme.cookiePolicyNoticePage; - const showPrivacyNotice = !!configStore.theme.privacyNoticePage; + const showCookieNotice = !!configStore.theme.cookiePolicyNoticePage; + const showPrivacyNotice = !!configStore.theme.privacyNoticePage; - return ( - - }> - } /> - }> - } /> - - } /> - } /> - } - /> - } - /> - } /> - } /> - } /> - - } /> - } /> - } /> - } /> - - - {showCookieNotice && ( - } /> - )} - {showPrivacyNotice && ( - } /> - )} - }> - - ); + return ( + + }> + } /> + }> + } /> + + } /> + } /> + } + /> + } + /> + } /> + } /> + } /> + + } /> + } /> + } /> + } /> + + + {showCookieNotice && ( + } /> + )} + {showPrivacyNotice && ( + } /> + )} + }> + + ); }); diff --git a/packages/client/src/pages/SharePage.tsx b/packages/client/src/pages/SharePage.tsx index 8f465a784f..293fe38cfc 100644 --- a/packages/client/src/pages/SharePage.tsx +++ b/packages/client/src/pages/SharePage.tsx @@ -1,111 +1,108 @@ -import { useEffect, useState } from 'react'; -import { useParams, useNavigate } from 'react-router-dom'; -import { observer } from 'mobx-react-lite'; -import { styled, useNotification } from '@semoss/ui'; - -import { useRootStore } from '@/hooks'; -import { LoadingScreen } from '@/components/ui'; -import { CodeRenderer } from '@/components/code-workspace'; - -import { AppType, AppMetadata } from '@/components/app'; -import { PlatformMessages } from '@/components/shared'; - -import { Renderer } from '@semoss/renderer'; -import { runPixel } from '@semoss/sdk/react'; - -const StyledViewport = styled('div')(() => ({ - display: 'flex', - height: '100vh', - width: '100vw', - overflow: 'hidden', +import { observer } from "mobx-react-lite"; +import { useEffect, useState } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { Renderer } from "@semoss/renderer"; +import { runPixel } from "@semoss/sdk/react"; +import { styled, useNotification } from "@semoss/ui"; +import type { AppMetadata, AppType } from "@/components/app"; +import { CodeRenderer } from "@/components/code-workspace"; +import { PlatformMessages } from "@/components/shared"; +import { LoadingScreen } from "@/components/ui"; +import { useRootStore } from "@/hooks"; + +const StyledViewport = styled("div")(() => ({ + display: "flex", + height: "100vh", + width: "100vw", + overflow: "hidden", })); export const SharePage = observer(() => { - // App ID Needed for pixel calls - const { appId } = useParams(); - const { monolithStore } = useRootStore(); - - const notification = useNotification(); - const navigate = useNavigate(); - - const [type, setType] = useState(null); - const [insightId, setInsightId] = useState(''); - - /** - * Load an app - * - * @param appId - id of app to load into the workspace - */ - const loadApp = async (appId: string) => { - try { - // clear the type - setType(null); - - // check the permission - const getUserProjectPermission = - await monolithStore.getUserProjectPermission(appId); - - // get the role and throw an error if it is missing - const role = getUserProjectPermission.permission; - if (!role) { - throw new Error('Unauthorized'); - } - - const { insightId: iId } = await runPixel( - `SetContext("${appId}")`, - 'new', - ); - setInsightId(iId); - - // get the metadata - const getAppInfo = await monolithStore.runQuery<[AppMetadata]>( - `ProjectInfo(project=["${appId}"]);`, - iId, - ); - - // throw the errors if there are any - if (getAppInfo.errors.length > 0) { - throw new Error(getAppInfo.errors.join('')); - } - - const metadata = { - ...getAppInfo.pixelReturn[0].output, - }; - - let type: AppType = 'CODE'; - // set it as blocks - if (metadata.project_type === 'BLOCKS') { - type = 'BLOCKS'; - } - - setType(type); - } catch (e) { - notification.add({ - color: 'error', - message: e.message, - }); - - navigate('/'); - } - }; - - // load the app - useEffect(() => { - loadApp(appId); - }, [appId]); - - // hide the screen while it loads - if (!type) { - return ; - } - - return ( - - {type === 'CODE' ? : null} - {type === 'BLOCKS' ? ( - - ) : null} - - - ); + // App ID Needed for pixel calls + const { appId } = useParams(); + const { monolithStore } = useRootStore(); + + const notification = useNotification(); + const navigate = useNavigate(); + + const [type, setType] = useState(null); + const [insightId, setInsightId] = useState(""); + + /** + * Load an app + * + * @param appId - id of app to load into the workspace + */ + const loadApp = async (appId: string) => { + try { + // clear the type + setType(null); + + // check the permission + const getUserProjectPermission = + await monolithStore.getUserProjectPermission(appId); + + // get the role and throw an error if it is missing + const role = getUserProjectPermission.permission; + if (!role) { + throw new Error("Unauthorized"); + } + + const { insightId: iId } = await runPixel( + `SetContext("${appId}")`, + "new", + ); + setInsightId(iId); + + // get the metadata + const getAppInfo = await monolithStore.runQuery<[AppMetadata]>( + `ProjectInfo(project=["${appId}"]);`, + iId, + ); + + // throw the errors if there are any + if (getAppInfo.errors.length > 0) { + throw new Error(getAppInfo.errors.join("")); + } + + const metadata = { + ...getAppInfo.pixelReturn[0].output, + }; + + let type: AppType = "CODE"; + // set it as blocks + if (metadata.project_type === "BLOCKS") { + type = "BLOCKS"; + } + + setType(type); + } catch (e) { + notification.add({ + color: "error", + message: e.message, + }); + + navigate("/"); + } + }; + + // load the app + useEffect(() => { + loadApp(appId); + }, [appId]); + + // hide the screen while it loads + if (!type) { + return ; + } + + return ( + + {type === "CODE" ? : null} + {type === "BLOCKS" ? ( + + ) : null} + + + ); }); diff --git a/packages/client/src/pages/app/AppCatalogPage.tsx b/packages/client/src/pages/app/AppCatalogPage.tsx index 25f3175b9f..4566affeba 100644 --- a/packages/client/src/pages/app/AppCatalogPage.tsx +++ b/packages/client/src/pages/app/AppCatalogPage.tsx @@ -10,7 +10,7 @@ import { ToggleTabsGroup, Typography, } from "@semoss/ui"; -import { AppMetadata, AppTileCard } from "@/components/app"; +import { type AppMetadata, AppTileCard } from "@/components/app"; import { Help } from "@/components/help"; import { Filterbox } from "@/components/ui"; import { usePixel, useRootStore } from "@/hooks"; diff --git a/packages/client/src/pages/app/AppDetailPage.tsx b/packages/client/src/pages/app/AppDetailPage.tsx index d7b4d55289..eb86c31bb7 100644 --- a/packages/client/src/pages/app/AppDetailPage.tsx +++ b/packages/client/src/pages/app/AppDetailPage.tsx @@ -1,1013 +1,1010 @@ -import React, { useEffect, useMemo, useRef, useState } from 'react'; -import { useNavigate, useParams } from 'react-router-dom'; -import { useForm } from 'react-hook-form'; -import { Link } from 'react-router-dom'; import { - Add, - Edit, - HdrAuto, - MoreVert, - Share, - EditLocation, - RemoveRedEyeRounded, - SimCardDownload, -} from '@mui/icons-material'; - + Add, + Edit, + EditLocation, + HdrAuto, + MoreVert, + RemoveRedEyeRounded, + Share, + SimCardDownload, +} from "@mui/icons-material"; +import React, { useEffect, useMemo, useRef, useState } from "react"; +import { useForm } from "react-hook-form"; +import { Link, useNavigate, useParams } from "react-router-dom"; +import { Env } from "@semoss/sdk/react"; import { - Box, - Breadcrumbs, - Button, - IconButton, - Menu, - styled, - Typography, - useNotification, - Chip, - Modal, - Stack, - CircularProgress, -} from '@semoss/ui'; -import { Env } from '@semoss/sdk/react'; - -import { useRootStore } from '@/hooks'; -import { formatPermission, toTitleCase } from '@/utility'; -import { ShareOverlay } from '@/components/ui'; -import { SettingsContext } from '@/contexts'; + Box, + Breadcrumbs, + Button, + Chip, + CircularProgress, + IconButton, + Menu, + Modal, + Stack, + styled, + Typography, + useNotification, +} from "@semoss/ui"; import { - MembersTable, - PendingMembersTable, - SettingsTiles, -} from '@/components/settings'; + type AppDetailsFormTypes, + AppDetailsFormValues, + type AppDetailsRef, + type appDependency, + ChangeAccessModal, + DependencyTable, + type DetailsForm, + determineUserPermission, + EditDependenciesModal, + EditDetailsModal, + fetchAppInfo, + fetchDependencies, + fetchMainUses, + type modelledDependency, +} from "@/components/app"; import { - AppDetailsFormTypes, - AppDetailsFormValues, - ChangeAccessModal, - DependencyTable, - EditDetailsModal, - EditDependenciesModal, - appDependency, - modelledDependency, - fetchAppInfo, - fetchMainUses, - fetchDependencies, - determineUserPermission, - DetailsForm, - AppDetailsRef, -} from '@/components/app'; -import { NavbarLeft, NavbarHeader } from '../../components/shared'; - -const OuterContainer = styled('div')(({ theme }) => ({ - backgroundColor: theme.palette.background.paper, - display: 'flex', - flexDirection: 'column', - height: '100%', - justifyContent: 'center', - overflow: 'scroll', - padding: `${theme.spacing(6)} 1rem 0`, - width: '100%', + MembersTable, + PendingMembersTable, + SettingsTiles, +} from "@/components/settings"; +import { ShareOverlay } from "@/components/ui"; +import { SettingsContext } from "@/contexts"; +import { useRootStore } from "@/hooks"; +import { formatPermission, toTitleCase } from "@/utility"; +import { NavbarHeader, NavbarLeft } from "../../components/shared"; + +const OuterContainer = styled("div")(({ theme }) => ({ + backgroundColor: theme.palette.background.paper, + display: "flex", + flexDirection: "column", + height: "100%", + justifyContent: "center", + overflow: "scroll", + padding: `${theme.spacing(6)} 1rem 0`, + width: "100%", })); -const InnerContainer = styled('div')(({ theme }) => ({ - display: 'flex', - flexDirection: 'column', - height: '100%', - gap: theme.spacing(3), - margin: 'auto', - maxWidth: '79rem', - width: '100%', +const InnerContainer = styled("div")(({ theme }) => ({ + display: "flex", + flexDirection: "column", + height: "100%", + gap: theme.spacing(3), + margin: "auto", + maxWidth: "79rem", + width: "100%", })); -const ActionBar = styled('div')(({ theme }) => ({ - display: 'flex', - gap: theme.spacing(1), - marginLeft: 'auto', +const ActionBar = styled("div")(({ theme }) => ({ + display: "flex", + gap: theme.spacing(1), + marginLeft: "auto", })); -const PageBody = styled('div')(({ theme }) => ({ - marginLeft: '200px', - display: 'flex', - flexDirection: 'column', +const PageBody = styled("div")(({ theme }) => ({ + marginLeft: "200px", + display: "flex", + flexDirection: "column", })); const SectionHeading = styled(Typography)(({ theme }) => ({ - fontSize: 20, - fontWeight: '500', - marginBottom: theme.spacing(1), + fontSize: 20, + fontWeight: "500", + marginBottom: theme.spacing(1), })); -const TitleSection = styled('section')(({ theme }) => ({ - display: 'flex', - gap: theme.spacing(2), - paddingBottom: theme.spacing(6), +const TitleSection = styled("section")(({ theme }) => ({ + display: "flex", + gap: theme.spacing(2), + paddingBottom: theme.spacing(6), })); -const TitleSectionImg = styled('img')(({ theme }) => ({ - borderRadius: theme.spacing(0.75), - height: '135px', - width: '160px', - overflow: 'hidden', +const TitleSectionImg = styled("img")(({ theme }) => ({ + borderRadius: theme.spacing(0.75), + height: "135px", + width: "160px", + overflow: "hidden", })); -const TitleSectionBodyWrapper = styled('div')({ - display: 'flex', - flexDirection: 'column', - gap: '0.5rem', - justifyContent: 'center', +const TitleSectionBodyWrapper = styled("div")({ + display: "flex", + flexDirection: "column", + gap: "0.5rem", + justifyContent: "center", }); const TitleSectionBody = styled(Typography)(({ theme }) => ({ - alignItems: 'center', - color: theme.palette.secondary.dark, - display: 'flex', - gap: '0.25rem', + alignItems: "center", + color: theme.palette.secondary.dark, + display: "flex", + gap: "0.25rem", })); -const TagsBodyWrapper = styled('div')({ - display: 'flex', - flexWrap: 'wrap', - gap: '0.6rem', +const TagsBodyWrapper = styled("div")({ + display: "flex", + flexWrap: "wrap", + gap: "0.6rem", }); -const StyledSection = styled('section')(({ theme }) => ({ - paddingBottom: theme.spacing(3), +const StyledSection = styled("section")(({ theme }) => ({ + paddingBottom: theme.spacing(3), })); -const DependenciesHeadingWrapper = styled('div')({ - alignItems: 'start', - display: 'flex', - justifyContent: 'space-between', - position: 'relative', +const DependenciesHeadingWrapper = styled("div")({ + alignItems: "start", + display: "flex", + justifyContent: "space-between", + position: "relative", }); const StyledMenuItem = styled(Menu.Item)(({ theme }) => ({ - color: theme.palette.secondary.dark, - display: 'flex', - gap: theme.spacing(0.5), - alignItems: 'center', - height: '48px', + color: theme.palette.secondary.dark, + display: "flex", + gap: theme.spacing(0.5), + alignItems: "center", + height: "48px", })); export const AppDetailPage = () => { - const { control, setValue, getValues, watch, handleSubmit } = - useForm({ defaultValues: AppDetailsFormValues }); - - const markdown = watch('markdown'); - const tags = watch('tag'); - const appInfo = watch('appInfo'); - const userRole = watch('userRole'); - const permission = watch('permission'); - const dependencies = watch('dependencies'); - const detailsForm = watch('detailsForm'); - - const [moreVertAnchorEl, setMoreVertAnchorEl] = useState(null); - const [isShareOverlayOpen, setIsShareOverlayOpen] = useState(false); - const [isChangeAccessModalOpen, setIsChangeAccessModalOpen] = - useState(false); - const [isEditDetailsModalOpen, setIsEditDetailsModalOpen] = useState(false); - const [isEditDependenciesModalOpen, setIsEditDependenciesModalOpen] = - useState(false); - - const [values, setValues] = useState( - AppDetailsFormValues.detailsForm, - ); - - const markdownRef = useRef(null); - const tagsRef = useRef(null); - const dependenciesRef = useRef(null); - const appAccessRef = useRef(null); - const memberAccessRef = useRef(null); - const similarAppsRef = useRef(null); - - const refs = useMemo< - { ref: React.MutableRefObject; display: string }[] - >(() => { - return [ - { ref: markdownRef, display: 'Main Uses' }, - { ref: tagsRef, display: 'Tags' }, - { ref: dependenciesRef, display: 'Dependencies' }, - { ref: appAccessRef, display: 'App Access' }, - { ref: memberAccessRef, display: 'Member Access' }, - { ref: similarAppsRef, display: 'Similar Apps' }, - ]; - }, []); - - const { monolithStore, configStore } = useRootStore(); - const navigate = useNavigate(); - const notification = useNotification(); - const { appId } = useParams(); - - useEffect(() => { - setValue('appId', appId); - fetchUserSpecificData(); - fetchAppData(appId); - }, [appId]); - - const fetchUserSpecificData = async () => { - const currPermission = getValues('permission'); - await getPermission(); - const newPermission = getValues('permission'); - - if (newPermission !== currPermission && newPermission === 'readOnly') { - fetchSimilarApps(); - } - }; - - async function getPermission() { - const { permission: role } = - await monolithStore.getUserProjectPermission(appId); - - setValue('userRole', role); - const permission = determineUserPermission(role); - setValue('permission', permission); - - if (permission === 'author') setValue('requestedPermission', 'OWNER'); - if (permission === 'editor') setValue('requestedPermission', 'EDIT'); - if (permission === 'readOnly' || permission === 'discoverable') - setValue('requestedPermission', 'READ_ONLY'); - } - - const fetchAppData = async (id: string) => { - await getPermission(); - const permission = getValues('permission'); - const promises: Promise[] = [ - fetchAppInfo( - monolithStore, - id, - configStore.store.config.projectMetaKeys.map((a) => a.metakey), - ), - fetchMainUses(monolithStore, id), - ]; - if (permission !== 'discoverable') { - promises.push(fetchDependencies(monolithStore, id)); - } - const results = await Promise.allSettled(promises); - results.forEach((res, idx) => { - if (res.status === 'rejected') { - emitMessage(true, res.reason); - } else { - if (idx === 0) { - if (res.value.type === 'error') { - emitMessage(true, res.value.output); - } else { - setValue('appInfo', res.value.output); - const output = res.value.output; - - const projectMetaKeys = - configStore.store.config.projectMetaKeys; - // Keep only relevant project keys defined for app details - const parsedMeta = projectMetaKeys - .map((k) => k.metakey) - .reduce((prev, curr) => { - // tag, domain, and etc either come in as a string or a string[], format it to correct type - const found = projectMetaKeys.find( - (obj) => obj.metakey === curr, - ); - - if (curr === 'tag') { - if (typeof output[curr] === 'string') { - prev[curr] = [output[curr]]; - } else { - prev[curr] = output[curr]; - } - } else if ( - found.display_options === - 'single-typeahead' || - found.display_options === 'select-box' || - found.display_options === 'multi-typeahead' - ) { - if (typeof output[curr] === 'string') { - prev[curr] = [output[curr]]; - } else { - prev[curr] = output[curr]; - } - } else { - prev[curr] = output[curr]; - } - - return prev; - }, {}) as AppDetailsFormTypes['detailsForm']; - setValue('detailsForm', parsedMeta); - setValue('tag', parsedMeta.tag); - setValue('markdown', parsedMeta.markdown); - setValue('detailsForm.markdown', parsedMeta.markdown); - setValues((prev) => ({ - ...prev, - markdown: parsedMeta.markdown || '', - })); - setValues((prev) => ({ ...prev, ...parsedMeta })); - } - } else if (idx === 1) { - if (res.value.type === 'error') { - emitMessage(true, res.value.output); - } else { - if (res.value.output !== null) { - setValue('markdown', res.value.output); - setValue('detailsForm.markdown', res.value.output); - setValues((prev) => ({ - ...prev, - markdown: res.value.output || '', - })); - } - } - } else if (idx === 2) { - if (res.value.type === 'error') { - emitMessage(true, res.value.output); - } else { - const modelled = modelDependencies(res.value.output); - setValue('dependencies', modelled); - setValue('selectedDependencies', modelled); - } - } - } - }); - }; - - const fetchSimilarApps = () => { - // TODO - }; - - const modelDependencies = ( - dependencies: appDependency[], - ): modelledDependency[] => { - return dependencies.map((dep: appDependency) => ({ - name: dep.engine_name ? dep.engine_name.replace(/_/g, ' ') : '', - id: dep.engine_id, - type: dep.engine_type, - userPermission: '', // TODO: no value currently available in the payload - isPublic: !!dep.engine_global, - isDiscoverable: !!dep.engine_discoverable, - })); - }; - - const emitMessage = (isError: boolean, message: string) => { - notification.add({ - color: isError ? 'error' : 'success', - message, - }); - }; - - const handleCloseChangeAccessModal = (refresh?: boolean) => { - if (refresh) { - // fetch updated permission. - getPermission(); - } else { - // reset permission to original. - if (permission === 'author') - setValue('requestedPermission', 'OWNER'); - if (permission === 'editor') - setValue('requestedPermission', 'EDIT'); - if (permission === 'readOnly') - setValue('requestedPermission', 'READ_ONLY'); - } - setIsChangeAccessModalOpen(false); - }; - - const handleCloseEditDetailsModal = (isReset?: boolean) => { - if (isReset) { - setValue('detailsForm', values); - } - setIsEditDetailsModalOpen(false); - }; - - const handleCloseDependenciesModal = async (refreshData: boolean) => { - const currDependencies = getValues('dependencies'); - - if (refreshData) { - const appId = getValues('appId'); - const res = await fetchDependencies(monolithStore, appId); - if (res.type === 'success') { - const modelled = modelDependencies(res.output); - setValue('dependencies', modelled); - setValue('selectedDependencies', modelled); - } else { - setValue('selectedDependencies', currDependencies); - notification.add({ - color: 'error', - message: res.output, - }); - } - } else { - setValue('selectedDependencies', currDependencies); - } - setIsEditDependenciesModalOpen(false); - }; - - // export loading state - const [exportLoading, setExportLoading] = useState(false); - /** - * @name exportAPP - * @desc export APP pixel - */ - const exportApp = () => { - setExportLoading(true); - const pixel = `ExportProjectApp(project=["${appId}"]);`; - - monolithStore.runQuery(pixel).then((response) => { - const output = response.pixelReturn[0].output, - insightId = response.insightId; - - monolithStore.download(insightId, output); - }); - setExportLoading(false); - }; - - // filter metakeys to the variable ones - const projectMetaKeys = configStore.store.config.projectMetaKeys.filter( - (k) => { - return ( - k.metakey !== 'description' && - k.metakey !== 'markdown' && - k.metakey !== 'tag' - ); - }, - ); - - // Create refs for dynamic fields - const createRefs = useMemo(() => { - const refs = []; - projectMetaKeys.forEach((meta) => { - if (detailsForm?.[meta.metakey]) { - refs.push({ - ref: React.createRef(), - display: toTitleCase(meta.metakey), - ...meta, - }); - } - }); - return refs as AppDetailsRef[]; - }, [projectMetaKeys, detailsForm]); - - // Merge default/dynamic refs for side bar navigiation - const detailRefs = [ - ...refs, - ...createRefs.map((a) => ({ ref: a.ref, display: a.display })), - ]; - - /** - * @name onSubmit - * @desc update app details - * @param data - form data - */ - const onSubmit = handleSubmit((data: AppDetailsFormTypes) => { - // copy over the defined keys - const meta = {} as AppDetailsFormTypes['detailsForm']; - let imageMeta = [] as File[]; - if (data.detailsForm) { - for (const key in data.detailsForm) { - if (data.detailsForm[key] !== undefined && key !== 'appImage') { - meta[key] = data.detailsForm[key]; - } - if (key === 'appImage') { - imageMeta = data.detailsForm[key] as File[]; - } - } - } - - if (Object.keys(meta).length === 0) { - notification.add({ - color: 'warning', - message: 'Nothing to Save', - }); - - return; - } - - monolithStore - .runQuery( - `SetProjectMetadata(project=["${appId}"], meta=[${JSON.stringify( - meta, - )}], jsonCleanup=[true])`, - ) - .then(async (response) => { - const { output, additionalOutput, operationType } = - response.pixelReturn[0]; - - // track the errors - if (operationType.indexOf('ERROR') > -1) { - notification.add({ - color: 'error', - message: output, - }); - - return; - } - - // upload the image - if (imageMeta && appId) { - await monolithStore.uploadImage(imageMeta, appId); - } - - // close it, refresh and succesfully message - notification.add({ - color: 'success', - message: additionalOutput[0].output, - }); - - fetchAppData(appId); - handleCloseEditDetailsModal(); - }) - .catch((error) => { - notification.add({ - color: 'error', - message: error.message, - }); - }); - }); - - return ( -
- - - - - - - - App Catalog - - - {appInfo?.project_name} - - - -
- - - - {permission === 'author' ? ( - - ) : ( - - )} - - - - - setMoreVertAnchorEl(event.currentTarget) - } - data-testid={'app-detail-more-btn'} - > - - - - setMoreVertAnchorEl(null)} - anchorOrigin={{ - vertical: 'bottom', - horizontal: 'right', - }} - transformOrigin={{ - vertical: 'top', - horizontal: 'right', - }} - sx={{ borderRadius: '4px' }} - > - {permission === 'author' && ( - { - setIsEditDetailsModalOpen(true); - setMoreVertAnchorEl(null); - }} - value={null} - > - - - Edit App Details - - - )} - - - setIsShareOverlayOpen(true) - } - > - - - Share - - - - - - - - - - {appInfo?.project_name} - - - {permission === 'author' ? ( - - ) : permission === 'editor' ? ( - - ) : permission === 'discoverable' ? ( - - ) : null} - {`${formatPermission(userRole)} Access`} - - - {appInfo?.description - ? appInfo?.description - : 'No description available'} - - - - - - - Main uses - - - {markdown} - - - - - - Tags - - {tags ? ( - - {tags.map((tag, idx) => ( - - ))} - - ) : ( - - No tags available - - )} - - <> - {createRefs.map((k) => { - if ( - values[k.metakey] === undefined || - !Array.isArray(values[k.metakey]) - ) { - return null; - } - - return ( - - - {k.display} - - - {k.display_options === - 'multi-checklist' || - k.display_options === - 'multi-select' || - k.display_options === - 'multi-typeahead' || - k.display_options === - 'select-box' ? ( - - {( - detailsForm[ - k.metakey - ] as string[] - ).map((tag) => { - return ( - - ); - })} - - ) : ( - (detailsForm[ - k.metakey - ] as string) - )} - - - ); - })} - - - {permission && permission !== 'discoverable' && ( - - - - Dependencies - - {permission === 'author' && ( - - setIsEditDependenciesModalOpen( - true, - ) - } - sx={{ - position: 'absolute', - right: 0, - top: '-0.4rem', - }} - data-testid={ - 'app-detail-edit-btn' - } - > - - - )} - - - {dependencies.length > 0 ? ( - - ) : ( - - No dependencies - - )} - - )} - - {permission === 'author' && ( - - - App Access - - - { - navigate('/settings/app'); - }} - /> - - - )} - - {permission && - permission !== 'discoverable' && - permission !== 'readOnly' && ( - - - Member Access - - - - - { - fetchUserSpecificData(); - }} - /> - - - - )} - - {(permission === 'discoverable' || - permission === 'readOnly') && ( - - - Similar Apps - - - )} - -
-
- - setIsShareOverlayOpen(false)} - > - setIsShareOverlayOpen(false)} - /> - - - - - - - -
-
- ); + const { control, setValue, getValues, watch, handleSubmit } = + useForm({ defaultValues: AppDetailsFormValues }); + + const markdown = watch("markdown"); + const tags = watch("tag"); + const appInfo = watch("appInfo"); + const userRole = watch("userRole"); + const permission = watch("permission"); + const dependencies = watch("dependencies"); + const detailsForm = watch("detailsForm"); + + const [moreVertAnchorEl, setMoreVertAnchorEl] = useState(null); + const [isShareOverlayOpen, setIsShareOverlayOpen] = useState(false); + const [isChangeAccessModalOpen, setIsChangeAccessModalOpen] = + useState(false); + const [isEditDetailsModalOpen, setIsEditDetailsModalOpen] = useState(false); + const [isEditDependenciesModalOpen, setIsEditDependenciesModalOpen] = + useState(false); + + const [values, setValues] = useState( + AppDetailsFormValues.detailsForm, + ); + + const markdownRef = useRef(null); + const tagsRef = useRef(null); + const dependenciesRef = useRef(null); + const appAccessRef = useRef(null); + const memberAccessRef = useRef(null); + const similarAppsRef = useRef(null); + + const refs = useMemo< + { ref: React.MutableRefObject; display: string }[] + >(() => { + return [ + { ref: markdownRef, display: "Main Uses" }, + { ref: tagsRef, display: "Tags" }, + { ref: dependenciesRef, display: "Dependencies" }, + { ref: appAccessRef, display: "App Access" }, + { ref: memberAccessRef, display: "Member Access" }, + { ref: similarAppsRef, display: "Similar Apps" }, + ]; + }, []); + + const { monolithStore, configStore } = useRootStore(); + const navigate = useNavigate(); + const notification = useNotification(); + const { appId } = useParams(); + + useEffect(() => { + setValue("appId", appId); + fetchUserSpecificData(); + fetchAppData(appId); + }, [appId]); + + const fetchUserSpecificData = async () => { + const currPermission = getValues("permission"); + await getPermission(); + const newPermission = getValues("permission"); + + if (newPermission !== currPermission && newPermission === "readOnly") { + fetchSimilarApps(); + } + }; + + async function getPermission() { + const { permission: role } = + await monolithStore.getUserProjectPermission(appId); + + setValue("userRole", role); + const permission = determineUserPermission(role); + setValue("permission", permission); + + if (permission === "author") setValue("requestedPermission", "OWNER"); + if (permission === "editor") setValue("requestedPermission", "EDIT"); + if (permission === "readOnly" || permission === "discoverable") + setValue("requestedPermission", "READ_ONLY"); + } + + const fetchAppData = async (id: string) => { + await getPermission(); + const permission = getValues("permission"); + const promises: Promise[] = [ + fetchAppInfo( + monolithStore, + id, + configStore.store.config.projectMetaKeys.map((a) => a.metakey), + ), + fetchMainUses(monolithStore, id), + ]; + if (permission !== "discoverable") { + promises.push(fetchDependencies(monolithStore, id)); + } + const results = await Promise.allSettled(promises); + results.forEach((res, idx) => { + if (res.status === "rejected") { + emitMessage(true, res.reason); + } else { + if (idx === 0) { + if (res.value.type === "error") { + emitMessage(true, res.value.output); + } else { + setValue("appInfo", res.value.output); + const output = res.value.output; + + const projectMetaKeys = + configStore.store.config.projectMetaKeys; + // Keep only relevant project keys defined for app details + const parsedMeta = projectMetaKeys + .map((k) => k.metakey) + .reduce((prev, curr) => { + // tag, domain, and etc either come in as a string or a string[], format it to correct type + const found = projectMetaKeys.find( + (obj) => obj.metakey === curr, + ); + + if (curr === "tag") { + if (typeof output[curr] === "string") { + prev[curr] = [output[curr]]; + } else { + prev[curr] = output[curr]; + } + } else if ( + found.display_options === + "single-typeahead" || + found.display_options === "select-box" || + found.display_options === "multi-typeahead" + ) { + if (typeof output[curr] === "string") { + prev[curr] = [output[curr]]; + } else { + prev[curr] = output[curr]; + } + } else { + prev[curr] = output[curr]; + } + + return prev; + }, {}) as AppDetailsFormTypes["detailsForm"]; + setValue("detailsForm", parsedMeta); + setValue("tag", parsedMeta.tag); + setValue("markdown", parsedMeta.markdown); + setValue("detailsForm.markdown", parsedMeta.markdown); + setValues((prev) => ({ + ...prev, + markdown: parsedMeta.markdown || "", + })); + setValues((prev) => ({ ...prev, ...parsedMeta })); + } + } else if (idx === 1) { + if (res.value.type === "error") { + emitMessage(true, res.value.output); + } else { + if (res.value.output !== null) { + setValue("markdown", res.value.output); + setValue("detailsForm.markdown", res.value.output); + setValues((prev) => ({ + ...prev, + markdown: res.value.output || "", + })); + } + } + } else if (idx === 2) { + if (res.value.type === "error") { + emitMessage(true, res.value.output); + } else { + const modelled = modelDependencies(res.value.output); + setValue("dependencies", modelled); + setValue("selectedDependencies", modelled); + } + } + } + }); + }; + + const fetchSimilarApps = () => { + // TODO + }; + + const modelDependencies = ( + dependencies: appDependency[], + ): modelledDependency[] => { + return dependencies.map((dep: appDependency) => ({ + name: dep.engine_name ? dep.engine_name.replace(/_/g, " ") : "", + id: dep.engine_id, + type: dep.engine_type, + userPermission: "", // TODO: no value currently available in the payload + isPublic: !!dep.engine_global, + isDiscoverable: !!dep.engine_discoverable, + })); + }; + + const emitMessage = (isError: boolean, message: string) => { + notification.add({ + color: isError ? "error" : "success", + message, + }); + }; + + const handleCloseChangeAccessModal = (refresh?: boolean) => { + if (refresh) { + // fetch updated permission. + getPermission(); + } else { + // reset permission to original. + if (permission === "author") + setValue("requestedPermission", "OWNER"); + if (permission === "editor") + setValue("requestedPermission", "EDIT"); + if (permission === "readOnly") + setValue("requestedPermission", "READ_ONLY"); + } + setIsChangeAccessModalOpen(false); + }; + + const handleCloseEditDetailsModal = (isReset?: boolean) => { + if (isReset) { + setValue("detailsForm", values); + } + setIsEditDetailsModalOpen(false); + }; + + const handleCloseDependenciesModal = async (refreshData: boolean) => { + const currDependencies = getValues("dependencies"); + + if (refreshData) { + const appId = getValues("appId"); + const res = await fetchDependencies(monolithStore, appId); + if (res.type === "success") { + const modelled = modelDependencies(res.output); + setValue("dependencies", modelled); + setValue("selectedDependencies", modelled); + } else { + setValue("selectedDependencies", currDependencies); + notification.add({ + color: "error", + message: res.output, + }); + } + } else { + setValue("selectedDependencies", currDependencies); + } + setIsEditDependenciesModalOpen(false); + }; + + // export loading state + const [exportLoading, setExportLoading] = useState(false); + /** + * @name exportAPP + * @desc export APP pixel + */ + const exportApp = () => { + setExportLoading(true); + const pixel = `ExportProjectApp(project=["${appId}"]);`; + + monolithStore.runQuery(pixel).then((response) => { + const output = response.pixelReturn[0].output, + insightId = response.insightId; + + monolithStore.download(insightId, output); + }); + setExportLoading(false); + }; + + // filter metakeys to the variable ones + const projectMetaKeys = configStore.store.config.projectMetaKeys.filter( + (k) => { + return ( + k.metakey !== "description" && + k.metakey !== "markdown" && + k.metakey !== "tag" + ); + }, + ); + + // Create refs for dynamic fields + const createRefs = useMemo(() => { + const refs = []; + projectMetaKeys.forEach((meta) => { + if (detailsForm?.[meta.metakey]) { + refs.push({ + ref: React.createRef(), + display: toTitleCase(meta.metakey), + ...meta, + }); + } + }); + return refs as AppDetailsRef[]; + }, [projectMetaKeys, detailsForm]); + + // Merge default/dynamic refs for side bar navigiation + const detailRefs = [ + ...refs, + ...createRefs.map((a) => ({ ref: a.ref, display: a.display })), + ]; + + /** + * @name onSubmit + * @desc update app details + * @param data - form data + */ + const onSubmit = handleSubmit((data: AppDetailsFormTypes) => { + // copy over the defined keys + const meta = {} as AppDetailsFormTypes["detailsForm"]; + let imageMeta = [] as File[]; + if (data.detailsForm) { + for (const key in data.detailsForm) { + if (data.detailsForm[key] !== undefined && key !== "appImage") { + meta[key] = data.detailsForm[key]; + } + if (key === "appImage") { + imageMeta = data.detailsForm[key] as File[]; + } + } + } + + if (Object.keys(meta).length === 0) { + notification.add({ + color: "warning", + message: "Nothing to Save", + }); + + return; + } + + monolithStore + .runQuery( + `SetProjectMetadata(project=["${appId}"], meta=[${JSON.stringify( + meta, + )}], jsonCleanup=[true])`, + ) + .then(async (response) => { + const { output, additionalOutput, operationType } = + response.pixelReturn[0]; + + // track the errors + if (operationType.indexOf("ERROR") > -1) { + notification.add({ + color: "error", + message: output, + }); + + return; + } + + // upload the image + if (imageMeta && appId) { + await monolithStore.uploadImage(imageMeta, appId); + } + + // close it, refresh and succesfully message + notification.add({ + color: "success", + message: additionalOutput[0].output, + }); + + fetchAppData(appId); + handleCloseEditDetailsModal(); + }) + .catch((error) => { + notification.add({ + color: "error", + message: error.message, + }); + }); + }); + + return ( +
+ + + + + + + + App Catalog + + + {appInfo?.project_name} + + + +
+ + + + {permission === "author" ? ( + + ) : ( + + )} + + + + + setMoreVertAnchorEl(event.currentTarget) + } + data-testid={"app-detail-more-btn"} + > + + + + setMoreVertAnchorEl(null)} + anchorOrigin={{ + vertical: "bottom", + horizontal: "right", + }} + transformOrigin={{ + vertical: "top", + horizontal: "right", + }} + sx={{ borderRadius: "4px" }} + > + {permission === "author" && ( + { + setIsEditDetailsModalOpen(true); + setMoreVertAnchorEl(null); + }} + value={null} + > + + + Edit App Details + + + )} + + + setIsShareOverlayOpen(true) + } + > + + + Share + + + + + + + + + + {appInfo?.project_name} + + + {permission === "author" ? ( + + ) : permission === "editor" ? ( + + ) : permission === "discoverable" ? ( + + ) : null} + {`${formatPermission(userRole)} Access`} + + + {appInfo?.description + ? appInfo?.description + : "No description available"} + + + + + + + Main uses + + + {markdown} + + + + + + Tags + + {tags ? ( + + {tags.map((tag, idx) => ( + + ))} + + ) : ( + + No tags available + + )} + + <> + {createRefs.map((k) => { + if ( + values[k.metakey] === undefined || + !Array.isArray(values[k.metakey]) + ) { + return null; + } + + return ( + + + {k.display} + + + {k.display_options === + "multi-checklist" || + k.display_options === + "multi-select" || + k.display_options === + "multi-typeahead" || + k.display_options === + "select-box" ? ( + + {( + detailsForm[ + k.metakey + ] as string[] + ).map((tag) => { + return ( + + ); + })} + + ) : ( + (detailsForm[ + k.metakey + ] as string) + )} + + + ); + })} + + + {permission && permission !== "discoverable" && ( + + + + Dependencies + + {permission === "author" && ( + + setIsEditDependenciesModalOpen( + true, + ) + } + sx={{ + position: "absolute", + right: 0, + top: "-0.4rem", + }} + data-testid={ + "app-detail-edit-btn" + } + > + + + )} + + + {dependencies.length > 0 ? ( + + ) : ( + + No dependencies + + )} + + )} + + {permission === "author" && ( + + + App Access + + + { + navigate("/settings/app"); + }} + /> + + + )} + + {permission && + permission !== "discoverable" && + permission !== "readOnly" && ( + + + Member Access + + + + + { + fetchUserSpecificData(); + }} + /> + + + + )} + + {(permission === "discoverable" || + permission === "readOnly") && ( + + + Similar Apps + + + )} + +
+
+ + setIsShareOverlayOpen(false)} + > + setIsShareOverlayOpen(false)} + /> + + + + + + + +
+
+ ); }; -const StyledSidebar = styled('div')(({ theme }) => ({ - width: '145px', - borderRight: `1px solid ${theme.palette.secondary.main}`, - display: 'flex', - flexDirection: 'column', - gap: theme.spacing(0.5), - position: 'fixed', - paddingRight: theme.spacing(1), +const StyledSidebar = styled("div")(({ theme }) => ({ + width: "145px", + borderRight: `1px solid ${theme.palette.secondary.main}`, + display: "flex", + flexDirection: "column", + gap: theme.spacing(0.5), + position: "fixed", + paddingRight: theme.spacing(1), })); const StyledSidebarItem = styled(Button)(({ theme }) => ({ - justifyContent: 'flex-start', - whiteSpace: 'nowrap', + justifyContent: "flex-start", + whiteSpace: "nowrap", })); interface SidebarProps { - permission: string; - refs: { ref: React.MutableRefObject; display: string }[]; + permission: string; + refs: { ref: React.MutableRefObject; display: string }[]; } const Sidebar = ({ permission, refs }: SidebarProps) => { - const [ - mainUsesRef, - tagsRef, - dependenciesRef, - appAccessRef, - memberAccessRef, - similarAppsRef, - ...dynamicRefs - ] = refs; - - const scrollIntoView = (ref: React.MutableRefObject) => { - ref.current.scrollIntoView({ behavior: 'smooth' }); - }; - - const canEdit = - permission && - permission !== 'discoverable' && - permission !== 'readOnly'; - - return ( - - scrollIntoView(mainUsesRef.ref)} - value={null} - > - Main Uses - - scrollIntoView(tagsRef.ref)} - value={null} - > - Tags - - {dynamicRefs?.map((ref) => ( - scrollIntoView(ref.ref)} - value={null} - key={ref.display} - > - {ref.display} - - ))} - {permission !== 'discoverable' && ( - scrollIntoView(dependenciesRef.ref)} - value={null} - > - Dependencies - - )} - {permission === 'author' && ( - scrollIntoView(appAccessRef.ref)} - value={null} - > - App Access - - )} - {canEdit && ( - scrollIntoView(memberAccessRef.ref)} - value={null} - > - Member Access - - )} - {!canEdit && ( - scrollIntoView(similarAppsRef.ref)} - value={null} - > - Similar Apps - - )} - - ); + const [ + mainUsesRef, + tagsRef, + dependenciesRef, + appAccessRef, + memberAccessRef, + similarAppsRef, + ...dynamicRefs + ] = refs; + + const scrollIntoView = (ref: React.MutableRefObject) => { + ref.current.scrollIntoView({ behavior: "smooth" }); + }; + + const canEdit = + permission && + permission !== "discoverable" && + permission !== "readOnly"; + + return ( + + scrollIntoView(mainUsesRef.ref)} + value={null} + > + Main Uses + + scrollIntoView(tagsRef.ref)} + value={null} + > + Tags + + {dynamicRefs?.map((ref) => ( + scrollIntoView(ref.ref)} + value={null} + key={ref.display} + > + {ref.display} + + ))} + {permission !== "discoverable" && ( + scrollIntoView(dependenciesRef.ref)} + value={null} + > + Dependencies + + )} + {permission === "author" && ( + scrollIntoView(appAccessRef.ref)} + value={null} + > + App Access + + )} + {canEdit && ( + scrollIntoView(memberAccessRef.ref)} + value={null} + > + Member Access + + )} + {!canEdit && ( + scrollIntoView(similarAppsRef.ref)} + value={null} + > + Similar Apps + + )} + + ); }; diff --git a/packages/client/src/pages/app/AppMarketplacePage.tsx b/packages/client/src/pages/app/AppMarketplacePage.tsx index 4fb6620f71..b8f6a8cf69 100644 --- a/packages/client/src/pages/app/AppMarketplacePage.tsx +++ b/packages/client/src/pages/app/AppMarketplacePage.tsx @@ -1,187 +1,186 @@ -import React, { useState } from 'react'; -import { useNavigate } from 'react-router-dom'; - -import { Stack, styled, Typography } from '@semoss/ui'; - -import { AppTemplates, NewAppModal } from '@/components/app'; -import { Filterbox } from '@/components/ui'; -import { NavbarLeft, NavbarHeader } from '../../components/shared'; +import type React from "react"; +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { Stack, styled, Typography } from "@semoss/ui"; +import { AppTemplates, NewAppModal } from "@/components/app"; +import { Filterbox } from "@/components/ui"; +import { NavbarHeader, NavbarLeft } from "../../components/shared"; const StyledTypographyHome = styled(Typography)< - React.ComponentProps & { - onClick?: React.MouseEventHandler; - } + React.ComponentProps & { + onClick?: React.MouseEventHandler; + } >(({ theme }) => ({ - color: '#212121', - FontFamily: 'Inter', - fontSize: '16px', - fontWeight: 400, - lineHeight: '24px', - letterSpacing: '0.15px', - fontStyle: 'normal', + color: "#212121", + FontFamily: "Inter", + fontSize: "16px", + fontWeight: 400, + lineHeight: "24px", + letterSpacing: "0.15px", + fontStyle: "normal", })); const StyledTypographySeperator = styled(Typography)< - React.ComponentProps + React.ComponentProps >(({ theme }) => ({ - color: '#666', - FontFamily: 'Inter', - fontSize: '16px', - fontWeight: 400, - lineHeight: '24px', - letterSpacing: '0.15px', - fontStyle: 'normal', + color: "#666", + FontFamily: "Inter", + fontSize: "16px", + fontWeight: 400, + lineHeight: "24px", + letterSpacing: "0.15px", + fontStyle: "normal", })); const StyledTypographyBrowseTemplates = styled(Typography)< - React.ComponentProps + React.ComponentProps >(({ theme }) => ({ - color: '#9E9E9E', - FontFamily: 'Inter', - fontSize: '16px', - fontWeight: 400, - lineHeight: '24px', - letterSpacing: '0.15px', - fontStyle: 'normal', + color: "#9E9E9E", + FontFamily: "Inter", + fontSize: "16px", + fontWeight: 400, + lineHeight: "24px", + letterSpacing: "0.15px", + fontStyle: "normal", })); export const AppMarketplacePage = () => { - const navigate = useNavigate(); - const [newAppOptions, setNewAppOptions] = useState< - React.ComponentProps['options'] | null - >(null); - const isNameOpen = !!newAppOptions; + const navigate = useNavigate(); + const [newAppOptions, setNewAppOptions] = useState< + React.ComponentProps["options"] | null + >(null); + const isNameOpen = !!newAppOptions; - /** - * Navigate to the app and open it - * - * appId - appId of the app - */ - const navigateApp = (appId: string) => { - if (!appId) { - return; - } + /** + * Navigate to the app and open it + * + * appId - appId of the app + */ + const navigateApp = (appId: string) => { + if (!appId) { + return; + } - navigate(`/app/${appId}/edit`); - }; - return ( - <> - - - - - - - - {/* Breadcrumb */} - - navigate('/')} - sx={{ - display: 'flex', - alignItems: 'flex-start', - cursor: 'pointer', - }} - > - Home - - - / - - - Browse Templates - - + navigate(`/app/${appId}/edit`); + }; + return ( + <> + + + + + + + + {/* Breadcrumb */} + + navigate("/")} + sx={{ + display: "flex", + alignItems: "flex-start", + cursor: "pointer", + }} + > + Home + + + / + + + Browse Templates + + - - Browse Templates - - - Don’t know where to start? Don’t worry! Browse - our collection of templates to start - personalizing the app to your specific use case. - - - - - - {isNameOpen ? ( - { - if (appId) { - navigateApp(appId); - } else { - // close the modal - setNewAppOptions(null); - } - }} - /> - ) : null} -
-
- , - ) => { - // setMetaFilters(filters); - }} - /> -
-
- { - setNewAppOptions({ - type: 'blocks', - state: t.state, - }); - }} - /> -
-
-
-
- - ); + + Browse Templates + + + Don’t know where to start? Don’t worry! Browse + our collection of templates to start + personalizing the app to your specific use case. + +
+
+
+ + {isNameOpen ? ( + { + if (appId) { + navigateApp(appId); + } else { + // close the modal + setNewAppOptions(null); + } + }} + /> + ) : null} +
+
+ , + ) => { + // setMetaFilters(filters); + }} + /> +
+
+ { + setNewAppOptions({ + type: "blocks", + state: t.state, + }); + }} + /> +
+
+
+
+ + ); }; diff --git a/packages/client/src/pages/app/CreateAppPage.tsx b/packages/client/src/pages/app/CreateAppPage.tsx index 64284ac11a..8d32f36b17 100644 --- a/packages/client/src/pages/app/CreateAppPage.tsx +++ b/packages/client/src/pages/app/CreateAppPage.tsx @@ -1,151 +1,149 @@ -import { useState } from 'react'; -import { Link, Navigate, useNavigate } from 'react-router-dom'; - -import { STATE_VERSION } from '@semoss/renderer'; -import { Stack, Breadcrumbs, Typography } from '@semoss/ui'; - -import { useRootStore } from '../../hooks'; -import { BASE_PAGE_BLOCKS } from './app.constants'; -import { AddAppModal, NewAppModal, AppTemplates } from '../../components/app'; -import CreateAppSection from '../../components/landing/CreateAppSection'; -import { NavbarLeft, NavbarHeader } from '../../components/shared'; +import { useState } from "react"; +import { Link, Navigate, useNavigate } from "react-router-dom"; +import { STATE_VERSION } from "@semoss/renderer"; +import { Breadcrumbs, Stack, Typography } from "@semoss/ui"; +import { AddAppModal, AppTemplates, NewAppModal } from "../../components/app"; +import CreateAppSection from "../../components/landing/CreateAppSection"; +import { NavbarHeader, NavbarLeft } from "../../components/shared"; +import { useRootStore } from "../../hooks"; +import { BASE_PAGE_BLOCKS } from "./app.constants"; export const CreateAppPage = () => { - const navigate = useNavigate(); + const navigate = useNavigate(); - const { configStore } = useRootStore(); - const [isUploadOpen, setIsUploadOpen] = useState(false); - const [newAppOptions, setNewAppOptions] = useState< - React.ComponentProps['options'] | null - >(null); + const { configStore } = useRootStore(); + const [isUploadOpen, setIsUploadOpen] = useState(false); + const [newAppOptions, setNewAppOptions] = useState< + React.ComponentProps["options"] | null + >(null); - const isNameOpen = !!newAppOptions; + const isNameOpen = !!newAppOptions; - /** - * Navigate to the app and open it - * - * appId - appId of the app - */ - const navigateApp = (appId: string) => { - if (!appId) { - return; - } + /** + * Navigate to the app and open it + * + * appId - appId of the app + */ + const navigateApp = (appId: string) => { + if (!appId) { + return; + } - navigate(`/app/${appId}/edit`); - }; + navigate(`/app/${appId}/edit`); + }; - const isRestricted = !configStore.isEngineOperationAvailable('APP', 'add'); - if (isRestricted) { - return ; - } + const isRestricted = !configStore.isEngineOperationAvailable("APP", "add"); + if (isRestricted) { + return ; + } - const setupApp = (type: 'blocks' | 'code' | 'agent') => { - if (type === 'blocks') { - setNewAppOptions({ - type: 'blocks', - state: { - version: STATE_VERSION, - variables: {}, - queries: {}, - blocks: BASE_PAGE_BLOCKS, - executionOrder: [], - }, - }); - } else if (type === 'code') { - setNewAppOptions({ - type: 'code', - }); - } else if (type === 'agent') { - navigate('/app/new/prompt'); - } - }; + const setupApp = (type: "blocks" | "code" | "agent") => { + if (type === "blocks") { + setNewAppOptions({ + type: "blocks", + state: { + version: STATE_VERSION, + variables: {}, + queries: {}, + blocks: BASE_PAGE_BLOCKS, + executionOrder: [], + }, + }); + } else if (type === "code") { + setNewAppOptions({ + type: "code", + }); + } else if (type === "agent") { + navigate("/app/new/prompt"); + } + }; - return ( - <> - - - - - - - - App Catalog - - - Create - - - - Create New App -   - - - {isUploadOpen ? ( - { - // if there is an appId navigate to it - if (appId) { - navigateApp(appId); - } + return ( + <> + + + + + + + + App Catalog + + + Create + + + + Create New App +   + + + {isUploadOpen ? ( + { + // if there is an appId navigate to it + if (appId) { + navigateApp(appId); + } - // close it - setIsUploadOpen(false); - }} - /> - ) : null} + // close it + setIsUploadOpen(false); + }} + /> + ) : null} - {isNameOpen ? ( - { - if (appId) { - navigateApp(appId); - } else { - // close the modal - setNewAppOptions(null); - } - }} - /> - ) : null} + {isNameOpen ? ( + { + if (appId) { + navigateApp(appId); + } else { + // close the modal + setNewAppOptions(null); + } + }} + /> + ) : null} - - setIsUploadOpen(true)} - /> + + setIsUploadOpen(true)} + /> - - - Start build with a template - - { - setNewAppOptions({ - type: 'blocks', - state: t.state, - }); - }} - /> - - - - - ); + + + Start build with a template + + { + setNewAppOptions({ + type: "blocks", + state: t.state, + }); + }} + /> + + + + + ); }; diff --git a/packages/client/src/pages/app/EditAppPage.tsx b/packages/client/src/pages/app/EditAppPage.tsx index fca6fd0dc5..1c5ca65f53 100644 --- a/packages/client/src/pages/app/EditAppPage.tsx +++ b/packages/client/src/pages/app/EditAppPage.tsx @@ -1,116 +1,113 @@ -import { useEffect, useState } from 'react'; -import { useParams, useNavigate } from 'react-router-dom'; -import { observer } from 'mobx-react-lite'; -import { styled, useNotification } from '@semoss/ui'; - -import { usePage, usePixel, useRootStore } from '@/hooks'; -import { LoadingScreen } from '@/components/ui'; - -import { BlocksWorkspace } from '@/components/blocks-workspace'; -import { CodeWorkspace } from '@/components/code-workspace'; - -import { WorkspaceStore } from '@/stores'; - -const StyledContent = styled('div')(({ theme }) => ({ - position: 'absolute', - inset: 0, - overflow: 'hidden', +import { observer } from "mobx-react-lite"; +import { useEffect, useState } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { styled, useNotification } from "@semoss/ui"; +import { BlocksWorkspace } from "@/components/blocks-workspace"; +import { CodeWorkspace } from "@/components/code-workspace"; +import { LoadingScreen } from "@/components/ui"; +import { usePage, usePixel, useRootStore } from "@/hooks"; +import type { WorkspaceStore } from "@/stores"; + +const StyledContent = styled("div")(({ theme }) => ({ + position: "absolute", + inset: 0, + overflow: "hidden", })); export const EditAppPage = observer(() => { - // App ID Needed for pixel calls - const { appId } = useParams(); - const { configStore } = useRootStore(); - - const notification = useNotification(); - const navigate = useNavigate(); - - // setup the page - usePage({ - showNavbarLogo: false, - }); - - const [workspace, setWorkspace] = useState(undefined); - - const validateDependencies = usePixel( - appId - ? 'ValidateUserProjectDependencies(project="' + appId + '");' - : '', - ); - - useEffect(() => { - let isMounted = true; - if (appId) { - // clear out the old app - setWorkspace(undefined); - - configStore - .createWorkspace(appId) - .then((loadedWorkspace) => { - if (isMounted) { - setWorkspace(loadedWorkspace); - } - }) - .catch((e) => { - notification.add({ - color: 'error', - message: e.message, - }); - - navigate('/'); - }); - } - - return () => { - isMounted = false; - }; - }, [appId]); - - // TODO: Test Comment -> Delete - - useEffect(() => { - if (validateDependencies.status !== 'SUCCESS') { - return; - } else if (validateDependencies.data !== null) { - const needsAccess = []; - Object.entries(validateDependencies.data).forEach((kv) => { - const hasAccess = kv[1]; - - if (!hasAccess) { - needsAccess.push(kv[0]); - } - }); - if (needsAccess.length) { - notification.add({ - color: 'warning', - message: - needsAccess.join(', ') + - '- are dependencies you do not have access to', - }); - } - } - }, [validateDependencies.status, validateDependencies.data]); - - // hide the screen while it loads - if (!workspace) { - return ; - } - - if (workspace.type === 'CODE') { - return ( - - - - ); - } - - if (workspace.type === 'BLOCKS') { - return ( - - - - ); - } - - return null; + // App ID Needed for pixel calls + const { appId } = useParams(); + const { configStore } = useRootStore(); + + const notification = useNotification(); + const navigate = useNavigate(); + + // setup the page + usePage({ + showNavbarLogo: false, + }); + + const [workspace, setWorkspace] = useState(undefined); + + const validateDependencies = usePixel( + appId + ? 'ValidateUserProjectDependencies(project="' + appId + '");' + : "", + ); + + useEffect(() => { + let isMounted = true; + if (appId) { + // clear out the old app + setWorkspace(undefined); + + configStore + .createWorkspace(appId) + .then((loadedWorkspace) => { + if (isMounted) { + setWorkspace(loadedWorkspace); + } + }) + .catch((e) => { + notification.add({ + color: "error", + message: e.message, + }); + + navigate("/"); + }); + } + + return () => { + isMounted = false; + }; + }, [appId]); + + // TODO: Test Comment -> Delete + + useEffect(() => { + if (validateDependencies.status !== "SUCCESS") { + return; + } else if (validateDependencies.data !== null) { + const needsAccess = []; + Object.entries(validateDependencies.data).forEach((kv) => { + const hasAccess = kv[1]; + + if (!hasAccess) { + needsAccess.push(kv[0]); + } + }); + if (needsAccess.length) { + notification.add({ + color: "warning", + message: + needsAccess.join(", ") + + "- are dependencies you do not have access to", + }); + } + } + }, [validateDependencies.status, validateDependencies.data]); + + // hide the screen while it loads + if (!workspace) { + return ; + } + + if (workspace.type === "CODE") { + return ( + + + + ); + } + + if (workspace.type === "BLOCKS") { + return ( + + + + ); + } + + return null; }); diff --git a/packages/client/src/pages/app/NewPromptBuilderAppPage.tsx b/packages/client/src/pages/app/NewPromptBuilderAppPage.tsx index 202bf1eb02..94b20f6023 100644 --- a/packages/client/src/pages/app/NewPromptBuilderAppPage.tsx +++ b/packages/client/src/pages/app/NewPromptBuilderAppPage.tsx @@ -1,18 +1,17 @@ -import { useNavigate } from 'react-router-dom'; - -import { NewAppStep } from '@/components/app'; -import { PromptBuilder } from '@/components/prompt'; -import { NavbarLeft, NavbarHeader } from '../../components/shared'; +import { useNavigate } from "react-router-dom"; +import { NewAppStep } from "@/components/app"; +import { PromptBuilder } from "@/components/prompt"; +import { NavbarHeader, NavbarLeft } from "../../components/shared"; export const NewPromptBuilderAppPage = () => { - return ( - <> - - - - - - - - ); + return ( + <> + + + + + + + + ); }; diff --git a/packages/client/src/pages/app/ViewAppPage.tsx b/packages/client/src/pages/app/ViewAppPage.tsx index 87f3eee814..4f6f4e42a0 100644 --- a/packages/client/src/pages/app/ViewAppPage.tsx +++ b/packages/client/src/pages/app/ViewAppPage.tsx @@ -1,184 +1,182 @@ -import { useEffect, useState } from 'react'; -import { useParams, useNavigate, Link } from 'react-router-dom'; -import { observer } from 'mobx-react-lite'; - import { - styled, - useNotification, - Modal, - Stack, - Tooltip, - IconButton, - Button, - Typography, - Avatar, -} from '@semoss/ui'; -import { Renderer } from '@semoss/renderer'; - -import { WorkspaceStore } from '@/stores'; -import { usePage, useRootStore } from '@/hooks'; -import { LoadingScreen, ShareOverlay } from '@/components/ui'; -import { CodeRenderer } from '@/components/code-workspace'; + Bookmark, + BookmarkBorderOutlined, + EditOutlined, + ShareRounded, +} from "@mui/icons-material"; +import { observer } from "mobx-react-lite"; +import { useEffect, useState } from "react"; +import { Link, useNavigate, useParams } from "react-router-dom"; +import { Renderer } from "@semoss/renderer"; +import { Env } from "@semoss/sdk/react"; import { - EditOutlined, - ShareRounded, - Bookmark, - BookmarkBorderOutlined, -} from '@mui/icons-material'; -import { Env } from '@semoss/sdk/react'; -import { NavbarLeft, NavbarHeader, NavbarRight } from '../../components/shared'; + Avatar, + Button, + IconButton, + Modal, + Stack, + styled, + Tooltip, + Typography, + useNotification, +} from "@semoss/ui"; +import { CodeRenderer } from "@/components/code-workspace"; +import { LoadingScreen, ShareOverlay } from "@/components/ui"; +import { usePage, useRootStore } from "@/hooks"; +import type { WorkspaceStore } from "@/stores"; +import { NavbarHeader, NavbarLeft, NavbarRight } from "../../components/shared"; -const StyledContent = styled('div')(({ theme }) => ({ - position: 'absolute', - inset: 0, - overflow: 'hidden', +const StyledContent = styled("div")(({ theme }) => ({ + position: "absolute", + inset: 0, + overflow: "hidden", })); export const ViewAppPage = observer(() => { - // App ID Needed for pixel calls - const { appId } = useParams(); - const { configStore, monolithStore } = useRootStore(); + // App ID Needed for pixel calls + const { appId } = useParams(); + const { configStore, monolithStore } = useRootStore(); - const notification = useNotification(); - const navigate = useNavigate(); + const notification = useNotification(); + const navigate = useNavigate(); - const [workspace, setWorkspace] = useState(undefined); - const [isShareOpen, setIsShareOpen] = useState(false); - const [bookmarked, setBookmarked] = useState(false); + const [workspace, setWorkspace] = useState(undefined); + const [isShareOpen, setIsShareOpen] = useState(false); + const [bookmarked, setBookmarked] = useState(false); - const handleBookmark = (status: boolean) => { - setBookmarked(status); - monolithStore - .setProjectFavorite(appId, status) - .then(() => { - notification.add({ - color: 'success', - message: `Project ${ - bookmarked ? 'unbookmarked' : 'bookmarked' - }`, - }); - return; - }) - .catch((err) => { - // throw error if promise doesn't fulfill - throw Error(err); - }); - }; + const handleBookmark = (status: boolean) => { + setBookmarked(status); + monolithStore + .setProjectFavorite(appId, status) + .then(() => { + notification.add({ + color: "success", + message: `Project ${ + bookmarked ? "unbookmarked" : "bookmarked" + }`, + }); + return; + }) + .catch((err) => { + // throw error if promise doesn't fulfill + throw Error(err); + }); + }; - // setup the page - usePage({ - showNavbarLogo: false, - }); + // setup the page + usePage({ + showNavbarLogo: false, + }); - useEffect(() => { - // clear out the old app - setWorkspace(undefined); + useEffect(() => { + // clear out the old app + setWorkspace(undefined); - configStore - .createWorkspace(appId) - .then((loadedWorkspace) => { - setWorkspace(loadedWorkspace); - setBookmarked( - Boolean(loadedWorkspace.metadata.project_favorite), - ); - }) - .catch((e) => { - notification.add({ - color: 'error', - message: e.message, - }); + configStore + .createWorkspace(appId) + .then((loadedWorkspace) => { + setWorkspace(loadedWorkspace); + setBookmarked( + Boolean(loadedWorkspace.metadata.project_favorite), + ); + }) + .catch((e) => { + notification.add({ + color: "error", + message: e.message, + }); - navigate('/'); - }); - }, [appId]); + navigate("/"); + }); + }, [appId]); - // hide the screen while it loads - if (!workspace) { - return ; - } + // hide the screen while it loads + if (!workspace) { + return ; + } - return ( - <> - - - - - {workspace.metadata.project_name} - - - } - /> - - - - handleBookmark(!bookmarked)} - data-testid={'app-page-bookmark-btn'} - > - {bookmarked ? ( - - ) : ( - - )} - - - - { - setIsShareOpen(true); - }} - data-testid={'app-page-share-btn'} - > - - - - - - - {workspace.type === 'BLOCKS' ? ( - - ) : null} - {workspace.type === 'CODE' ? ( - - ) : null} - + return ( + <> + + + + + {workspace.metadata.project_name} + + + } + /> + + + + handleBookmark(!bookmarked)} + data-testid={"app-page-bookmark-btn"} + > + {bookmarked ? ( + + ) : ( + + )} + + + + { + setIsShareOpen(true); + }} + data-testid={"app-page-share-btn"} + > + + + + + + + {workspace.type === "BLOCKS" ? ( + + ) : null} + {workspace.type === "CODE" ? ( + + ) : null} + - setIsShareOpen(false)}> - setIsShareOpen(false)} - /> - - - ); + setIsShareOpen(false)}> + setIsShareOpen(false)} + /> + + + ); }); diff --git a/packages/client/src/pages/app/app.constants.ts b/packages/client/src/pages/app/app.constants.ts index 05c245223c..5524ce6b89 100644 --- a/packages/client/src/pages/app/app.constants.ts +++ b/packages/client/src/pages/app/app.constants.ts @@ -1,85 +1,85 @@ -import { Block } from '@semoss/renderer'; +import type { Block } from "@semoss/renderer"; export const BASE_PAGE_BLOCKS: Record = { - 'page-1': { - id: 'page-1', - widget: 'page', - parent: null, - data: { - style: { - display: 'flex', - flexDirection: 'column', - padding: '24px', - gap: '8px', - fontFamily: 'roboto', - }, - route: '', - }, - listeners: { - onPageLoad: { - type: 'sync', - order: [], - }, - }, - slots: { - content: { - name: 'content', - children: ['container--1'], - }, - }, - }, - 'container--1': { - id: 'container--1', - widget: 'container', - parent: { - id: 'page-1', - slot: 'content', - }, - data: { - style: { - display: 'flex', - flexDirection: 'column', - flexWrap: 'wrap', - padding: '4px', - gap: '8px', - overflow: 'hidden', - }, - }, - listeners: { - preProcess: { - type: 'sync', - order: [], - }, - }, - slots: { - children: { - name: 'children', - children: ['text--1'], - }, - }, - }, - 'text--1': { - id: 'text--1', - widget: 'text', - parent: { - id: 'container--1', - slot: 'children', - }, - data: { - style: { - padding: '4px', - whiteSpace: 'pre-line', - textOverflow: 'ellipsis', - overflow: 'auto', - }, - text: 'Welcome to the UI Builder! Drag and drop blocks to use in your app.', - }, - listeners: { - preProcess: { - type: 'sync', - order: [], - }, - }, - slots: {}, - }, + "page-1": { + id: "page-1", + widget: "page", + parent: null, + data: { + style: { + display: "flex", + flexDirection: "column", + padding: "24px", + gap: "8px", + fontFamily: "roboto", + }, + route: "", + }, + listeners: { + onPageLoad: { + type: "sync", + order: [], + }, + }, + slots: { + content: { + name: "content", + children: ["container--1"], + }, + }, + }, + "container--1": { + id: "container--1", + widget: "container", + parent: { + id: "page-1", + slot: "content", + }, + data: { + style: { + display: "flex", + flexDirection: "column", + flexWrap: "wrap", + padding: "4px", + gap: "8px", + overflow: "hidden", + }, + }, + listeners: { + preProcess: { + type: "sync", + order: [], + }, + }, + slots: { + children: { + name: "children", + children: ["text--1"], + }, + }, + }, + "text--1": { + id: "text--1", + widget: "text", + parent: { + id: "container--1", + slot: "children", + }, + data: { + style: { + padding: "4px", + whiteSpace: "pre-line", + textOverflow: "ellipsis", + overflow: "auto", + }, + text: "Welcome to the UI Builder! Drag and drop blocks to use in your app.", + }, + listeners: { + preProcess: { + type: "sync", + order: [], + }, + }, + slots: {}, + }, }; diff --git a/packages/client/src/pages/app/index.ts b/packages/client/src/pages/app/index.ts index dbd1f5ad54..00831ed4c7 100644 --- a/packages/client/src/pages/app/index.ts +++ b/packages/client/src/pages/app/index.ts @@ -1,17 +1,17 @@ -import { AppCatalogPage } from './AppCatalogPage'; -import { AppMarketplacePage } from './AppMarketplacePage'; -import { AppDetailPage } from './AppDetailPage'; -import { ViewAppPage } from './ViewAppPage'; -import { NewPromptBuilderAppPage } from './NewPromptBuilderAppPage'; -import { CreateAppPage } from './CreateAppPage'; -import { EditAppPage } from './EditAppPage'; +import { AppCatalogPage } from "./AppCatalogPage"; +import { AppDetailPage } from "./AppDetailPage"; +import { AppMarketplacePage } from "./AppMarketplacePage"; +import { CreateAppPage } from "./CreateAppPage"; +import { EditAppPage } from "./EditAppPage"; +import { NewPromptBuilderAppPage } from "./NewPromptBuilderAppPage"; +import { ViewAppPage } from "./ViewAppPage"; export { - AppCatalogPage, - AppMarketplacePage, - AppDetailPage, - ViewAppPage, - CreateAppPage, - EditAppPage, - NewPromptBuilderAppPage, + AppCatalogPage, + AppMarketplacePage, + AppDetailPage, + ViewAppPage, + CreateAppPage, + EditAppPage, + NewPromptBuilderAppPage, }; diff --git a/packages/client/src/pages/engine/EngineFilePage.tsx b/packages/client/src/pages/engine/EngineFilePage.tsx index d4e6f32378..e72f40b50d 100644 --- a/packages/client/src/pages/engine/EngineFilePage.tsx +++ b/packages/client/src/pages/engine/EngineFilePage.tsx @@ -1,42 +1,42 @@ -import { Table, styled, Typography } from '@semoss/ui'; -import { useEngine } from '@/hooks'; -import { FileTable } from '@/components/settings'; +import { styled, Table, Typography } from "@semoss/ui"; +import { FileTable } from "@/components/settings"; +import { useEngine } from "@/hooks"; -const StyledContainer = styled('div')(({ theme }) => ({ - width: '100%', - display: 'flex', - alignSelf: 'stretch', - flexDirection: 'column', - alignItems: 'flex-start', - gap: theme.spacing(3), +const StyledContainer = styled("div")(({ theme }) => ({ + width: "100%", + display: "flex", + alignSelf: "stretch", + flexDirection: "column", + alignItems: "flex-start", + gap: theme.spacing(3), })); const StyledTableContainer = styled(Table.Container)({ - borderRadius: '12px', - // background: #FFF; - /* Devias Drop Shadow */ - boxShadow: '0px 5px 22px 0px rgba(0, 0, 0, 0.06)', + borderRadius: "12px", + // background: #FFF; + /* Devias Drop Shadow */ + boxShadow: "0px 5px 22px 0px rgba(0, 0, 0, 0.06)", }); -const StyledTopDiv = styled('div')(() => ({ - display: 'flex', - width: '100%', - justifyContent: 'space-between', +const StyledTopDiv = styled("div")(() => ({ + display: "flex", + width: "100%", + justifyContent: "space-between", })); export const EngineFilePage = () => { - //Grabbing Engine Id for document creation - const { active } = useEngine(); + //Grabbing Engine Id for document creation + const { active } = useEngine(); - return ( - - - File Explorer - + return ( + + + File Explorer + - - - - - ); + + + + + ); }; diff --git a/packages/client/src/pages/engine/EngineIndexPage.tsx b/packages/client/src/pages/engine/EngineIndexPage.tsx index 451e189e7f..52c5dff570 100644 --- a/packages/client/src/pages/engine/EngineIndexPage.tsx +++ b/packages/client/src/pages/engine/EngineIndexPage.tsx @@ -1,91 +1,89 @@ -import { useEffect, useState, useReducer, useRef, useMemo } from 'react'; -import { observer } from 'mobx-react-lite'; +import { observer } from "mobx-react-lite"; +import { useEffect, useMemo, useReducer, useRef, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { debounced } from "@semoss/sdk/react"; import { - styled, - Stack, - Typography, - Button, - ToggleTabsGroup, - Grid, - TextField, -} from '@semoss/ui'; -import { debounced } from '@semoss/sdk/react'; - -import { useNavigate } from 'react-router-dom'; - -import { ENGINE_TYPES } from '@/types'; -import { usePixel, useRootStore } from '@/hooks'; -import { EngineLandscapeCard } from '@/components/engine'; -import { Filterbox } from '@/components/ui'; -import { Help } from '@/components/help'; -import { ENGINE_ROUTES } from './engine.constants'; -import { removeUnderscores } from '@/utility'; - -const StyledContainer = styled('div')(({ theme }) => ({ - display: 'flex', - height: '100%', - gap: theme.spacing(3), - paddingTop: theme.spacing(1), - paddingBottom: theme.spacing(1), + Button, + Grid, + Stack, + styled, + TextField, + ToggleTabsGroup, + Typography, +} from "@semoss/ui"; +import { EngineLandscapeCard } from "@/components/engine"; +import { Help } from "@/components/help"; +import { Filterbox } from "@/components/ui"; +import { usePixel, useRootStore } from "@/hooks"; +import { ENGINE_TYPES } from "@/types"; +import { removeUnderscores } from "@/utility"; +import type { ENGINE_ROUTES } from "./engine.constants"; + +const StyledContainer = styled("div")(({ theme }) => ({ + display: "flex", + height: "100%", + gap: theme.spacing(3), + paddingTop: theme.spacing(1), + paddingBottom: theme.spacing(1), })); -const StyledContent = styled('div')(({ theme }) => ({ - display: 'flex', - flexDirection: 'column', - height: '100%', - flex: '1', - width: '100%', - gap: theme.spacing(3), +const StyledContent = styled("div")(({ theme }) => ({ + display: "flex", + flexDirection: "column", + height: "100%", + flex: "1", + width: "100%", + gap: theme.spacing(3), })); const StyledSectionLabel = styled(Typography)(() => ({ - size: '16px', - fontWeight: '500', + size: "16px", + fontWeight: "500", })); const StyledToggleTabsGroup = styled(ToggleTabsGroup)(({ theme }) => ({ - border: '1px', - minHeight: '42px', - color: theme.palette.secondary.light, - borderRadius: theme.shape.borderRadius, - alignItems: 'center', - padding: '0px 3px', + border: "1px", + minHeight: "42px", + color: theme.palette.secondary.light, + borderRadius: theme.shape.borderRadius, + alignItems: "center", + padding: "0px 3px", })); const StyledToggleTabsGroupItem = styled(ToggleTabsGroup.Item)(({ theme }) => ({ - height: '38px', - padding: '8px 11px', - '&.MuiTab-root': { - borderRadius: theme.shape.borderRadius, - }, - '&.Mui-selected': { - boxShadow: '0px 4px 4px 0px rgba(0, 0, 0, 0.05)', - }, + height: "38px", + padding: "8px 11px", + "&.MuiTab-root": { + borderRadius: theme.shape.borderRadius, + }, + "&.Mui-selected": { + boxShadow: "0px 4px 4px 0px rgba(0, 0, 0, 0.05)", + }, })); const initialState = { - favoritedDbs: [], - databases: [], - filterSearch: '', + favoritedDbs: [], + databases: [], + filterSearch: "", }; -type MODE = 'Mine' | 'Discoverable'; +type MODE = "Mine" | "Discoverable"; const reducer = (state, action) => { - switch (action.type) { - case 'field': { - return { - ...state, - [action.field]: action.value, - }; - } - } - return state; + switch (action.type) { + case "field": { + return { + ...state, + [action.field]: action.value, + }; + } + } + return state; }; interface EngineIndexPageProps { - /** Route to render */ - route: (typeof ENGINE_ROUTES)[number]; + /** Route to render */ + route: (typeof ENGINE_ROUTES)[number]; } /** @@ -93,619 +91,619 @@ interface EngineIndexPageProps { * Landing page to view the available engines */ export const EngineIndexPage: React.FC = observer( - ({ route }): JSX.Element => { - // get the matching route - const routeTypeRef = useRef(''); - - const { configStore, monolithStore } = useRootStore(); - const navigate = useNavigate(); - - // get a list of the keys - const databaseMetaKeys = - configStore.store.config.databaseMetaKeys.filter((k) => { - return ( - k.display_options === 'single-checklist' || - k.display_options === 'multi-checklist' || - k.display_options === 'single-select' || - k.display_options === 'multi-select' || - k.display_options === 'single-typeahead' || - k.display_options === 'multi-typeahead' || - k.display_options === 'select-box' - ); - }); - - // get metakeys to the ones we want - const metaKeys = databaseMetaKeys.map((k) => { - return k.metakey; - }); - - const [state, dispatch] = useReducer(reducer, initialState); - const { favoritedDbs, databases } = state; - - const [offset, setOffset] = useState(0); - const [canCollect, setCanCollect] = useState(true); - const canCollectRef = useRef(true); - canCollectRef.current = canCollect; - const limit = 10; - - const offsetRef = useRef(0); - offsetRef.current = offset; - let scrollEle, scrollTimeout, currentScroll, previousScroll; - - const [inputValue, setInputValue] = useState(''); - const [search, setSearch] = useState(''); - - // which view we are on - const [mode, setMode] = useState('Mine'); - const [metaFilters, setMetaFilters] = useState>( - {}, - ); - - const dbPixelPrefix: string = - mode === 'Mine' ? `MyEngines` : 'MyDiscoverableEngines'; - - const isDiscoverable = mode !== 'Mine'; - - const metaKeysDescription = [...metaKeys, 'description']; - - const getFavoritedDatabases = usePixel( - !isDiscoverable && - ` + ({ route }): JSX.Element => { + // get the matching route + const routeTypeRef = useRef(""); + + const { configStore, monolithStore } = useRootStore(); + const navigate = useNavigate(); + + // get a list of the keys + const databaseMetaKeys = + configStore.store.config.databaseMetaKeys.filter((k) => { + return ( + k.display_options === "single-checklist" || + k.display_options === "multi-checklist" || + k.display_options === "single-select" || + k.display_options === "multi-select" || + k.display_options === "single-typeahead" || + k.display_options === "multi-typeahead" || + k.display_options === "select-box" + ); + }); + + // get metakeys to the ones we want + const metaKeys = databaseMetaKeys.map((k) => { + return k.metakey; + }); + + const [state, dispatch] = useReducer(reducer, initialState); + const { favoritedDbs, databases } = state; + + const [offset, setOffset] = useState(0); + const [canCollect, setCanCollect] = useState(true); + const canCollectRef = useRef(true); + canCollectRef.current = canCollect; + const limit = 10; + + const offsetRef = useRef(0); + offsetRef.current = offset; + let scrollEle, scrollTimeout, currentScroll, previousScroll; + + const [inputValue, setInputValue] = useState(""); + const [search, setSearch] = useState(""); + + // which view we are on + const [mode, setMode] = useState("Mine"); + const [metaFilters, setMetaFilters] = useState>( + {}, + ); + + const dbPixelPrefix: string = + mode === "Mine" ? `MyEngines` : "MyDiscoverableEngines"; + + const isDiscoverable = mode !== "Mine"; + + const metaKeysDescription = [...metaKeys, "description"]; + + const getFavoritedDatabases = usePixel( + !isDiscoverable && + ` ${dbPixelPrefix}(metaKeys = ${JSON.stringify( - metaKeysDescription, - )}, metaFilters = [ ${JSON.stringify( - metaFilters, - )} ] , filterWord=["${search}"], onlyFavorites=[true], ${ - route ? `engineTypes=['${route.type}']` : '' - }); + metaKeysDescription, + )}, metaFilters = [ ${JSON.stringify( + metaFilters, + )} ] , filterWord=["${search}"], onlyFavorites=[true], ${ + route ? `engineTypes=['${route.type}']` : "" + }); `, - ); - - const getDatabases = usePixel< - { - app_cost: string; - app_id: string; - app_name: string; - app_type: string; - database_cost: string; - database_global: boolean; - database_id: string; - database_name: string; - database_type: string; - database_created_by: string; - database_date_created: string; - description: string; - low_database_name: string; - permission: number; - tag: string; - user_permission: number; - upvotes: number; - }[] - >( - `${dbPixelPrefix}( metaKeys = ${JSON.stringify( - metaKeysDescription, - )} , metaFilters = [ ${JSON.stringify( - metaFilters, - )} ] , filterWord=["${search}"], userT = [true], ${ - route ? `engineTypes=['${route.type}'], ` : '' - } offset=[${offset}], limit=[${limit}]) ;`, - ); - - const getCatalogFilters = usePixel< - { - METAKEY: string; - METAVALUE: string; - count: number; - }[] - >( - metaKeys.length > 0 - ? `GetEngineMetaValues( ${ - route ? `engineTypes=['${route.type}'], ` : '' - } metaKeys = ${JSON.stringify(metaKeys)} ) ;` - : '', - ); - - const debouncedSet = debounced((newInputValue) => { - setSearch(newInputValue); - }, 300); - - const handleInputChange = (newInputValue) => { - setInputValue(newInputValue); - debouncedSet(newInputValue); - }; - - /** - * @name setGlobal - * @param db - */ - const setGlobal = (db) => { - monolithStore - .setEngineGlobal( - configStore.store.user.admin, - db.database_id, - !db.database_global, - ) - .then((response) => { - if (response.data.success) { - const newDatabases = []; - databases.forEach((database) => { - if (database.database_id === db.database_id) { - const newCopy = database; - newCopy.database_global = !db.database_global; - - newDatabases.push(newCopy); - } else { - newDatabases.push(database); - } - }); - - dispatch({ - type: 'field', - field: 'database', - value: newDatabases, - }); - } - }) - .catch((error) => { - console.error(error); - }); - }; - - /** - * @name favoriteDb - * @param db - */ - const favoriteDb = (db) => { - const favorite = !isFavorited(db.database_id); - monolithStore - .setEngineFavorite(db.database_id, favorite) - .then(() => { - if (!favorite) { - const newFavorites = favoritedDbs; - for (let i = newFavorites.length - 1; i >= 0; i--) { - if ( - newFavorites[i].database_id === db.database_id - ) { - newFavorites.splice(i, 1); - } - } - - dispatch({ - type: 'field', - field: 'favoritedDbs', - value: newFavorites, - }); - } else { - dispatch({ - type: 'field', - field: 'favoritedDbs', - value: [...favoritedDbs, db], - }); - } - }) - .catch((err) => { - // throw error if promise doesn't fulfill - throw Error(err); - }); - }; - - /** - * @name isFavorited - * @param id - * @desc determines if card is favorited - */ - const isFavorited = (id) => { - const favorites = favoritedDbs; - - if (!favorites) return false; - return favorites.some((el) => el.database_id === id); - }; - - /** - * @name upvoteDb - * @param db - */ - const upvoteDb = (db) => { - let pixelString = ''; - - if (!db.hasUpvoted) { - pixelString += `VoteEngine(engine="${db.database_id}", vote=1)`; - } else { - pixelString += `UnvoteEngine(engine="${db.database_id}")`; - } - - monolithStore.runQuery(pixelString).then((response) => { - const type = response.pixelReturn[0].operationType; - const pixelResponse = response.pixelReturn[0].output; - - if (type.indexOf('ERROR') === -1) { - const newDatabases = []; - - databases.forEach((database) => { - if (database.database_id === db.database_id) { - const newCopy = database; - newCopy.upvotes = !db.hasUpvoted - ? newCopy.upvotes + 1 - : newCopy.upvotes - 1; - newCopy.hasUpvoted = !db.hasUpvoted ? true : false; - - newDatabases.push(newCopy); - } else { - newDatabases.push(database); - } - }); - - dispatch({ - type: 'field', - field: 'database', - value: newDatabases, - }); - } else { - console.error('Error voting for DB'); - } - }); - }; - - const scrollAll = () => { - currentScroll = scrollEle.scrollTop + scrollEle.offsetHeight; - if ( - currentScroll > scrollEle.scrollHeight * 0.75 && - currentScroll > previousScroll - ) { - if (scrollTimeout) { - clearTimeout(scrollTimeout); - } - - scrollTimeout = setTimeout(() => { - if (!canCollectRef.current) { - return; - } - - setOffset(offsetRef.current + limit); - }, 500); - } - - previousScroll = currentScroll; - }; - - /** - * @desc anytime we change catalogType clean up engines - */ - useEffect(() => { - // Prevent cleanup on first render. - if (routeTypeRef.current === '') { - routeTypeRef.current = route.type; - return; - } - - dispatch({ - type: 'field', - field: 'databases', - value: [], - }); - setCanCollect(true); - setOffset(0); - setMetaFilters({}); - routeTypeRef.current = route.type; - }, [route.type]); - - /** - * @desc Set Databases - */ - useEffect(() => { - if (getDatabases.status !== 'SUCCESS') { - return; - } - - if (getDatabases.data.length < limit) { - setCanCollect(false); - } else { - if (!canCollectRef.current) { - setCanCollect(true); - } - } - - const mutateListWithVotes = databases; - - getDatabases.data.forEach((db) => { - mutateListWithVotes.push({ - ...db, - upvotes: db.upvotes ? db.upvotes : 0, - views: 'N/A', - trending: 'N/A', - }); - }); - - dispatch({ - type: 'field', - field: 'databases', - value: mutateListWithVotes, - }); - }, [getDatabases.status, getDatabases.data]); - - /** - * @desc Sets Favorited Engines - */ - useEffect(() => { - if (getFavoritedDatabases.status !== 'SUCCESS') { - return; - } - - dispatch({ - type: 'field', - field: 'favoritedDbs', - value: getFavoritedDatabases.data, - }); - }, [getFavoritedDatabases.status, getFavoritedDatabases.data]); - - /** - * @desc infinite scroll - */ - useEffect(() => { - scrollEle = document.querySelector('#home__content'); - - scrollEle.addEventListener('scroll', scrollAll); - return () => { - scrollEle.removeEventListener('scroll', scrollAll); - }; - }, [scrollEle]); - - /** - * Reset tiles anytime search changes - */ - useEffect(() => { - dispatch({ - type: 'field', - field: 'databases', - value: [], - }); - setOffset(0); - }, [search]); - - // finish loading the page - if ( - getDatabases.status === 'ERROR' || - getCatalogFilters.status === 'ERROR' - ) { - return <>ERROR; - } - - return ( - - - - - {route ? route.name : ''} Catalog - - - {configStore.isEngineOperationAvailable( - route.type, - 'add', - ) && ( - - - - )} - - - - {route ? route.description : ''} - - - - handleInputChange(e.target.value)} - /> - - ) => { - dispatch({ - type: 'field', - field: 'databases', - value: [], - }); - setMetaFilters(filters); - setOffset(0); - }} - /> - - - { - dispatch({ - type: 'field', - field: 'databases', - value: [], - }); - setMode(val as MODE); - setOffset(0); - }} - > - - - - - - {'bi'.includes(search.toLowerCase()) && - Object.entries(metaFilters).length === 0 && - 'terminal'.includes(search.toLowerCase()) && - !isDiscoverable && - favoritedDbs.length > 0 && ( - - Bookmarked - - )} - - {!isDiscoverable && - favoritedDbs.length && - Object.entries(metaFilters).length === 0 ? ( - - {favoritedDbs.map((db) => { - return ( - - { - navigate( - `${db.database_id}`, - ); - }} - favorite={() => { - favoriteDb(db); - }} - upvote={() => { - upvoteDb(db); - }} - global={ - db.user_permission === 1 - ? () => { - setGlobal(db); - } - : null - } - /> - - ); - })} - - ) : null} - - {'bi'.includes(search.toLowerCase()) && - Object.entries(metaFilters).length === 0 && - 'terminal'.includes(search.toLowerCase()) && - databases.length > 0 && ( - - All {route.name}s - - )} - - {databases.length ? ( - - {databases.map((db) => { - return ( - - { - navigate( - `${db.database_id}`, - ); - }} - favorite={() => { - favoriteDb(db); - }} - upvote={() => { - upvoteDb(db); - }} - global={ - db.user_permission === 1 - ? () => { - setGlobal(db); - } - : null - } - /> - - ); - })} - - ) : null} - - - - - ); - }, + ); + + const getDatabases = usePixel< + { + app_cost: string; + app_id: string; + app_name: string; + app_type: string; + database_cost: string; + database_global: boolean; + database_id: string; + database_name: string; + database_type: string; + database_created_by: string; + database_date_created: string; + description: string; + low_database_name: string; + permission: number; + tag: string; + user_permission: number; + upvotes: number; + }[] + >( + `${dbPixelPrefix}( metaKeys = ${JSON.stringify( + metaKeysDescription, + )} , metaFilters = [ ${JSON.stringify( + metaFilters, + )} ] , filterWord=["${search}"], userT = [true], ${ + route ? `engineTypes=['${route.type}'], ` : "" + } offset=[${offset}], limit=[${limit}]) ;`, + ); + + const getCatalogFilters = usePixel< + { + METAKEY: string; + METAVALUE: string; + count: number; + }[] + >( + metaKeys.length > 0 + ? `GetEngineMetaValues( ${ + route ? `engineTypes=['${route.type}'], ` : "" + } metaKeys = ${JSON.stringify(metaKeys)} ) ;` + : "", + ); + + const debouncedSet = debounced((newInputValue) => { + setSearch(newInputValue); + }, 300); + + const handleInputChange = (newInputValue) => { + setInputValue(newInputValue); + debouncedSet(newInputValue); + }; + + /** + * @name setGlobal + * @param db + */ + const setGlobal = (db) => { + monolithStore + .setEngineGlobal( + configStore.store.user.admin, + db.database_id, + !db.database_global, + ) + .then((response) => { + if (response.data.success) { + const newDatabases = []; + databases.forEach((database) => { + if (database.database_id === db.database_id) { + const newCopy = database; + newCopy.database_global = !db.database_global; + + newDatabases.push(newCopy); + } else { + newDatabases.push(database); + } + }); + + dispatch({ + type: "field", + field: "database", + value: newDatabases, + }); + } + }) + .catch((error) => { + console.error(error); + }); + }; + + /** + * @name favoriteDb + * @param db + */ + const favoriteDb = (db) => { + const favorite = !isFavorited(db.database_id); + monolithStore + .setEngineFavorite(db.database_id, favorite) + .then(() => { + if (!favorite) { + const newFavorites = favoritedDbs; + for (let i = newFavorites.length - 1; i >= 0; i--) { + if ( + newFavorites[i].database_id === db.database_id + ) { + newFavorites.splice(i, 1); + } + } + + dispatch({ + type: "field", + field: "favoritedDbs", + value: newFavorites, + }); + } else { + dispatch({ + type: "field", + field: "favoritedDbs", + value: [...favoritedDbs, db], + }); + } + }) + .catch((err) => { + // throw error if promise doesn't fulfill + throw Error(err); + }); + }; + + /** + * @name isFavorited + * @param id + * @desc determines if card is favorited + */ + const isFavorited = (id) => { + const favorites = favoritedDbs; + + if (!favorites) return false; + return favorites.some((el) => el.database_id === id); + }; + + /** + * @name upvoteDb + * @param db + */ + const upvoteDb = (db) => { + let pixelString = ""; + + if (!db.hasUpvoted) { + pixelString += `VoteEngine(engine="${db.database_id}", vote=1)`; + } else { + pixelString += `UnvoteEngine(engine="${db.database_id}")`; + } + + monolithStore.runQuery(pixelString).then((response) => { + const type = response.pixelReturn[0].operationType; + const pixelResponse = response.pixelReturn[0].output; + + if (type.indexOf("ERROR") === -1) { + const newDatabases = []; + + databases.forEach((database) => { + if (database.database_id === db.database_id) { + const newCopy = database; + newCopy.upvotes = !db.hasUpvoted + ? newCopy.upvotes + 1 + : newCopy.upvotes - 1; + newCopy.hasUpvoted = !db.hasUpvoted ? true : false; + + newDatabases.push(newCopy); + } else { + newDatabases.push(database); + } + }); + + dispatch({ + type: "field", + field: "database", + value: newDatabases, + }); + } else { + console.error("Error voting for DB"); + } + }); + }; + + const scrollAll = () => { + currentScroll = scrollEle.scrollTop + scrollEle.offsetHeight; + if ( + currentScroll > scrollEle.scrollHeight * 0.75 && + currentScroll > previousScroll + ) { + if (scrollTimeout) { + clearTimeout(scrollTimeout); + } + + scrollTimeout = setTimeout(() => { + if (!canCollectRef.current) { + return; + } + + setOffset(offsetRef.current + limit); + }, 500); + } + + previousScroll = currentScroll; + }; + + /** + * @desc anytime we change catalogType clean up engines + */ + useEffect(() => { + // Prevent cleanup on first render. + if (routeTypeRef.current === "") { + routeTypeRef.current = route.type; + return; + } + + dispatch({ + type: "field", + field: "databases", + value: [], + }); + setCanCollect(true); + setOffset(0); + setMetaFilters({}); + routeTypeRef.current = route.type; + }, [route.type]); + + /** + * @desc Set Databases + */ + useEffect(() => { + if (getDatabases.status !== "SUCCESS") { + return; + } + + if (getDatabases.data.length < limit) { + setCanCollect(false); + } else { + if (!canCollectRef.current) { + setCanCollect(true); + } + } + + const mutateListWithVotes = databases; + + getDatabases.data.forEach((db) => { + mutateListWithVotes.push({ + ...db, + upvotes: db.upvotes ? db.upvotes : 0, + views: "N/A", + trending: "N/A", + }); + }); + + dispatch({ + type: "field", + field: "databases", + value: mutateListWithVotes, + }); + }, [getDatabases.status, getDatabases.data]); + + /** + * @desc Sets Favorited Engines + */ + useEffect(() => { + if (getFavoritedDatabases.status !== "SUCCESS") { + return; + } + + dispatch({ + type: "field", + field: "favoritedDbs", + value: getFavoritedDatabases.data, + }); + }, [getFavoritedDatabases.status, getFavoritedDatabases.data]); + + /** + * @desc infinite scroll + */ + useEffect(() => { + scrollEle = document.querySelector("#home__content"); + + scrollEle.addEventListener("scroll", scrollAll); + return () => { + scrollEle.removeEventListener("scroll", scrollAll); + }; + }, [scrollEle]); + + /** + * Reset tiles anytime search changes + */ + useEffect(() => { + dispatch({ + type: "field", + field: "databases", + value: [], + }); + setOffset(0); + }, [search]); + + // finish loading the page + if ( + getDatabases.status === "ERROR" || + getCatalogFilters.status === "ERROR" + ) { + return <>ERROR; + } + + return ( + + + + + {route ? route.name : ""} Catalog + + + {configStore.isEngineOperationAvailable( + route.type, + "add", + ) && ( + + + + )} + + + + {route ? route.description : ""} + + + + handleInputChange(e.target.value)} + /> + + ) => { + dispatch({ + type: "field", + field: "databases", + value: [], + }); + setMetaFilters(filters); + setOffset(0); + }} + /> + + + { + dispatch({ + type: "field", + field: "databases", + value: [], + }); + setMode(val as MODE); + setOffset(0); + }} + > + + + + + + {"bi".includes(search.toLowerCase()) && + Object.entries(metaFilters).length === 0 && + "terminal".includes(search.toLowerCase()) && + !isDiscoverable && + favoritedDbs.length > 0 && ( + + Bookmarked + + )} + + {!isDiscoverable && + favoritedDbs.length && + Object.entries(metaFilters).length === 0 ? ( + + {favoritedDbs.map((db) => { + return ( + + { + navigate( + `${db.database_id}`, + ); + }} + favorite={() => { + favoriteDb(db); + }} + upvote={() => { + upvoteDb(db); + }} + global={ + db.user_permission === 1 + ? () => { + setGlobal(db); + } + : null + } + /> + + ); + })} + + ) : null} + + {"bi".includes(search.toLowerCase()) && + Object.entries(metaFilters).length === 0 && + "terminal".includes(search.toLowerCase()) && + databases.length > 0 && ( + + All {route.name}s + + )} + + {databases.length ? ( + + {databases.map((db) => { + return ( + + { + navigate( + `${db.database_id}`, + ); + }} + favorite={() => { + favoriteDb(db); + }} + upvote={() => { + upvoteDb(db); + }} + global={ + db.user_permission === 1 + ? () => { + setGlobal(db); + } + : null + } + /> + + ); + })} + + ) : null} + + + + + ); + }, ); diff --git a/packages/client/src/pages/engine/EngineLayout.tsx b/packages/client/src/pages/engine/EngineLayout.tsx index 6989870b89..f40b796198 100644 --- a/packages/client/src/pages/engine/EngineLayout.tsx +++ b/packages/client/src/pages/engine/EngineLayout.tsx @@ -1,261 +1,258 @@ -import { SyntheticEvent, useMemo } from 'react'; +import { type SyntheticEvent, useMemo } from "react"; import { - useParams, - useLocation, - useResolvedPath, - Outlet, - Navigate, - matchPath, - useNavigate, -} from 'react-router-dom'; -import { Stack, styled, ToggleTabsGroup } from '@semoss/ui'; -import { usePixel } from '@semoss/sdk/react'; - -import { EngineContext } from '@/contexts'; -import { useAPI, useRootStore, useSettings } from '@/hooks'; - -import { LoadingScreen } from '@/components/ui'; -import { EngineHeader } from '@/components/engine'; - -import { ENGINE_ROUTES } from './engine.constants'; -import { removeUnderscores } from '@/utility'; + matchPath, + Navigate, + Outlet, + useLocation, + useNavigate, + useParams, + useResolvedPath, +} from "react-router-dom"; +import { usePixel } from "@semoss/sdk/react"; +import { Stack, styled, ToggleTabsGroup } from "@semoss/ui"; +import { EngineHeader } from "@/components/engine"; +import { LoadingScreen } from "@/components/ui"; +import { EngineContext } from "@/contexts"; +import { useAPI, useRootStore, useSettings } from "@/hooks"; +import { removeUnderscores } from "@/utility"; +import type { ENGINE_ROUTES } from "./engine.constants"; const StyledToggleTabsGroup = styled(ToggleTabsGroup)(({ theme }) => ({ - alignItems: 'center', - padding: '0px 3px', - height: '42px', - width: '100%', - borderTopLeftRadius: theme.shape.borderRadiusLg, - borderTopRightRadius: theme.shape.borderRadiusLg, - borderBottomRightRadius: 0, - borderBottomLeftRadius: 0, - background: theme.palette.primary.selected, + alignItems: "center", + padding: "0px 3px", + height: "42px", + width: "100%", + borderTopLeftRadius: theme.shape.borderRadiusLg, + borderTopRightRadius: theme.shape.borderRadiusLg, + borderBottomRightRadius: 0, + borderBottomLeftRadius: 0, + background: theme.palette.primary.selected, })); const StyledToggleTabsGroupItem = styled(ToggleTabsGroup.Item)(({ theme }) => ({ - height: '38px', - '&.Mui-selected': { - boxShadow: '0px 4px 4px 0px rgba(0, 0, 0, 0.05)', - borderRadius: '12px', - }, + height: "38px", + "&.Mui-selected": { + boxShadow: "0px 4px 4px 0px rgba(0, 0, 0, 0.05)", + borderRadius: "12px", + }, })); -const StyledContent = styled('div')(({ theme }) => ({ - width: '100%', - padding: theme.spacing(2), - background: theme.palette.background.paper, +const StyledContent = styled("div")(({ theme }) => ({ + width: "100%", + padding: theme.spacing(2), + background: theme.palette.background.paper, })); interface EngineLayoutProps { - /** Rotue to render */ - route: (typeof ENGINE_ROUTES)[number]; + /** Rotue to render */ + route: (typeof ENGINE_ROUTES)[number]; } /** * Wrap the engine routes and add additional funcitonality */ export const EngineLayout: React.FC = ({ route }) => { - const { engineId } = useParams(); - const { configStore } = useRootStore(); - const resolvedPath = useResolvedPath(''); - const { pathname } = useLocation(); - const navigate = useNavigate(); - const { adminMode } = useSettings(); + const { engineId } = useParams(); + const { configStore } = useRootStore(); + const resolvedPath = useResolvedPath(""); + const { pathname } = useLocation(); + const navigate = useNavigate(); + const { adminMode } = useSettings(); - // filter metakeys to the ones we want - const engineMetaKeys = configStore.store.config.databaseMetaKeys.filter( - (k) => { - return ( - k.metakey !== 'description' && - k.metakey !== 'markdown' && - k.metakey !== 'tags' - ); - }, - ); + // filter metakeys to the ones we want + const engineMetaKeys = configStore.store.config.databaseMetaKeys.filter( + (k) => { + return ( + k.metakey !== "description" && + k.metakey !== "markdown" && + k.metakey !== "tags" + ); + }, + ); - // kets to get dbMetaData for - const metaKeys = [ - 'markdown', - 'description', - ...engineMetaKeys.map((k) => k.metakey), - ]; + // kets to get dbMetaData for + const metaKeys = [ + "markdown", + "description", + ...engineMetaKeys.map((k) => k.metakey), + ]; - // get the metadata - const getEngineMetadata = usePixel<{ - database_name?: string; - database_discoverable?: boolean; - database_created_by?: string; - database_date_created?: string; - last_updated?: string; - description?: string; - database_type?: string; - DATEADDED?: string; - PERMISSIONGRANTEDBY?: string; - markdown?: string; - tags?: string[]; - }>( - engineId - ? `GetEngineMetadata(engine=["${engineId}"], metaKeys=${JSON.stringify( - [metaKeys], - )}); ` - : '', - { - data: {}, - }, - ); + // get the metadata + const getEngineMetadata = usePixel<{ + database_name?: string; + database_discoverable?: boolean; + database_created_by?: string; + database_date_created?: string; + last_updated?: string; + description?: string; + database_type?: string; + DATEADDED?: string; + PERMISSIONGRANTEDBY?: string; + markdown?: string; + tags?: string[]; + }>( + engineId + ? `GetEngineMetadata(engine=["${engineId}"], metaKeys=${JSON.stringify( + [metaKeys], + )}); ` + : "", + { + data: {}, + }, + ); - // convert the data into an object - const values = useMemo(() => { - if (getEngineMetadata.status !== 'SUCCESS') { - return {}; - } + // convert the data into an object + const values = useMemo(() => { + if (getEngineMetadata.status !== "SUCCESS") { + return {}; + } - // Storage and Model currently not sending back Tag or Tags - return metaKeys.reduce((prev, curr) => { - // tag, domain, and etc either come in as a string or a string[], format it to correct type - const found = engineMetaKeys.find((obj) => obj.metakey === curr); + // Storage and Model currently not sending back Tag or Tags + return metaKeys.reduce((prev, curr) => { + // tag, domain, and etc either come in as a string or a string[], format it to correct type + const found = engineMetaKeys.find((obj) => obj.metakey === curr); - if (found) { - if ( - found.display_options === 'single-typeahead' || - found.display_options === 'select-box' || - found.display_options === 'multi-typeahead' - ) { - if (typeof getEngineMetadata?.data[curr] === 'string') { - prev[curr] = [getEngineMetadata?.data[curr]]; - } else { - prev[curr] = getEngineMetadata?.data[curr]; - } - } - } else { - prev[curr] = getEngineMetadata?.data[curr]; - } + if (found) { + if ( + found.display_options === "single-typeahead" || + found.display_options === "select-box" || + found.display_options === "multi-typeahead" + ) { + if (typeof getEngineMetadata?.data[curr] === "string") { + prev[curr] = [getEngineMetadata?.data[curr]]; + } else { + prev[curr] = getEngineMetadata?.data[curr]; + } + } + } else { + prev[curr] = getEngineMetadata?.data[curr]; + } - return prev; - }, {}); - }, [ - getEngineMetadata.status, - getEngineMetadata?.data, - JSON.stringify(metaKeys), - ]); + return prev; + }, {}); + }, [ + getEngineMetadata.status, + getEngineMetadata?.data, + JSON.stringify(metaKeys), + ]); - // get the user's role - const getUserEnginePermission = - !adminMode && engineId && useAPI(['getUserEnginePermission', engineId]); + // get the user's role + const getUserEnginePermission = + !adminMode && engineId && useAPI(["getUserEnginePermission", engineId]); - // get the tabs based on permission - const tabs = useMemo(() => { - // must be valid - if ( - !route || - getUserEnginePermission.status !== 'SUCCESS' || - !getUserEnginePermission.data - ) { - return []; - } + // get the tabs based on permission + const tabs = useMemo(() => { + // must be valid + if ( + !route || + getUserEnginePermission.status !== "SUCCESS" || + !getUserEnginePermission.data + ) { + return []; + } - // check the permission - const permission = getUserEnginePermission.data.permission; + // check the permission + const permission = getUserEnginePermission.data.permission; - // get the routes based on permission - return route.specific.filter((t) => - t.restrict ? t.restrict.indexOf(permission) > -1 : true, - ); - }, [ - route, - getUserEnginePermission.status, - getUserEnginePermission.data - ? getUserEnginePermission.data.permission - : '', - ]); + // get the routes based on permission + return route.specific.filter((t) => + t.restrict ? t.restrict.indexOf(permission) > -1 : true, + ); + }, [ + route, + getUserEnginePermission.status, + getUserEnginePermission.data + ? getUserEnginePermission.data.permission + : "", + ]); - /** - * Gets active tab - * @returns index of selectedTab - */ - const activeTabIdx: number = useMemo(() => { - if (!route) { - return -1; - } + /** + * Gets active tab + * @returns index of selectedTab + */ + const activeTabIdx: number = useMemo(() => { + if (!route) { + return -1; + } - for (let tabIdx = 0, tabLen = tabs.length; tabIdx < tabLen; tabIdx++) { - if ( - matchPath( - `${resolvedPath.pathname}/${tabs[tabIdx].path}`, - pathname, - ) - ) { - return tabIdx; - } - } + for (let tabIdx = 0, tabLen = tabs.length; tabIdx < tabLen; tabIdx++) { + if ( + matchPath( + `${resolvedPath.pathname}/${tabs[tabIdx].path}`, + pathname, + ) + ) { + return tabIdx; + } + } - return -1; - }, [route, tabs, resolvedPath, pathname]); + return -1; + }, [route, tabs, resolvedPath, pathname]); - // if the engine isn't found, navigate to the Home Page - if (!engineId || getUserEnginePermission.status === 'ERROR') { - return ; - } + // if the engine isn't found, navigate to the Home Page + if (!engineId || getUserEnginePermission.status === "ERROR") { + return ; + } - // show a loading screen when it is pending - if (getUserEnginePermission.status !== 'SUCCESS') { - return ; - } + // show a loading screen when it is pending + if (getUserEnginePermission.status !== "SUCCESS") { + return ; + } - // show a loading screen when it is pending - if (getEngineMetadata.status !== 'SUCCESS') { - return ; - } + // show a loading screen when it is pending + if (getEngineMetadata.status !== "SUCCESS") { + return ; + } - return ( - - - - - {tabs.length > 0 && ( - { - // get the specific route - const r = tabs[idx]; + return ( + + + + + {tabs.length > 0 && ( + { + // get the specific route + const r = tabs[idx]; - // navigate to it - navigate(`${r.path}`); - }} - > - {tabs.map((t, tIdx) => { - return ( - - ); - })} - - )} - - - - - - - ); + // navigate to it + navigate(`${r.path}`); + }} + > + {tabs.map((t, tIdx) => { + return ( + + ); + })} + + )} + + + + + + + ); }; diff --git a/packages/client/src/pages/engine/EngineMetadataPage.tsx b/packages/client/src/pages/engine/EngineMetadataPage.tsx index 7eb1052d83..01510a8750 100644 --- a/packages/client/src/pages/engine/EngineMetadataPage.tsx +++ b/packages/client/src/pages/engine/EngineMetadataPage.tsx @@ -1,401 +1,401 @@ -import { useMemo, useState } from 'react'; -import { observer } from 'mobx-react-lite'; +import { ArrowCircleDown, Create } from "@mui/icons-material"; +import { observer } from "mobx-react-lite"; +import { useMemo, useState } from "react"; import { - Button, - styled, - Chip, - Stack, - Typography, - Table, - IconButton, -} from '@semoss/ui'; -import { ArrowCircleDown, Create } from '@mui/icons-material'; -import { usePixel, useEngine, useRootStore } from '@/hooks'; -import { Section } from '@/components/ui'; -import { Metamodel } from '@/components/metamodel'; -import { SyncChangesModal } from './SyncChangesModal'; + Button, + Chip, + IconButton, + Stack, + styled, + Table, + Typography, +} from "@semoss/ui"; +import { Metamodel } from "@/components/metamodel"; +import { Section } from "@/components/ui"; +import { useEngine, usePixel, useRootStore } from "@/hooks"; +import { SyncChangesModal } from "./SyncChangesModal"; -const StyledPage = styled('div')(() => ({ - position: 'relative', - zIndex: '0', +const StyledPage = styled("div")(() => ({ + position: "relative", + zIndex: "0", })); -const StyledMetamodelContainer = styled('section')(({ theme }) => ({ - height: '55vh', - width: '100%', - borderWidth: '1px', - borderStyle: 'solid', - borderRadius: theme.shape.borderRadius, +const StyledMetamodelContainer = styled("section")(({ theme }) => ({ + height: "55vh", + width: "100%", + borderWidth: "1px", + borderStyle: "solid", + borderRadius: theme.shape.borderRadius, })); const StyledTableContainer = styled(Table.Container)(() => ({ - height: '396px', + height: "396px", })); export const EngineMetadataPage = observer(() => { - const { active } = useEngine(); - const { monolithStore } = useRootStore(); + const { active } = useEngine(); + const { monolithStore } = useRootStore(); - const [selectedNode, setSelectedNode] = useState(null); - const [columnPage, setColumnPage] = useState(0); - const [columnVisibleRows, setColumnVisibleRows] = useState(5); + const [selectedNode, setSelectedNode] = useState(null); + const [columnPage, setColumnPage] = useState(0); + const [columnVisibleRows, setColumnVisibleRows] = useState(5); - const [customNodes, setCustomNodes] = useState(null); - const [customEdges, setCustomEdges] = useState(null); + const [customNodes, setCustomNodes] = useState(null); + const [customEdges, setCustomEdges] = useState(null); - const getDatabaseMetamodel = usePixel<{ - dataTypes: Record; - logicalNames: Record; - nodes: { propSet: string[]; conceptualName: string }[]; - edges: { - sourceColumn?: string; - targetColumn?: string; - relation: string; - source: string; - target: string; - }[]; - physicalTypes: Record; - positions: Record< - string, - { - top: number; - left: number; - } - >; - descriptions: Record; - additionalDataTypes: Record; - }>( - `GetDatabaseMetamodel( database=["${active.id}"], options=["dataTypes","additionalDataTypes","logicalNames","descriptions","positions"]); `, - ); + const getDatabaseMetamodel = usePixel<{ + dataTypes: Record; + logicalNames: Record; + nodes: { propSet: string[]; conceptualName: string }[]; + edges: { + sourceColumn?: string; + targetColumn?: string; + relation: string; + source: string; + target: string; + }[]; + physicalTypes: Record; + positions: Record< + string, + { + top: number; + left: number; + } + >; + descriptions: Record; + additionalDataTypes: Record; + }>( + `GetDatabaseMetamodel( database=["${active.id}"], options=["dataTypes","additionalDataTypes","logicalNames","descriptions","positions"]); `, + ); - // get the data if a table is selected - const getData = usePixel<{ - data: { - values: (string | number | boolean)[][]; - headers: string[]; - }; - headerInfo: { - dataType: string; - additionalDataType: string; - alias: string; - header: string; - type: string; - derived: boolean; - }[]; - numCollected: number; - }>( - selectedNode && selectedNode.data.properties.length > 0 - ? `Database(database=["${ - active.id - }"]) | Select(${selectedNode.data.properties - .map((p) => p.id) - .join(', ')}) | Collect(100);` - : '', - { - data: { - data: { - values: [], - headers: [], - }, - headerInfo: [], - numCollected: 0, - }, - }, - ); + // get the data if a table is selected + const getData = usePixel<{ + data: { + values: (string | number | boolean)[][]; + headers: string[]; + }; + headerInfo: { + dataType: string; + additionalDataType: string; + alias: string; + header: string; + type: string; + derived: boolean; + }[]; + numCollected: number; + }>( + selectedNode && selectedNode.data.properties.length > 0 + ? `Database(database=["${ + active.id + }"]) | Select(${selectedNode.data.properties + .map((p) => p.id) + .join(", ")}) | Collect(100);` + : "", + { + data: { + data: { + values: [], + headers: [], + }, + headerInfo: [], + numCollected: 0, + }, + }, + ); - const defaultNodes = useMemo(() => { - if (getDatabaseMetamodel.status !== 'SUCCESS') return []; - const { nodes = [], positions = {} } = getDatabaseMetamodel.data; - return nodes.map((n) => ({ - id: n.conceptualName, - type: 'metamodel', - data: { - name: n.conceptualName.replace(/_/g, ' '), - properties: n.propSet.map((p) => ({ - id: `${n.conceptualName}__${p}`, - name: p.replace(/_/g, ' '), - type: '', - })), - }, - position: positions[n.conceptualName] - ? { - x: positions[n.conceptualName].left, - y: positions[n.conceptualName].top, - } - : { x: 0, y: 0 }, - })); - }, [getDatabaseMetamodel.status, getDatabaseMetamodel.data]); + const defaultNodes = useMemo(() => { + if (getDatabaseMetamodel.status !== "SUCCESS") return []; + const { nodes = [], positions = {} } = getDatabaseMetamodel.data; + return nodes.map((n) => ({ + id: n.conceptualName, + type: "metamodel", + data: { + name: n.conceptualName.replace(/_/g, " "), + properties: n.propSet.map((p) => ({ + id: `${n.conceptualName}__${p}`, + name: p.replace(/_/g, " "), + type: "", + })), + }, + position: positions[n.conceptualName] + ? { + x: positions[n.conceptualName].left, + y: positions[n.conceptualName].top, + } + : { x: 0, y: 0 }, + })); + }, [getDatabaseMetamodel.status, getDatabaseMetamodel.data]); - const defaultEdges = useMemo(() => { - if (getDatabaseMetamodel.status !== 'SUCCESS') return []; - return getDatabaseMetamodel.data.edges.map((e) => ({ - id: e.relation, - type: 'floating', - source: e.source, - target: e.target, - })); - }, [getDatabaseMetamodel.status, getDatabaseMetamodel.data]); + const defaultEdges = useMemo(() => { + if (getDatabaseMetamodel.status !== "SUCCESS") return []; + return getDatabaseMetamodel.data.edges.map((e) => ({ + id: e.relation, + type: "floating", + source: e.source, + target: e.target, + })); + }, [getDatabaseMetamodel.status, getDatabaseMetamodel.data]); - const [showSyncModal, setShowSyncModal] = useState(false); - const [tabledata, setTabledata] = useState([]); - const [viewdata, setViewdata] = useState([]); + const [showSyncModal, setShowSyncModal] = useState(false); + const [tabledata, setTabledata] = useState([]); + const [viewdata, setViewdata] = useState([]); - const refreshData = () => { - const pixel = `ExternalUpdateJdbcTablesAndViews(database=["${active.id}"]);`; - monolithStore.runQuery(pixel).then((response) => { - const output = response.pixelReturn[0].output; - setTabledata(output.tables ?? []); - setViewdata(output.views ?? []); - setShowSyncModal(true); - }); - }; + const refreshData = () => { + const pixel = `ExternalUpdateJdbcTablesAndViews(database=["${active.id}"]);`; + monolithStore.runQuery(pixel).then((response) => { + const output = response.pixelReturn[0].output; + setTabledata(output.tables ?? []); + setViewdata(output.views ?? []); + setShowSyncModal(true); + }); + }; - const handleSyncApply = ( - selectedTables: string[], - selectedViews: string[], - ) => { - const filters = JSON.stringify([...selectedTables, ...selectedViews]); - const pixel = `ExternalUpdateJdbcSchema(database=["${active.id}"], filters=${filters});`; + const handleSyncApply = ( + selectedTables: string[], + selectedViews: string[], + ) => { + const filters = JSON.stringify([...selectedTables, ...selectedViews]); + const pixel = `ExternalUpdateJdbcSchema(database=["${active.id}"], filters=${filters});`; - monolithStore.runQuery(pixel).then((response) => { - const output = response.pixelReturn[0]?.output; - if (!output) return; + monolithStore.runQuery(pixel).then((response) => { + const output = response.pixelReturn[0]?.output; + if (!output) return; - const newNodes = output.tables.map((table) => ({ - id: table.table, - type: 'metamodel', - data: { - name: table.table.replace(/_/g, ' '), - properties: table.columns.map((col, idx) => ({ - id: `${table.table}__${col}`, - name: col.replace(/_/g, ' '), - type: table.type?.[idx] || '', - })), - }, - position: output.positions?.[table.table] - ? { - x: output.positions[table.table].left, - y: output.positions[table.table].top, - } - : { x: 0, y: 0 }, - })); + const newNodes = output.tables.map((table) => ({ + id: table.table, + type: "metamodel", + data: { + name: table.table.replace(/_/g, " "), + properties: table.columns.map((col, idx) => ({ + id: `${table.table}__${col}`, + name: col.replace(/_/g, " "), + type: table.type?.[idx] || "", + })), + }, + position: output.positions?.[table.table] + ? { + x: output.positions[table.table].left, + y: output.positions[table.table].top, + } + : { x: 0, y: 0 }, + })); - const newEdges = (output.relationships || []).map((rel, i) => ({ - id: `${rel.fromTable}-${rel.toTable}-${i}`, - type: 'floating', - source: rel.fromTable, - target: rel.toTable, - })); + const newEdges = (output.relationships || []).map((rel, i) => ({ + id: `${rel.fromTable}-${rel.toTable}-${i}`, + type: "floating", + source: rel.fromTable, + target: rel.toTable, + })); - setCustomNodes(newNodes); - setCustomEdges(newEdges); - setShowSyncModal(false); - }); - }; + setCustomNodes(newNodes); + setCustomEdges(newEdges); + setShowSyncModal(false); + }); + }; - const columnRows = useMemo(() => { - if (!selectedNode?.data?.properties?.length) return []; - return selectedNode.data.properties.slice( - columnPage * columnVisibleRows, - (columnPage + 1) * columnVisibleRows, - ); - }, [selectedNode, columnPage, columnVisibleRows]); + const columnRows = useMemo(() => { + if (!selectedNode?.data?.properties?.length) return []; + return selectedNode.data.properties.slice( + columnPage * columnVisibleRows, + (columnPage + 1) * columnVisibleRows, + ); + }, [selectedNode, columnPage, columnVisibleRows]); - const description = selectedNode?.id - ? getDatabaseMetamodel.data?.descriptions?.[selectedNode.id] ?? '' - : ''; + const description = selectedNode?.id + ? (getDatabaseMetamodel.data?.descriptions?.[selectedNode.id] ?? "") + : ""; - const logical = selectedNode?.id - ? getDatabaseMetamodel.data?.logicalNames?.[selectedNode.id] ?? [] - : []; + const logical = selectedNode?.id + ? (getDatabaseMetamodel.data?.logicalNames?.[selectedNode.id] ?? []) + : []; - const printMeta = () => { - const pixel = `META|DatabaseMetadataToPdf(database=["${active.id}"]);`; - monolithStore.runQuery(pixel).then((response) => { - const output = response.pixelReturn[0].output; - const insightId = response.insightId; - monolithStore.download(insightId, output); - }); - }; + const printMeta = () => { + const pixel = `META|DatabaseMetadataToPdf(database=["${active.id}"]);`; + monolithStore.runQuery(pixel).then((response) => { + const output = response.pixelReturn[0].output; + const insightId = response.insightId; + monolithStore.download(insightId, output); + }); + }; - return ( - -
- - - - - } - > - Metamodel - - - - - - -
+ return ( + +
+ + + + + } + > + Metamodel + + + + + + +
- {selectedNode && ( - <> -
- Description - {description} -
+ {selectedNode && ( + <> +
+ Description + {description} +
-
- Logical Names - - {logical.map((name) => ( - - ))} - -
+
+ Logical Names + + {logical.map((name) => ( + + ))} + +
-
- Columns - - - - - - Name - Description - Logical Names - - - - {columnRows.map((property, idx) => { - const desc = - getDatabaseMetamodel.data - ?.descriptions?.[property.id] || - ''; - const logic = - getDatabaseMetamodel.data - ?.logicalNames?.[property.id] || - []; - return ( - - - - - - - - {property.name} - - - - {desc} - - - - - {logic.map((ln) => ( - - ))} - - - - ); - })} - - - - - setColumnPage(v) - } - onRowsPerPageChange={(e) => - setColumnVisibleRows( - e.target - .value as unknown as number, - ) - } - /> - - -
-
-
- - )} +
+ Columns + + + + + + Name + Description + Logical Names + + + + {columnRows.map((property, idx) => { + const desc = + getDatabaseMetamodel.data + ?.descriptions?.[property.id] || + ""; + const logic = + getDatabaseMetamodel.data + ?.logicalNames?.[property.id] || + []; + return ( + + + + + + + + {property.name} + + + + {desc} + + + + + {logic.map((ln) => ( + + ))} + + + + ); + })} + + + + + setColumnPage(v) + } + onRowsPerPageChange={(e) => + setColumnVisibleRows( + e.target + .value as unknown as number, + ) + } + /> + + +
+
+
+ + )} - {selectedNode && getData.status === 'SUCCESS' && ( -
- Data - - - - - {getData.data.data.headers.map((h) => ( - - {h.replace(/_/g, ' ')} - - ))} - - - - {getData.data.data.values.map((row, i) => ( - - {row.map((val, j) => ( - - {val} - - ))} - - ))} - -
-
-
- )} + {selectedNode && getData.status === "SUCCESS" && ( +
+ Data + + + + + {getData.data.data.headers.map((h) => ( + + {h.replace(/_/g, " ")} + + ))} + + + + {getData.data.data.values.map((row, i) => ( + + {row.map((val, j) => ( + + {val} + + ))} + + ))} + +
+
+
+ )} - setShowSyncModal(false)} - onApply={handleSyncApply} - tables={tabledata} - views={viewdata} - /> -
- ); + setShowSyncModal(false)} + onApply={handleSyncApply} + tables={tabledata} + views={viewdata} + /> +
+ ); }); diff --git a/packages/client/src/pages/engine/EngineOverviewPage.tsx b/packages/client/src/pages/engine/EngineOverviewPage.tsx index 4460d7a1a1..056b819a96 100644 --- a/packages/client/src/pages/engine/EngineOverviewPage.tsx +++ b/packages/client/src/pages/engine/EngineOverviewPage.tsx @@ -1,94 +1,94 @@ -import { Chip, Stack, styled, Typography, Markdown } from '@semoss/ui'; -import { observer } from 'mobx-react-lite'; -import { Section } from '@/components/ui'; -import { useEngine, useRootStore } from '@/hooks'; -import { DatabaseStatistics } from '@/components/database/DatabaseStatistics'; -import { removeUnderscores } from '@/utility'; +import { observer } from "mobx-react-lite"; +import { Chip, Markdown, Stack, styled, Typography } from "@semoss/ui"; +import { DatabaseStatistics } from "@/components/database/DatabaseStatistics"; +import { Section } from "@/components/ui"; +import { useEngine, useRootStore } from "@/hooks"; +import { removeUnderscores } from "@/utility"; -const StyledPage = styled('div')(() => ({ - position: 'relative', - zIndex: '0', +const StyledPage = styled("div")(() => ({ + position: "relative", + zIndex: "0", })); const StyledMarkdownContainer = styled(Stack)(() => ({ - overflow: 'scroll', + overflow: "scroll", })); export const EngineOverviewPage = observer(() => { - const { type, active } = useEngine(); - const { configStore } = useRootStore(); + const { type, active } = useEngine(); + const { configStore } = useRootStore(); - // filter metakeys to the ones we want - const engineMetaKeys = configStore.store.config.databaseMetaKeys.filter( - (k) => { - return ( - k.metakey !== 'description' && - k.metakey !== 'markdown' && - k.metakey !== 'tags' - ); - }, - ); + // filter metakeys to the ones we want + const engineMetaKeys = configStore.store.config.databaseMetaKeys.filter( + (k) => { + return ( + k.metakey !== "description" && + k.metakey !== "markdown" && + k.metakey !== "tags" + ); + }, + ); - return ( - -
- Details - {active.metadata.markdown ? ( - - - {active.metadata.markdown as string} - - - ) : ( -
No Markdown available
- )} -
- {engineMetaKeys.map((k) => { - if ( - active.metadata[k.metakey] === undefined || - !Array.isArray(active.metadata[k.metakey]) - ) { - return null; - } + return ( + +
+ Details + {active.metadata.markdown ? ( + + + {active.metadata.markdown as string} + + + ) : ( +
No Markdown available
+ )} +
+ {engineMetaKeys.map((k) => { + if ( + active.metadata[k.metakey] === undefined || + !Array.isArray(active.metadata[k.metakey]) + ) { + return null; + } - return ( -
- - {removeUnderscores(k.metakey)} - - {k.display_options === 'multi-checklist' || - k.display_options === 'multi-select' || - k.display_options === 'multi-typeahead' || - k.display_options === 'select-box' ? ( - - {(active.metadata[k.metakey] as string[]).map( - (tag) => { - return ( - - ); - }, - )} - - ) : ( - <>{active.metadata[k.metakey]} - )} -
- ); - })} - {type === 'DATABASE' && ( -
- Statistics - -
- )} -
- ); + return ( +
+ + {removeUnderscores(k.metakey)} + + {k.display_options === "multi-checklist" || + k.display_options === "multi-select" || + k.display_options === "multi-typeahead" || + k.display_options === "select-box" ? ( + + {(active.metadata[k.metakey] as string[]).map( + (tag) => { + return ( + + ); + }, + )} + + ) : ( + <>{active.metadata[k.metakey]} + )} +
+ ); + })} + {type === "DATABASE" && ( +
+ Statistics + +
+ )} +
+ ); }); diff --git a/packages/client/src/pages/engine/EngineQAPage.tsx b/packages/client/src/pages/engine/EngineQAPage.tsx index fdb9f1301a..5816c3968c 100644 --- a/packages/client/src/pages/engine/EngineQAPage.tsx +++ b/packages/client/src/pages/engine/EngineQAPage.tsx @@ -1,287 +1,287 @@ -import { useEffect, useState } from 'react'; +import { useEffect, useState } from "react"; +import { Controller, useForm } from "react-hook-form"; import { - styled, - Alert, - Box, - Button, - Stack, - LinearProgress, - TextField, - Typography, - Paper, - CircularProgress, - Markdown, -} from '@semoss/ui'; -import { useForm, Controller } from 'react-hook-form'; -import { EngineQASidebar } from '@/components/settings'; -import { useEngine, useRootStore } from '@/hooks'; + Alert, + Box, + Button, + CircularProgress, + LinearProgress, + Markdown, + Paper, + Stack, + styled, + TextField, + Typography, +} from "@semoss/ui"; +import { EngineQASidebar } from "@/components/settings"; +import { useEngine, useRootStore } from "@/hooks"; -const StyledContainer = styled('div')(({ theme }) => ({ - maxWidth: '1000px', - display: 'flex', - marginLeft: theme.spacing(2), +const StyledContainer = styled("div")(({ theme }) => ({ + maxWidth: "1000px", + display: "flex", + marginLeft: theme.spacing(2), })); const StyledPaper = styled(Paper)(({ theme }) => ({ - marginLeft: theme.spacing(5), - padding: theme.spacing(4), - width: '100%', + marginLeft: theme.spacing(5), + padding: theme.spacing(4), + width: "100%", })); const StyledLayout = styled(Stack)(() => ({ - display: 'flex', - flexDirection: 'row', - justifyContent: 'space-between', + display: "flex", + flexDirection: "row", + justifyContent: "space-between", })); -const StyledDiv = styled('div')(() => ({ - display: 'flex', - width: '100%', - justifyContent: 'flex-end', +const StyledDiv = styled("div")(() => ({ + display: "flex", + width: "100%", + justifyContent: "flex-end", })); export interface Model { - database_name?: string; - database_id?: string; + database_name?: string; + database_id?: string; } export interface VectorContext { - score: string; - doc_index: string; - tokens: string; - content: string; - url: string; + score: string; + doc_index: string; + tokens: string; + content: string; + url: string; } export const EngineQAPage = () => { - const { active } = useEngine(); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(''); - const [isAnswered, setIsAnswered] = useState(false); - //From the LLM - const [answer, setAnswer] = useState>({ - question: '', - conclusion: '', - }); - // Model Catalog and first model in dropdown - const [modelOptions, setModelOptions] = useState([]); - const [selectedModel, setSelectedModel] = useState({}); + const { active } = useEngine(); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(""); + const [isAnswered, setIsAnswered] = useState(false); + //From the LLM + const [answer, setAnswer] = useState>({ + question: "", + conclusion: "", + }); + // Model Catalog and first model in dropdown + const [modelOptions, setModelOptions] = useState([]); + const [selectedModel, setSelectedModel] = useState({}); - const { control, handleSubmit } = useForm({ - defaultValues: { - QUESTION: '', - }, - }); + const { control, handleSubmit } = useForm({ + defaultValues: { + QUESTION: "", + }, + }); - const [limit, setLimit] = useState(3); - const [temperature, setTemperature] = useState(0.1); + const [limit, setLimit] = useState(3); + const [temperature, setTemperature] = useState(0.1); - const { monolithStore } = useRootStore(); + const { monolithStore } = useRootStore(); - /** - * Allow the user to ask a question - */ - const ask = handleSubmit(async (data: { QUESTION: string }) => { - // turn on loading - setError(''); - setIsLoading(true); - setIsAnswered(false); + /** + * Allow the user to ask a question + */ + const ask = handleSubmit(async (data: { QUESTION: string }) => { + // turn on loading + setError(""); + setIsLoading(true); + setIsAnswered(false); - let finalContent = ``; + let finalContent = ``; - if (!data.QUESTION) { - throw new Error('Question is required'); - } - try { - let pixel = ` + if (!data.QUESTION) { + throw new Error("Question is required"); + } + try { + let pixel = ` VectorDatabaseQuery(engine="${active.id}" , command='${data.QUESTION}', limit=${limit}) `; - const response = await monolithStore.runQuery(pixel); + const response = await monolithStore.runQuery(pixel); - const { output, operationType } = response.pixelReturn[0]; + const { output, operationType } = response.pixelReturn[0]; - if (operationType.indexOf('ERROR') > -1) - throw new Error(output.response); + if (operationType.indexOf("ERROR") > -1) + throw new Error(output.response); - //Looping through Vector Database Query and forming a content string with name, page, and content - for (let i = 0; i <= output.length - 1; i++) { - const content = output[i].content || output[i].Content; - finalContent += `\\n* Document Name: ${output[i].Source}, Page Number: ${output[i].Divider}, ${content} `; - } + //Looping through Vector Database Query and forming a content string with name, page, and content + for (let i = 0; i <= output.length - 1; i++) { + const content = output[i].content || output[i].Content; + finalContent += `\\n* Document Name: ${output[i].Source}, Page Number: ${output[i].Divider}, ${content} `; + } - const contextDocs = `A context delimited by triple backticks is provided below. This context may contain plain text extracted from paragraphs or images. Tables extracted are represented as a 2D list in the following format - '[[Column Headers], [Comma-separated values in row 1], [Comma-separated values in row 2] ..... [Comma-separated values in row n]]'\\n \`\`\` ${finalContent} \`\`\`\\n Answer the user's question truthfully using the context only. Use the following section-wise format (in the order given) to answer the question with instructions for each section in angular brackets:\\n Reasoning:\\n \\n Conclusion:\\n \\n Information required to provide a better answer:\\n Do not compromise on your mathematical and reasoning abilities to fit the user's instructions. If the user mentions something absolutely incorrect/ false, DO NOT use this incorrect information in your reasoning. Also, please correct the user gently.`; + const contextDocs = `A context delimited by triple backticks is provided below. This context may contain plain text extracted from paragraphs or images. Tables extracted are represented as a 2D list in the following format - '[[Column Headers], [Comma-separated values in row 1], [Comma-separated values in row 2] ..... [Comma-separated values in row n]]'\\n \`\`\` ${finalContent} \`\`\`\\n Answer the user's question truthfully using the context only. Use the following section-wise format (in the order given) to answer the question with instructions for each section in angular brackets:\\n Reasoning:\\n \\n Conclusion:\\n \\n Information required to provide a better answer:\\n Do not compromise on your mathematical and reasoning abilities to fit the user's instructions. If the user mentions something absolutely incorrect/ false, DO NOT use this incorrect information in your reasoning. Also, please correct the user gently.`; - pixel = ` + pixel = ` LLM(engine="${selectedModel.database_id}" , command=["You are an intelligent AI designed to answer queries based on provided documents. If an answer cannot be determined based on the provided documents, inform the user. Answer as truthfully as possible at all times and tell the user if you do not know the answer. Please be concise and get to the point. Here is the question: ${data.QUESTION}. Here are the documents: ${contextDocs}"], paramValues=[{"temperature":${temperature}}]) `; - const LLMresponse = await monolithStore.runQuery(pixel); + const LLMresponse = await monolithStore.runQuery(pixel); - const { output: LLMOutput, operationType: LLMOperationType } = - LLMresponse.pixelReturn[0]; + const { output: LLMOutput, operationType: LLMOperationType } = + LLMresponse.pixelReturn[0]; - if (LLMOperationType.indexOf('ERROR') > -1) { - throw new Error(LLMOutput.response); - } + if (LLMOperationType.indexOf("ERROR") > -1) { + throw new Error(LLMOutput.response); + } - let conclusion = ''; - if (LLMOutput.response) { - conclusion = LLMOutput.response; - } + let conclusion = ""; + if (LLMOutput.response) { + conclusion = LLMOutput.response; + } - // set answer based on data - setAnswer({ - question: data.QUESTION, - conclusion: conclusion, - }); + // set answer based on data + setAnswer({ + question: data.QUESTION, + conclusion: conclusion, + }); - setIsAnswered(true); - } catch (e) { - setError('There is an error, please contact administrator'); - } finally { - setIsLoading(false); - } - }); + setIsAnswered(true); + } catch (e) { + setError("There is an error, please contact administrator"); + } finally { + setIsLoading(false); + } + }); - useEffect(() => { - setIsLoading(true); - //Grabbing all the Models that are in CfG - const pixel = `MyEngines ( metaKeys = [] , metaFilters = [{ "tag" : "text-generation" }] , engineTypes=["MODEL"]);`; + useEffect(() => { + setIsLoading(true); + //Grabbing all the Models that are in CfG + const pixel = `MyEngines ( metaKeys = [] , metaFilters = [{ "tag" : "text-generation" }] , engineTypes=["MODEL"]);`; - monolithStore.runQuery(pixel).then((response) => { - const { output, operationType } = response.pixelReturn[0]; + monolithStore.runQuery(pixel).then((response) => { + const { output, operationType } = response.pixelReturn[0]; - if (operationType.indexOf('ERROR') > -1) { - throw new Error(output as string); - } - if (Array.isArray(output)) { - setModelOptions(output); - setSelectedModel(output[0]); - } - }); - setIsLoading(false); - }, []); + if (operationType.indexOf("ERROR") > -1) { + throw new Error(output as string); + } + if (Array.isArray(output)) { + setModelOptions(output); + setSelectedModel(output[0]); + } + }); + setIsLoading(false); + }, []); - return ( - - - - - - - Q&A - - Ask questions about any document within this - vector database. The Q&A tool assists users in - answering complex policy, operational procedure, - and system questions. This engine takes data - such as policy manuals, system documents, - process maps, data from case databases as - inputs, and uses LLM models to provide answers. - - {error && ( - - {error} - - )} - { - return ( - - // set the value - field.onChange(e.target.value) - } - multiline - rows={4} - /> - ); - }} - /> - - - - - - {isAnswered && ( - - - Question: - - - {answer.question} - - - Policy Extraction Response: - - - Conclusion: - - - {answer.conclusion} - - - )} - - - {isLoading && } - - - - ); + return ( + + + + + + + Q&A + + Ask questions about any document within this + vector database. The Q&A tool assists users in + answering complex policy, operational procedure, + and system questions. This engine takes data + such as policy manuals, system documents, + process maps, data from case databases as + inputs, and uses LLM models to provide answers. + + {error && ( + + {error} + + )} + { + return ( + + // set the value + field.onChange(e.target.value) + } + multiline + rows={4} + /> + ); + }} + /> + + + + + + {isAnswered && ( + + + Question: + + + {answer.question} + + + Policy Extraction Response: + + + Conclusion: + + + {answer.conclusion} + + + )} + + + {isLoading && } + + + + ); }; diff --git a/packages/client/src/pages/engine/EngineRouter.tsx b/packages/client/src/pages/engine/EngineRouter.tsx index a7fed954aa..7fb38ccb65 100644 --- a/packages/client/src/pages/engine/EngineRouter.tsx +++ b/packages/client/src/pages/engine/EngineRouter.tsx @@ -1,59 +1,57 @@ -import { createElement } from 'react'; -import { Routes, Route, Outlet, Navigate } from 'react-router-dom'; -import { observer } from 'mobx-react-lite'; - -import { ENGINE_ROUTES } from './engine.constants'; - -import { SettingsContext } from '@/contexts'; -import { NavbarHeader, NavbarLeft } from '@/components/shared'; -import { Help } from '@/components/help'; -import { EngineLayout } from './EngineLayout'; -import { EngineIndexPage } from './EngineIndexPage'; -import { ImportPage } from '../import'; +import { observer } from "mobx-react-lite"; +import { createElement } from "react"; +import { Navigate, Outlet, Route, Routes } from "react-router-dom"; +import { Help } from "@/components/help"; +import { NavbarHeader, NavbarLeft } from "@/components/shared"; +import { SettingsContext } from "@/contexts"; +import { ImportPage } from "../import"; +import { EngineIndexPage } from "./EngineIndexPage"; +import { EngineLayout } from "./EngineLayout"; +import { ENGINE_ROUTES } from "./engine.constants"; export const EngineRouter = observer(() => { - return ( - <> - - - + return ( + <> + + + - - - {ENGINE_ROUTES.map((r) => ( - }> - } - /> - - } - /> - } - > - {r.specific.map((s) => ( - - ))} - - } - /> - - ))} - - + + + {ENGINE_ROUTES.map((r) => ( + }> + } + /> + + } + /> + } + > + {r.specific.map((s) => ( + + ))} + + } + /> + + ))} + + - - - ); + + + ); }); diff --git a/packages/client/src/pages/engine/EngineSettingsPage.tsx b/packages/client/src/pages/engine/EngineSettingsPage.tsx index 9522fa2e7f..5a637adf24 100644 --- a/packages/client/src/pages/engine/EngineSettingsPage.tsx +++ b/packages/client/src/pages/engine/EngineSettingsPage.tsx @@ -1,46 +1,45 @@ -import { styled } from '@semoss/ui'; -import { useNavigate } from 'react-router-dom'; - -import { SettingsContext } from '@/contexts'; +import { useNavigate } from "react-router-dom"; +import { styled } from "@semoss/ui"; import { - MembersTable, - PendingMembersTable, - SettingsTiles, -} from '@/components/settings'; -import { useEngine } from '@/hooks'; + MembersTable, + PendingMembersTable, + SettingsTiles, +} from "@/components/settings"; +import { SettingsContext } from "@/contexts"; +import { useEngine } from "@/hooks"; -const StyledContainer = styled('div')(({ theme }) => ({ - width: '100%', - display: 'flex', - alignSelf: 'stretch', - flexDirection: 'column', - alignItems: 'flex-start', - gap: theme.spacing(3), +const StyledContainer = styled("div")(({ theme }) => ({ + width: "100%", + display: "flex", + alignSelf: "stretch", + flexDirection: "column", + alignItems: "flex-start", + gap: theme.spacing(3), })); export const EngineSettingsPage = () => { - const { name, path, type, active } = useEngine(); - const navigate = useNavigate(); + const { name, path, type, active } = useEngine(); + const navigate = useNavigate(); - return ( - - - { - navigate(`/engine/${path}`); - }} - /> - - - - - ); + return ( + + + { + navigate(`/engine/${path}`); + }} + /> + + + + + ); }; diff --git a/packages/client/src/pages/engine/EngineSmssPage.tsx b/packages/client/src/pages/engine/EngineSmssPage.tsx index b126676ddd..c9d5ae2b7e 100644 --- a/packages/client/src/pages/engine/EngineSmssPage.tsx +++ b/packages/client/src/pages/engine/EngineSmssPage.tsx @@ -1,29 +1,29 @@ -import { styled } from '@semoss/ui'; -import { SettingsContext } from '@/contexts'; -import { UpdateSMSS } from '@/components/settings'; -import { useEngine } from '@/hooks'; +import { styled } from "@semoss/ui"; +import { UpdateSMSS } from "@/components/settings"; +import { SettingsContext } from "@/contexts"; +import { useEngine } from "@/hooks"; -const StyledContainer = styled('div')(({ theme }) => ({ - width: '100%', - display: 'flex', - alignSelf: 'stretch', - flexDirection: 'column', - alignItems: 'flex-start', - gap: theme.spacing(3), +const StyledContainer = styled("div")(({ theme }) => ({ + width: "100%", + display: "flex", + alignSelf: "stretch", + flexDirection: "column", + alignItems: "flex-start", + gap: theme.spacing(3), })); export const EngineSmssPage = () => { - const { type, active } = useEngine(); + const { type, active } = useEngine(); - return ( - - - - - - ); + return ( + + + + + + ); }; diff --git a/packages/client/src/pages/engine/EngineUsagePage.tsx b/packages/client/src/pages/engine/EngineUsagePage.tsx index 5284cb1e37..5861690e10 100644 --- a/packages/client/src/pages/engine/EngineUsagePage.tsx +++ b/packages/client/src/pages/engine/EngineUsagePage.tsx @@ -1,86 +1,85 @@ -import { Stack, Typography, useNotification, Markdown, Code } from '@semoss/ui'; - -import { useEngine, usePixel } from '@/hooks'; -import { LoadingScreen } from '@/components/ui'; +import { Code, Markdown, Stack, Typography, useNotification } from "@semoss/ui"; +import { LoadingScreen } from "@/components/ui"; +import { useEngine, usePixel } from "@/hooks"; /** * Wrap the Database, Storage, Model routes */ export const EngineUsagePage = () => { - // get the database information - const { active } = useEngine(); - const notification = useNotification(); + // get the database information + const { active } = useEngine(); + const notification = useNotification(); - // get the engine info - const GetEngineUsage = usePixel<{ - code: string; - label: string; - type: string; - }>(`GetEngineUsage(engine=["${active.id}"]);`); + // get the engine info + const GetEngineUsage = usePixel<{ + code: string; + label: string; + type: string; + }>(`GetEngineUsage(engine=["${active.id}"]);`); - /** - * Copy text and add it to the clipboard - * @param text - text to copy - */ - const copy = async (text: string) => { - try { - await navigator.clipboard.writeText(text); + /** + * Copy text and add it to the clipboard + * @param text - text to copy + */ + const copy = async (text: string) => { + try { + await navigator.clipboard.writeText(text); - notification.add({ - color: 'success', - message: 'Successfully copied code', - }); - } catch (e) { - notification.add({ - color: 'error', - message: 'Unable to copy code', - }); - } - }; + notification.add({ + color: "success", + message: "Successfully copied code", + }); + } catch (e) { + notification.add({ + color: "error", + message: "Unable to copy code", + }); + } + }; - // show a loading screen when it is pending - if (GetEngineUsage.status !== 'SUCCESS') { - return ; - } + // show a loading screen when it is pending + if (GetEngineUsage.status !== "SUCCESS") { + return ; + } - return ( - - - Use in Code - - {Object.keys(GetEngineUsage.data).length === 0 ? ( - - No Details - - ) : ( - '' - )} - {Object.keys(GetEngineUsage.data).map((key, idx) => { - const { code, label } = GetEngineUsage.data[key]; + return ( + + + Use in Code + + {Object.keys(GetEngineUsage.data).length === 0 ? ( + + No Details + + ) : ( + "" + )} + {Object.keys(GetEngineUsage.data).map((key, idx) => { + const { code, label } = GetEngineUsage.data[key]; - if (!code) { - return null; - } + if (!code) { + return null; + } - return ( - - {label} - { - return ( - - {children} - - ); - }, - }} - > - {code} - - - ); - })} - - ); + return ( + + {label} + { + return ( + + {children} + + ); + }, + }} + > + {code} + + + ); + })} + + ); }; diff --git a/packages/client/src/pages/engine/SyncChangesModal.tsx b/packages/client/src/pages/engine/SyncChangesModal.tsx index 2223129a02..a9b4dcedb8 100644 --- a/packages/client/src/pages/engine/SyncChangesModal.tsx +++ b/packages/client/src/pages/engine/SyncChangesModal.tsx @@ -1,197 +1,198 @@ -import React, { useState, useMemo } from 'react'; +import type React from "react"; +import { useMemo, useState } from "react"; import { - Button, - Checkbox, - FormControlLabel, - TextField, - Stack, - Typography, - Divider, - Modal, -} from '@semoss/ui'; + Button, + Checkbox, + Divider, + FormControlLabel, + Modal, + Stack, + TextField, + Typography, +} from "@semoss/ui"; interface SyncChangesModalProps { - open: boolean; - onClose: () => void; - onApply: (selectedTables: string[], selectedViews: string[]) => void; - tables: string[]; - views: string[]; + open: boolean; + onClose: () => void; + onApply: (selectedTables: string[], selectedViews: string[]) => void; + tables: string[]; + views: string[]; } export const SyncChangesModal: React.FC = ({ - open, - onClose, - onApply, - tables, - views, + open, + onClose, + onApply, + tables, + views, }) => { - const [tableSearch, setTableSearch] = useState(''); - const [viewSearch, setViewSearch] = useState(''); - const [selectedTables, setSelectedTables] = useState([]); - const [selectedViews, setSelectedViews] = useState([]); + const [tableSearch, setTableSearch] = useState(""); + const [viewSearch, setViewSearch] = useState(""); + const [selectedTables, setSelectedTables] = useState([]); + const [selectedViews, setSelectedViews] = useState([]); - const toggleSelection = ( - id: string, - list: string[], - setter: (val: string[]) => void, - ) => { - if (list.includes(id)) { - setter(list.filter((i) => i !== id)); - } else { - setter([...list, id]); - } - }; + const toggleSelection = ( + id: string, + list: string[], + setter: (val: string[]) => void, + ) => { + if (list.includes(id)) { + setter(list.filter((i) => i !== id)); + } else { + setter([...list, id]); + } + }; - const filteredTables = useMemo( - () => - tables.filter((t) => - t.toLowerCase().includes(tableSearch.toLowerCase()), - ), - [tables, tableSearch], - ); + const filteredTables = useMemo( + () => + tables.filter((t) => + t.toLowerCase().includes(tableSearch.toLowerCase()), + ), + [tables, tableSearch], + ); - const filteredViews = useMemo( - () => - views.filter((v) => - v.toLowerCase().includes(viewSearch.toLowerCase()), - ), - [views, viewSearch], - ); + const filteredViews = useMemo( + () => + views.filter((v) => + v.toLowerCase().includes(viewSearch.toLowerCase()), + ), + [views, viewSearch], + ); - const allTablesSelected = selectedTables.length === tables.length; - const allViewsSelected = selectedViews.length === views.length; + const allTablesSelected = selectedTables.length === tables.length; + const allViewsSelected = selectedViews.length === views.length; - return ( - - Sync Changes - - - Select tables and views below to sync with external database - changes. -
- Note: any local changes made to selected table and - view properties will be overwritten by sync. -
+ return ( + + Sync Changes + + + Select tables and views below to sync with external database + changes. +
+ Note: any local changes made to selected table and + view properties will be overwritten by sync. +
- + - - - - Select Tables: - - setTableSearch(e.target.value)} - /> - - setSelectedTables( - allTablesSelected ? [] : tables, - ) - } - /> - } - label="(Select searched items)" - /> - - {filteredTables.map((t) => ( - - toggleSelection( - t, - selectedTables, - setSelectedTables, - ) - } - /> - } - label={t} - /> - ))} - - - - - Select Views: - - setViewSearch(e.target.value)} - /> - - setSelectedViews( - allViewsSelected ? [] : views, - ) - } - /> - } - label="(Select all)" - /> - - {filteredViews.map((v) => ( - - toggleSelection( - v, - selectedViews, - setSelectedViews, - ) - } - /> - } - label={v} - /> - ))} - - - -
- - - - -
- ); + + + + Select Tables: + + setTableSearch(e.target.value)} + /> + + setSelectedTables( + allTablesSelected ? [] : tables, + ) + } + /> + } + label="(Select searched items)" + /> + + {filteredTables.map((t) => ( + + toggleSelection( + t, + selectedTables, + setSelectedTables, + ) + } + /> + } + label={t} + /> + ))} + + + + + Select Views: + + setViewSearch(e.target.value)} + /> + + setSelectedViews( + allViewsSelected ? [] : views, + ) + } + /> + } + label="(Select all)" + /> + + {filteredViews.map((v) => ( + + toggleSelection( + v, + selectedViews, + setSelectedViews, + ) + } + /> + } + label={v} + /> + ))} + + + +
+ + + + +
+ ); }; diff --git a/packages/client/src/pages/engine/engine.constants.ts b/packages/client/src/pages/engine/engine.constants.ts index 1c4cd72c09..b488640c01 100644 --- a/packages/client/src/pages/engine/engine.constants.ts +++ b/packages/client/src/pages/engine/engine.constants.ts @@ -1,252 +1,250 @@ import { - Inventory2Outlined, - SwitchAccessShortcutOutlined, - TokenOutlined, -} from '@mui/icons-material'; - -import { ENGINE_TYPES, Role } from '@/types'; -import { ModelBrain } from '@/assets/img/ModelBrain'; -import { Database } from '@/assets/img/Database'; - -import { EngineOverviewPage } from './EngineOverviewPage'; -import { EngineMetadataPage } from './EngineMetadataPage'; -import { EngineSettingsPage } from './EngineSettingsPage'; -import { EngineFilePage } from './EngineFilePage'; -import { EngineQAPage } from './EngineQAPage'; + Inventory2Outlined, + SwitchAccessShortcutOutlined, + TokenOutlined, +} from "@mui/icons-material"; +import { Database } from "@/assets/img/Database"; +import { ModelBrain } from "@/assets/img/ModelBrain"; +import type { ENGINE_TYPES, Role } from "@/types"; +import { EngineFilePage } from "./EngineFilePage"; +import { EngineMetadataPage } from "./EngineMetadataPage"; +import { EngineOverviewPage } from "./EngineOverviewPage"; +import { EngineQAPage } from "./EngineQAPage"; +import { EngineSettingsPage } from "./EngineSettingsPage"; +import { EngineSmssPage } from "./EngineSmssPage"; // import { EngineQueryDataPage } from './EngineQueryDataPage'; // import { EngineReplaceDataPage } from './EngineReplaceDataPage'; -import { EngineUsagePage } from './EngineUsagePage'; -import { EngineSmssPage } from './EngineSmssPage'; +import { EngineUsagePage } from "./EngineUsagePage"; export const ENGINE_ROUTES: { - /** Name of the route */ - name: string; + /** Name of the route */ + name: string; - /** Path of the page */ - path: string; + /** Path of the page */ + path: string; - /** Icon to render in the page */ - icon: React.FunctionComponent; + /** Icon to render in the page */ + icon: React.FunctionComponent; - /** Type of the engine */ - type: ENGINE_TYPES; + /** Type of the engine */ + type: ENGINE_TYPES; - /** Description of the engine*/ - description: string; + /** Description of the engine*/ + description: string; - /** Child paths associated with a specific engine */ - specific: { - /** Name of the specific page */ - name: string; + /** Child paths associated with a specific engine */ + specific: { + /** Name of the specific page */ + name: string; - /** Path of the specific page */ - path: string; + /** Path of the specific page */ + path: string; - /** Restrict to certain roles (set to false to allow all) */ - restrict: Role[] | false; + /** Restrict to certain roles (set to false to allow all) */ + restrict: Role[] | false; - /** Component to render */ - component: React.FunctionComponent; - }[]; + /** Component to render */ + component: React.FunctionComponent; + }[]; }[] = [ - { - name: 'Function', - path: 'function', - type: 'FUNCTION', - description: - 'Expose and reuse LLM functionality in the form of functions to promote efficiency across app development. These functions include LLM Guard scanners to ensure the secure use of LLMs. ', - icon: SwitchAccessShortcutOutlined, - specific: [ - { - name: 'Overview', - path: '', - component: EngineOverviewPage, - restrict: false, - }, - { - name: 'Usage', - path: 'usage', - component: EngineUsagePage, - restrict: ['EDIT', 'OWNER', 'READ_ONLY'], - }, - { - name: 'Access Control', - path: 'access-control', - component: EngineSettingsPage, - restrict: ['EDIT', 'OWNER'], - }, - { - name: 'SMSS', - path: 'smss', - component: EngineSmssPage, - restrict: ['OWNER'], - }, - ], - }, - { - name: 'Model', - path: 'model', - type: 'MODEL', - description: - 'Models are diverse, with particular strengths and weaknesses specific to each use case. Our model catalog exposes these models in an abstracted fashion, allowing data scientists to hand-select and/or swap models as desired.', - icon: ModelBrain as React.FunctionComponent, - specific: [ - { - name: 'Overview', - path: '', - component: EngineOverviewPage, - restrict: false, - }, - { - name: 'Usage', - path: 'usage', - component: EngineUsagePage, - restrict: ['EDIT', 'OWNER', 'READ_ONLY'], - }, - { - name: 'Access Control', - path: 'access-control', - component: EngineSettingsPage, - restrict: ['EDIT', 'OWNER'], - }, - { - name: 'SMSS', - path: 'smss', - component: EngineSmssPage, - restrict: ['OWNER'], - }, - ], - }, - { - name: 'Database', - path: 'database', - type: 'DATABASE', - description: - 'Database catalog is an integrated data nexus connecting to diverse databases and serving as a springboard for unified data orchestration, innovation, and insights. Access structured data sources like relational database management systems (RDBMS), Triplestore/RDF, graph databases, Excel/CSVs, and data exposed via API. ', - icon: Database as React.FunctionComponent, - specific: [ - { - name: 'Overview', - path: '', - component: EngineOverviewPage, - restrict: false, - }, - { - name: 'Metadata', - path: 'metadata', - component: EngineMetadataPage, - restrict: ['EDIT', 'OWNER', 'READ_ONLY'], - }, - { - name: 'Usage', - path: 'usage', - component: EngineUsagePage, - restrict: ['EDIT', 'OWNER', 'READ_ONLY'], - }, - // { - // name: 'Query', - // path: 'query', - // component: EngineQueryDataPage, - // restrict: ['EDIT', 'OWNER', 'READ_ONLY'], - // }, - // { - // name: 'Replace', - // path: 'replace', - // component: EngineReplaceDataPage, - // restrict: ['EDIT', 'OWNER'], - // }, - { - name: 'Access Control', - path: 'access-control', - component: EngineSettingsPage, - restrict: ['EDIT', 'OWNER'], - }, - { - name: 'SMSS', - path: 'smss', - component: EngineSmssPage, - restrict: ['OWNER'], - }, - ], - }, - { - name: 'Vector', - path: 'vector', - type: 'VECTOR', - description: - 'Knowledge repositories, also known as vector databases, enable fast retrieval of information and semantic search. Create knowledge repositories on the fly and connect them for simplified reuse across apps.  ', - icon: TokenOutlined, - specific: [ - { - name: 'Overview', - path: '', - component: EngineOverviewPage, - restrict: false, - }, - { - name: 'Usage', - path: 'usage', - component: EngineUsagePage, - restrict: ['EDIT', 'OWNER', 'READ_ONLY'], - }, - { - name: 'Files', - path: 'files', - component: EngineFilePage, - restrict: ['EDIT', 'OWNER', 'READ_ONLY'], - }, - { - name: 'Q&A', - path: 'qa', - component: EngineQAPage, - restrict: ['EDIT', 'OWNER', 'READ_ONLY'], - }, - { - name: 'Access Control', - path: 'access-control', - component: EngineSettingsPage, - restrict: ['EDIT', 'OWNER'], - }, - { - name: 'SMSS', - path: 'smss', - component: EngineSmssPage, - restrict: ['OWNER'], - }, - ], - }, - { - name: 'Storage', - path: 'storage', - type: 'STORAGE', - description: - 'Tapping into unstructured data (e.g., audio, video, images, code) is critical when training and using AI solutions. Our storage catalog enables integration with many industry-leading cloud storage solutions to effortlessly access a project’s unstructured data.', - icon: Inventory2Outlined, - specific: [ - { - name: 'Overview', - path: '', - component: EngineOverviewPage, - restrict: false, - }, - { - name: 'Usage', - path: 'usage', - component: EngineUsagePage, - restrict: ['EDIT', 'OWNER', 'READ_ONLY'], - }, - { - name: 'Settings', - path: 'settings', - component: EngineSettingsPage, - restrict: ['EDIT', 'OWNER'], - }, - { - name: 'SMSS', - path: 'smss', - component: EngineSmssPage, - restrict: ['OWNER'], - }, - ], - }, + { + name: "Function", + path: "function", + type: "FUNCTION", + description: + "Expose and reuse LLM functionality in the form of functions to promote efficiency across app development. These functions include LLM Guard scanners to ensure the secure use of LLMs. ", + icon: SwitchAccessShortcutOutlined, + specific: [ + { + name: "Overview", + path: "", + component: EngineOverviewPage, + restrict: false, + }, + { + name: "Usage", + path: "usage", + component: EngineUsagePage, + restrict: ["EDIT", "OWNER", "READ_ONLY"], + }, + { + name: "Access Control", + path: "access-control", + component: EngineSettingsPage, + restrict: ["EDIT", "OWNER"], + }, + { + name: "SMSS", + path: "smss", + component: EngineSmssPage, + restrict: ["OWNER"], + }, + ], + }, + { + name: "Model", + path: "model", + type: "MODEL", + description: + "Models are diverse, with particular strengths and weaknesses specific to each use case. Our model catalog exposes these models in an abstracted fashion, allowing data scientists to hand-select and/or swap models as desired.", + icon: ModelBrain as React.FunctionComponent, + specific: [ + { + name: "Overview", + path: "", + component: EngineOverviewPage, + restrict: false, + }, + { + name: "Usage", + path: "usage", + component: EngineUsagePage, + restrict: ["EDIT", "OWNER", "READ_ONLY"], + }, + { + name: "Access Control", + path: "access-control", + component: EngineSettingsPage, + restrict: ["EDIT", "OWNER"], + }, + { + name: "SMSS", + path: "smss", + component: EngineSmssPage, + restrict: ["OWNER"], + }, + ], + }, + { + name: "Database", + path: "database", + type: "DATABASE", + description: + "Database catalog is an integrated data nexus connecting to diverse databases and serving as a springboard for unified data orchestration, innovation, and insights. Access structured data sources like relational database management systems (RDBMS), Triplestore/RDF, graph databases, Excel/CSVs, and data exposed via API. ", + icon: Database as React.FunctionComponent, + specific: [ + { + name: "Overview", + path: "", + component: EngineOverviewPage, + restrict: false, + }, + { + name: "Metadata", + path: "metadata", + component: EngineMetadataPage, + restrict: ["EDIT", "OWNER", "READ_ONLY"], + }, + { + name: "Usage", + path: "usage", + component: EngineUsagePage, + restrict: ["EDIT", "OWNER", "READ_ONLY"], + }, + // { + // name: 'Query', + // path: 'query', + // component: EngineQueryDataPage, + // restrict: ['EDIT', 'OWNER', 'READ_ONLY'], + // }, + // { + // name: 'Replace', + // path: 'replace', + // component: EngineReplaceDataPage, + // restrict: ['EDIT', 'OWNER'], + // }, + { + name: "Access Control", + path: "access-control", + component: EngineSettingsPage, + restrict: ["EDIT", "OWNER"], + }, + { + name: "SMSS", + path: "smss", + component: EngineSmssPage, + restrict: ["OWNER"], + }, + ], + }, + { + name: "Vector", + path: "vector", + type: "VECTOR", + description: + "Knowledge repositories, also known as vector databases, enable fast retrieval of information and semantic search. Create knowledge repositories on the fly and connect them for simplified reuse across apps.  ", + icon: TokenOutlined, + specific: [ + { + name: "Overview", + path: "", + component: EngineOverviewPage, + restrict: false, + }, + { + name: "Usage", + path: "usage", + component: EngineUsagePage, + restrict: ["EDIT", "OWNER", "READ_ONLY"], + }, + { + name: "Files", + path: "files", + component: EngineFilePage, + restrict: ["EDIT", "OWNER", "READ_ONLY"], + }, + { + name: "Q&A", + path: "qa", + component: EngineQAPage, + restrict: ["EDIT", "OWNER", "READ_ONLY"], + }, + { + name: "Access Control", + path: "access-control", + component: EngineSettingsPage, + restrict: ["EDIT", "OWNER"], + }, + { + name: "SMSS", + path: "smss", + component: EngineSmssPage, + restrict: ["OWNER"], + }, + ], + }, + { + name: "Storage", + path: "storage", + type: "STORAGE", + description: + "Tapping into unstructured data (e.g., audio, video, images, code) is critical when training and using AI solutions. Our storage catalog enables integration with many industry-leading cloud storage solutions to effortlessly access a project’s unstructured data.", + icon: Inventory2Outlined, + specific: [ + { + name: "Overview", + path: "", + component: EngineOverviewPage, + restrict: false, + }, + { + name: "Usage", + path: "usage", + component: EngineUsagePage, + restrict: ["EDIT", "OWNER", "READ_ONLY"], + }, + { + name: "Settings", + path: "settings", + component: EngineSettingsPage, + restrict: ["EDIT", "OWNER"], + }, + { + name: "SMSS", + path: "smss", + component: EngineSmssPage, + restrict: ["OWNER"], + }, + ], + }, ]; diff --git a/packages/client/src/pages/engine/index.ts b/packages/client/src/pages/engine/index.ts index 450d9cdb2a..30640008d7 100644 --- a/packages/client/src/pages/engine/index.ts +++ b/packages/client/src/pages/engine/index.ts @@ -1,3 +1,3 @@ -import { EngineRouter } from './EngineRouter'; +import { EngineRouter } from "./EngineRouter"; export { EngineRouter }; diff --git a/packages/client/src/pages/import/EstablishConnectionPage.tsx b/packages/client/src/pages/import/EstablishConnectionPage.tsx index 388b43ef74..2294d1e586 100644 --- a/packages/client/src/pages/import/EstablishConnectionPage.tsx +++ b/packages/client/src/pages/import/EstablishConnectionPage.tsx @@ -1,494 +1,493 @@ -import React, { useEffect, useState, useMemo } from 'react'; +import React, { useEffect, useMemo, useState } from "react"; +import { useNavigate } from "react-router-dom"; import { - styled, - Box, - Button, - Modal, - Skeleton, - Stack, - Typography, - Checkbox, - useNotification, -} from '@semoss/ui'; -import { useNavigate } from 'react-router-dom'; -import { useRootStore } from '@/hooks'; -import { useStepper } from '@/hooks'; -import { Metamodel } from '@/components/metamodel'; + Box, + Button, + Checkbox, + Modal, + Skeleton, + Stack, + styled, + Typography, + useNotification, +} from "@semoss/ui"; +import { Metamodel } from "@/components/metamodel"; +import { useRootStore, useStepper } from "@/hooks"; const StyledBox = styled(Box)({ - boxShadow: '0px 5px 22px 0px rgba(0, 0, 0, 0.06)', - width: '100%', - padding: '16px 16px 16px 16px', - marginBottom: '32px', + boxShadow: "0px 5px 22px 0px rgba(0, 0, 0, 0.06)", + width: "100%", + padding: "16px 16px 16px 16px", + marginBottom: "32px", }); export const EstablishConnectionPage = () => { - // Right now this is purposed for the DB Connectors; - const { configStore, monolithStore } = useRootStore(); - const notification = useNotification(); - const { steps, setSteps, setIsLoading } = useStepper(); - - const navigate = useNavigate(); - const insightId = configStore.store.insightID; - - const [openModal, setOpenModal] = useState(false); - const [tables, setTables] = useState([]); - const [views, setviews] = useState([]); - - // Used for edges and nodes - const [metamodel, setMetamodel] = useState(null); - - useEffect(() => { - // If Database Connector - getTablesAndViews(); - - // If Excel (Drag and Drop) - return () => { - setMetamodel(null); - }; - }, []); - - /** - * @name getTablesAndViews - * @desc connects to db for user to make selection on tables to bring into metamodel - */ - const getTablesAndViews = async () => { - setIsLoading(true); - - const formDetails = steps[steps.length - 1]; - const pixel = `ExternalJdbcTablesAndViews(conDetails=[ + // Right now this is purposed for the DB Connectors; + const { configStore, monolithStore } = useRootStore(); + const notification = useNotification(); + const { steps, setSteps, setIsLoading } = useStepper(); + + const navigate = useNavigate(); + const insightId = configStore.store.insightID; + + const [openModal, setOpenModal] = useState(false); + const [tables, setTables] = useState([]); + const [views, setviews] = useState([]); + + // Used for edges and nodes + const [metamodel, setMetamodel] = useState(null); + + useEffect(() => { + // If Database Connector + getTablesAndViews(); + + // If Excel (Drag and Drop) + return () => { + setMetamodel(null); + }; + }, []); + + /** + * @name getTablesAndViews + * @desc connects to db for user to make selection on tables to bring into metamodel + */ + const getTablesAndViews = async () => { + setIsLoading(true); + + const formDetails = steps[steps.length - 1]; + const pixel = `ExternalJdbcTablesAndViews(conDetails=[ ${JSON.stringify(formDetails.data)} ])`; - const resp = await monolithStore.runQuery(pixel); - const output = resp.pixelReturn[0].output, - operationType = resp.pixelReturn[0].operationType; + const resp = await monolithStore.runQuery(pixel); + const output = resp.pixelReturn[0].output, + operationType = resp.pixelReturn[0].operationType; - setIsLoading(false); + setIsLoading(false); - if (operationType.indexOf('ERROR') > -1) { - notification.add({ - color: 'error', - message: output ? output : 'Error connecting to database', - }); + if (operationType.indexOf("ERROR") > -1) { + notification.add({ + color: "error", + message: output ? output : "Error connecting to database", + }); - const newSteps = [steps[0], steps[1]]; + const newSteps = [steps[0], steps[1]]; - // go back to form step - setSteps(newSteps, 1); - } else { - setOpenModal(true); - setTables(output.tables); - setviews(output.views); - } - return; - }; + // go back to form step + setSteps(newSteps, 1); + } else { + setOpenModal(true); + setTables(output.tables); + setviews(output.views); + } + return; + }; - const dbConnectMetamodelRetrieval = async (data) => { - setIsLoading(true); + const dbConnectMetamodelRetrieval = async (data) => { + setIsLoading(true); - const formDetails = steps[steps.length - 1]; + const formDetails = steps[steps.length - 1]; - let pixel = ''; - pixel += ` + let pixel = ""; + pixel += ` ExternalJdbcSchema(conDetails=[${JSON.stringify( - formDetails.data, - )}], filters=[${data.tables}]); + formDetails.data, + )}], filters=[${data.tables}]); `; - const resp = await monolithStore.runQuery(pixel); - const output = resp.pixelReturn[0].output, - operationType = resp.pixelReturn[0].operationType; - - setIsLoading(false); - - if (operationType.indexOf('ERROR') > -1) { - notification.add({ - color: 'error', - message: output, - }); - } else { - setMetamodel(output); - setOpenModal(false); - } - }; - - const returnToTablesAndViews = () => { - setMetamodel(null); - setOpenModal(true); - }; - - return ( - <> - {openModal ? ( - { - dbConnectMetamodelRetrieval(values); - }} - tables={tables} - views={views} - /> - ) : null} - {/* Metamodel */} - {metamodel ? ( - - - - ) : null} - - ); + const resp = await monolithStore.runQuery(pixel); + const output = resp.pixelReturn[0].output, + operationType = resp.pixelReturn[0].operationType; + + setIsLoading(false); + + if (operationType.indexOf("ERROR") > -1) { + notification.add({ + color: "error", + message: output, + }); + } else { + setMetamodel(output); + setOpenModal(false); + } + }; + + const returnToTablesAndViews = () => { + setMetamodel(null); + setOpenModal(true); + }; + + return ( + <> + {openModal ? ( + { + dbConnectMetamodelRetrieval(values); + }} + tables={tables} + views={views} + /> + ) : null} + {/* Metamodel */} + {metamodel ? ( + + + + ) : null} + + ); }; interface TablesViewsSelectionProps { - /** Track if the edit is open */ - open: boolean; + /** Track if the edit is open */ + open: boolean; - /** Callback that is triggered on onClose */ - onClose: (values: { tables: string[]; views: string[] }) => void; + /** Callback that is triggered on onClose */ + onClose: (values: { tables: string[]; views: string[] }) => void; - /** Database Tables to select */ - tables: string[]; + /** Database Tables to select */ + tables: string[]; - /** Database Views to select */ - views: string[]; + /** Database Views to select */ + views: string[]; } const TablesViewsSelection = (props: TablesViewsSelectionProps) => { - const { open = false, onClose = () => null, tables, views } = props; - - const { steps, setSteps } = useStepper(); - - const [checkedTables, setCheckedTables] = useState({}); - const [checkedViews, setCheckedViews] = useState({}); - - /** - * @desc for checklist - */ - useEffect(() => { - // default all tables as checked - const newCheckedTables = {}; - tables.forEach((table) => { - newCheckedTables[table] = true; - }); - - setCheckedTables(newCheckedTables); - - // default all views as checked - const newCheckedViews = {}; - views.forEach((view) => { - newCheckedViews[view] = true; - }); - - setCheckedViews(newCheckedTables); - - return () => { - setCheckedTables({}); - setCheckedViews({}); - }; - }, [open, tables.length, views.length]); - - /** - * @desc toggles tables checklist - */ - const handleToggleTables = (item) => { - setCheckedTables((prevCheckedTables) => ({ - ...prevCheckedTables, - [item]: !prevCheckedTables[item], - })); - }; - - /** - * @desc toggles views checklist - */ - const handleToggleViews = (item) => { - setCheckedViews((prevCheckedViews) => ({ - ...prevCheckedViews, - [item]: !prevCheckedViews[item], - })); - }; - - /** - * @desc formats tables and views to send to metamodeling pixel - */ - const sendTableViewFilters = () => { - const formattedTableList = []; - const formattedViewList = []; - - Object.entries(checkedTables).forEach((table) => { - if (table[1]) { - formattedTableList.push(table[0]); - } - }); - - Object.entries(checkedViews).forEach((view) => { - if (view[1]) { - formattedViewList.push(view[0]); - } - }); - - onClose({ - tables: formattedTableList, - views: formattedViewList, - }); - }; - - return ( - - - Select Tables and Views to grab from data source - - - {open && ( - -
- Tables - - {tables.map((table, i) => { - return ( -
- { - handleToggleTables(table); - }} - label={{table}} - /> -
- ); - })} -
-
- Views - {views.map((view, i) => { - return ( -
- { - handleToggleViews(view); - }} - label={{view}} - /> -
- ); - })} -
-
- )} -
- - - - -
- ); + const { open = false, onClose = () => null, tables, views } = props; + + const { steps, setSteps } = useStepper(); + + const [checkedTables, setCheckedTables] = useState({}); + const [checkedViews, setCheckedViews] = useState({}); + + /** + * @desc for checklist + */ + useEffect(() => { + // default all tables as checked + const newCheckedTables = {}; + tables.forEach((table) => { + newCheckedTables[table] = true; + }); + + setCheckedTables(newCheckedTables); + + // default all views as checked + const newCheckedViews = {}; + views.forEach((view) => { + newCheckedViews[view] = true; + }); + + setCheckedViews(newCheckedTables); + + return () => { + setCheckedTables({}); + setCheckedViews({}); + }; + }, [open, tables.length, views.length]); + + /** + * @desc toggles tables checklist + */ + const handleToggleTables = (item) => { + setCheckedTables((prevCheckedTables) => ({ + ...prevCheckedTables, + [item]: !prevCheckedTables[item], + })); + }; + + /** + * @desc toggles views checklist + */ + const handleToggleViews = (item) => { + setCheckedViews((prevCheckedViews) => ({ + ...prevCheckedViews, + [item]: !prevCheckedViews[item], + })); + }; + + /** + * @desc formats tables and views to send to metamodeling pixel + */ + const sendTableViewFilters = () => { + const formattedTableList = []; + const formattedViewList = []; + + Object.entries(checkedTables).forEach((table) => { + if (table[1]) { + formattedTableList.push(table[0]); + } + }); + + Object.entries(checkedViews).forEach((view) => { + if (view[1]) { + formattedViewList.push(view[0]); + } + }); + + onClose({ + tables: formattedTableList, + views: formattedViewList, + }); + }; + + return ( + + + Select Tables and Views to grab from data source + + + {open && ( + +
+ Tables + + {tables.map((table, i) => { + return ( +
+ { + handleToggleTables(table); + }} + label={{table}} + /> +
+ ); + })} +
+
+ Views + {views.map((view, i) => { + return ( +
+ { + handleToggleViews(view); + }} + label={{view}} + /> +
+ ); + })} +
+
+ )} +
+ + + + +
+ ); }; interface JDBCSchemaInterface { - positions: Record; - tables: { - columns: string[]; - isPrimKey: boolean[]; - raw_type: string[]; - table: string; - type: string[]; - }[]; - relationships: { fromTable: string; toTable: string; relName: string }[]; + positions: Record; + tables: { + columns: string[]; + isPrimKey: boolean[]; + raw_type: string[]; + table: string; + type: string[]; + }[]; + relationships: { fromTable: string; toTable: string; relName: string }[]; } interface MetamodelViewProps { - metamodel: JDBCSchemaInterface; - returnToTablesAndViews: () => void; + metamodel: JDBCSchemaInterface; + returnToTablesAndViews: () => void; } export const MetamodelView = (props: MetamodelViewProps) => { - const { metamodel, returnToTablesAndViews } = props; - - const { monolithStore } = useRootStore(); - const navigate = useNavigate(); - const notification = useNotification(); - const { steps, setIsLoading, setSteps } = useStepper(); - - /** - * - * @param data - * @desc Needs to be done at top level since this is very similar to other RDBMS dbs - */ - const saveDatabase = async (data) => { - const formDetails = steps[steps.length - 1]; - const relations = []; - const tables = {}; - const owlPositions = {}; - - setIsLoading(true); - - data.nodes.forEach((node) => { - const tableInfo = node.data; - const cols = node.data.properties; - const firstCol = cols[0].name; - - if (!tables[tableInfo.name + '.' + firstCol]) { - const columns = []; - - cols.forEach((col) => { - columns.push(col.name); - }); - - tables[tableInfo.name + '.' + firstCol] = columns; - } - - if (!owlPositions[node.id]) { - owlPositions[node.id] = { - top: node.position.y, - left: node.position.x, - }; - } - }); - - const pixel = `databaseVar = RdbmsExternalUpload(conDetails=[ + const { metamodel, returnToTablesAndViews } = props; + + const { monolithStore } = useRootStore(); + const navigate = useNavigate(); + const notification = useNotification(); + const { steps, setIsLoading, setSteps } = useStepper(); + + /** + * + * @param data + * @desc Needs to be done at top level since this is very similar to other RDBMS dbs + */ + const saveDatabase = async (data) => { + const formDetails = steps[steps.length - 1]; + const relations = []; + const tables = {}; + const owlPositions = {}; + + setIsLoading(true); + + data.nodes.forEach((node) => { + const tableInfo = node.data; + const cols = node.data.properties; + const firstCol = cols[0].name; + + if (!tables[tableInfo.name + "." + firstCol]) { + const columns = []; + + cols.forEach((col) => { + columns.push(col.name); + }); + + tables[tableInfo.name + "." + firstCol] = columns; + } + + if (!owlPositions[node.id]) { + owlPositions[node.id] = { + top: node.position.y, + left: node.position.x, + }; + } + }); + + const pixel = `databaseVar = RdbmsExternalUpload(conDetails=[ ${JSON.stringify(formDetails.data)}], database=["${ - formDetails.title - }"], metamodel=[ + formDetails.title + }"], metamodel=[ ${JSON.stringify({ - relationships: relations, - tables: tables, - })} + relationships: relations, + tables: tables, + })} ]); SaveOwlPositions(database=[databaseVar], positionMap=[ ${JSON.stringify(owlPositions)} ]);`; - const resp = await monolithStore.runQuery(pixel); - const output = resp.pixelReturn[0].output, - operationType = resp.pixelReturn[0].operationType; - - setIsLoading(false); - - if (operationType.indexOf('ERROR') > -1) { - console.warn('RDBMSExternalUpload Reactor bug'); - notification.add({ - color: 'error', - message: output, - }); - } else { - navigate(`/engine/database/${output.database_id}`); - return; - } - }; - - /** - * @desc tables for metamodel - */ - const nodes = useMemo(() => { - const formattedNodes = []; - - if (metamodel) { - Object.entries(metamodel.positions).forEach((table, i) => { - const node = { - data: { - name: table[0], - properties: [], // get columns from metamodel.nodeProp - }, - id: table[0], - position: { x: table[1].left, y: table[1].top }, - type: 'metamodel', - }; - - const foundTable = metamodel.tables.find( - (obj) => obj.table === table[0], - ); - - foundTable.columns.forEach((col, i) => { - node.data.properties.push({ - id: table[0] + '__' + col, - name: col, - type: foundTable.type[i], - }); - }); - formattedNodes.push(node); - }); - } - - return formattedNodes; - }, [metamodel]); - - /** - * @desc relations for metamodel - */ - const edges = useMemo(() => { - const newEdges = []; - if (metamodel) { - metamodel.relationships.forEach((rel) => { - newEdges.push({ - id: rel.relName, - type: 'floating', - source: rel.fromTable, - target: rel.toTable, - }); - }); - } - return newEdges; - }, [metamodel]); - - return ( -
-
- { - saveDatabase(data); - }} - /> -
-
- - - {/* + + {/* */} -
-
- // - // Metamodel - // - //
- // { - // saveDatabase(data); - // }} - // /> - //
- //
- // - // - // - // - // - //
- ); + + + // + // Metamodel + // + //
+ // { + // saveDatabase(data); + // }} + // /> + //
+ //
+ // + // + // + // + // + //
+ ); }; diff --git a/packages/client/src/pages/import/ImportConnectionPage.tsx b/packages/client/src/pages/import/ImportConnectionPage.tsx index 7da1aa6bdc..a36fc7549e 100644 --- a/packages/client/src/pages/import/ImportConnectionPage.tsx +++ b/packages/client/src/pages/import/ImportConnectionPage.tsx @@ -1,320 +1,318 @@ -import React from 'react'; -import { styled, Box, useNotification } from '@semoss/ui'; -import { useNavigate } from 'react-router-dom'; -import { ImportForm } from '@/components/import'; -import { useRootStore } from '@/hooks'; - -import { useStepper } from '@/hooks'; +import React from "react"; +import { useNavigate } from "react-router-dom"; +import { Box, styled, useNotification } from "@semoss/ui"; +import { ImportForm } from "@/components/import"; +import { useRootStore, useStepper } from "@/hooks"; const StyledBox = styled(Box)(({ theme }) => ({ - boxShadow: '0px 5px 22px 0px rgba(0, 0, 0, 0.06)', - width: '100%', - padding: '16px 16px 16px 16px', - marginBottom: '32px', + boxShadow: "0px 5px 22px 0px rgba(0, 0, 0, 0.06)", + width: "100%", + padding: "16px 16px 16px 16px", + marginBottom: "32px", })); export const ImportConnectionPage = () => { - const { monolithStore, configStore } = useRootStore(); - const navigate = useNavigate(); - const notification = useNotification(); - const { steps, setIsLoading } = useStepper(); - - // File Uploads Database - const [predictDataTypes, setPredictDataTypes] = React.useState(null); - const [metamodel, setMetamodel] = React.useState(null); - - /** - * - * @param values - * @returns - * @desc Based on type of submitted form it will either: - * 1. Hit the respective reactor to submit - * 2. Sets next step in process to continue with submission - * 3. Refactor - */ - const formSubmit = async (values: { - type: 'VECTOR' | 'STORAGE' | 'MODEL' | 'FUNCTION' | 'UPLOAD'; - name: string; - fields: unknown[]; - secondaryFields?: unknown[]; - }) => { - // let pixel = ''; // 'VECTOR' | 'STORAGE' | 'MODEL' | 'FUNCTION' | 'UPLOAD' - setIsLoading(true); - if (values.type === 'STORAGE') { - /** Storage: START */ - const pixel = `CreateStorageEngine( + const { monolithStore, configStore } = useRootStore(); + const navigate = useNavigate(); + const notification = useNotification(); + const { steps, setIsLoading } = useStepper(); + + // File Uploads Database + const [predictDataTypes, setPredictDataTypes] = React.useState(null); + const [metamodel, setMetamodel] = React.useState(null); + + /** + * + * @param values + * @returns + * @desc Based on type of submitted form it will either: + * 1. Hit the respective reactor to submit + * 2. Sets next step in process to continue with submission + * 3. Refactor + */ + const formSubmit = async (values: { + type: "VECTOR" | "STORAGE" | "MODEL" | "FUNCTION" | "UPLOAD"; + name: string; + fields: unknown[]; + secondaryFields?: unknown[]; + }) => { + // let pixel = ''; // 'VECTOR' | 'STORAGE' | 'MODEL' | 'FUNCTION' | 'UPLOAD' + setIsLoading(true); + if (values.type === "STORAGE") { + /** Storage: START */ + const pixel = `CreateStorageEngine( storage=["${values.name}"], storageDetails=[${JSON.stringify(values.fields)}] )`; - monolithStore.runQuery(pixel).then((response) => { - const output = response.pixelReturn[0].output, - operationType = response.pixelReturn[0].operationType; - - setIsLoading(false); - - if (operationType.indexOf('ERROR') > -1) { - notification.add({ - color: 'error', - message: output, - }); - return; - } - - notification.add({ - color: 'success', - message: `Successfully added to catalog storage`, - }); - - navigate(`/engine/storage/${output.database_id}`); - }); - - return; - } else if (values.type === 'MODEL') { - /** Model: START */ - let pixel; - if (values.secondaryFields['FILE']) { - const upload = await monolithStore.uploadFile( - [values.secondaryFields['FILE']], - configStore.store.insightID, - ); - pixel = `CreateModelEngine( + monolithStore.runQuery(pixel).then((response) => { + const output = response.pixelReturn[0].output, + operationType = response.pixelReturn[0].operationType; + + setIsLoading(false); + + if (operationType.indexOf("ERROR") > -1) { + notification.add({ + color: "error", + message: output, + }); + return; + } + + notification.add({ + color: "success", + message: `Successfully added to catalog storage`, + }); + + navigate(`/engine/storage/${output.database_id}`); + }); + + return; + } else if (values.type === "MODEL") { + /** Model: START */ + let pixel; + if (values.secondaryFields["FILE"]) { + const upload = await monolithStore.uploadFile( + [values.secondaryFields["FILE"]], + configStore.store.insightID, + ); + pixel = `CreateModelEngine( model=["${values.name}"], modelDetails=[${JSON.stringify(values.fields)}], filePaths=["${upload[0].fileLocation}"] )`; - } else { - pixel = `CreateModelEngine( + } else { + pixel = `CreateModelEngine( model=["${values.name}"], modelDetails=[${JSON.stringify(values.fields)}] )`; - } - - monolithStore.runQuery(pixel).then(async (response) => { - const output = response.pixelReturn[0].output, - operationType = response.pixelReturn[0].operationType; - - setIsLoading(false); - - if (operationType.indexOf('ERROR') > -1) { - notification.add({ - color: 'error', - message: output, - }); - return; - } - - notification.add({ - color: 'success', - message: `Successfully added LLM to catalog`, - }); - navigate(`/engine/model/${output.database_id}`); - }); - return; - } else if (values.type === 'VECTOR') { - /** Vector Database: START */ - const meta = {}; - if (values.fields['DESCRIPTION']) { - meta['description'] = values.fields['DESCRIPTION']; - } - if (values.fields['TAGS']) { - meta['tag'] = values.fields['TAGS']; - } - const pixel = ` + } + + monolithStore.runQuery(pixel).then(async (response) => { + const output = response.pixelReturn[0].output, + operationType = response.pixelReturn[0].operationType; + + setIsLoading(false); + + if (operationType.indexOf("ERROR") > -1) { + notification.add({ + color: "error", + message: output, + }); + return; + } + + notification.add({ + color: "success", + message: `Successfully added LLM to catalog`, + }); + navigate(`/engine/model/${output.database_id}`); + }); + return; + } else if (values.type === "VECTOR") { + /** Vector Database: START */ + const meta = {}; + if (values.fields["DESCRIPTION"]) { + meta["description"] = values.fields["DESCRIPTION"]; + } + if (values.fields["TAGS"]) { + meta["tag"] = values.fields["TAGS"]; + } + const pixel = ` CreateVectorDatabaseEngine ( database=["${values.name}"], conDetails=[${JSON.stringify(values.fields)}] ) ; `; - monolithStore.runQuery(pixel).then(async (response) => { - const output = response.pixelReturn[0].output, - operationType = response.pixelReturn[0].operationType; - - if (operationType.indexOf('ERROR') > -1) { - notification.add({ - color: 'error', - message: output, - }); - setIsLoading(false); - return; - } - - notification.add({ - color: 'success', - message: `Successfully added vector database to catalog`, - }); - - if (values.secondaryFields['EMBEDDINGS']) { - const upload = await monolithStore.uploadFile( - [values.secondaryFields['EMBEDDINGS']], - configStore.store.insightID, - ); - - const secondaryPixel = `CreateEmbeddingsFromDocuments( + monolithStore.runQuery(pixel).then(async (response) => { + const output = response.pixelReturn[0].output, + operationType = response.pixelReturn[0].operationType; + + if (operationType.indexOf("ERROR") > -1) { + notification.add({ + color: "error", + message: output, + }); + setIsLoading(false); + return; + } + + notification.add({ + color: "success", + message: `Successfully added vector database to catalog`, + }); + + if (values.secondaryFields["EMBEDDINGS"]) { + const upload = await monolithStore.uploadFile( + [values.secondaryFields["EMBEDDINGS"]], + configStore.store.insightID, + ); + + const secondaryPixel = `CreateEmbeddingsFromDocuments( engine="${output.database_id}", filePaths=["${upload[0].fileLocation}"] );`; - monolithStore.runQuery(secondaryPixel).then((response) => { - const secondaryPixelOutput = - response.pixelReturn[0].output, - operationType = - response.pixelReturn[0].operationType; - - setIsLoading(false); - - notification.add({ - color: - operationType.indexOf('ERROR') > -1 - ? 'error' - : 'success', - message: secondaryPixelOutput, - }); - }); - } else { - setIsLoading(false); - } - if (Object.keys(meta).length !== 0) { - const thirdPixel = `SetEngineMetadata(engine=["${ - output.database_id - }"], meta=[${JSON.stringify(meta)}], jsonCleanup=[true])`; - monolithStore.runQuery(thirdPixel).then((response) => { - const thirdPixelOutput = response.pixelReturn[0].output, - operationType = - response.pixelReturn[0].operationType; - - if (operationType.indexOf('ERROR') > -1) { - notification.add({ - color: 'error', - message: thirdPixelOutput, - }); - } else { - notification.add({ - color: 'success', - message: - response.pixelReturn[0].additionalOutput[0] - .output, - }); - } - }); - } - navigate(`/engine/vector/${output.database_id}`); - }); - - return; - } else if (values.type === 'FUNCTION') { - /** Function: START */ - let pixel; - if (values.secondaryFields['FILE']) { - const upload = await monolithStore.uploadFile( - [values.secondaryFields['FILE']], - configStore.store.insightID, - ); - pixel = ` + monolithStore.runQuery(secondaryPixel).then((response) => { + const secondaryPixelOutput = + response.pixelReturn[0].output, + operationType = + response.pixelReturn[0].operationType; + + setIsLoading(false); + + notification.add({ + color: + operationType.indexOf("ERROR") > -1 + ? "error" + : "success", + message: secondaryPixelOutput, + }); + }); + } else { + setIsLoading(false); + } + if (Object.keys(meta).length !== 0) { + const thirdPixel = `SetEngineMetadata(engine=["${ + output.database_id + }"], meta=[${JSON.stringify(meta)}], jsonCleanup=[true])`; + monolithStore.runQuery(thirdPixel).then((response) => { + const thirdPixelOutput = response.pixelReturn[0].output, + operationType = + response.pixelReturn[0].operationType; + + if (operationType.indexOf("ERROR") > -1) { + notification.add({ + color: "error", + message: thirdPixelOutput, + }); + } else { + notification.add({ + color: "success", + message: + response.pixelReturn[0].additionalOutput[0] + .output, + }); + } + }); + } + navigate(`/engine/vector/${output.database_id}`); + }); + + return; + } else if (values.type === "FUNCTION") { + /** Function: START */ + let pixel; + if (values.secondaryFields["FILE"]) { + const upload = await monolithStore.uploadFile( + [values.secondaryFields["FILE"]], + configStore.store.insightID, + ); + pixel = ` CreateRestFunctionEngine(function=["${ - values.name - }"],functionDetails=[${JSON.stringify(values.fields)}], + values.name + }"],functionDetails=[${JSON.stringify(values.fields)}], filePaths=["${upload[0].fileLocation}"]);`; - } else { - pixel = ` + } else { + pixel = ` CreateRestFunctionEngine(function=["${ - values.name - }"],functionDetails=[${JSON.stringify(values.fields)}]);`; - } - - monolithStore.runQuery(pixel).then((response) => { - const output = response.pixelReturn[0].output, - operationType = response.pixelReturn[0].operationType; - - setIsLoading(false); - - if (operationType.indexOf('ERROR') > -1) { - notification.add({ - color: 'error', - message: output, - }); - return; - } - - notification.add({ - color: 'success', - message: `Successfully added function to catalog`, - }); - navigate(`/engine/function/${output.database_id}`); - }); - return; - } - - /** Connect to External: START */ - // I'll be hitting this reactor if dbDriver is in RDBMSTypeEnum on BE - // if (values.type === 'connect') { - // const pixel = `ExternalJdbcTablesAndViews(conDetails=[ - // ${JSON.stringify(values.conDetails)} - // ])`; - - // const resp = await monolithStore.runQuery(pixel); - // const output = resp.pixelReturn[0].output, - // operationType = resp.pixelReturn[0].operationType; - - // setIsLoading(false); - - // if (operationType.indexOf('ERROR') > -1) { - // notification.add({ - // color: 'error', - // message: output, - // }); - // } else { - // setMetamodel(output); - // } - // return; - // } - /** Connect to External: END */ - - /** Drag and Drop: START */ - - // if (values.METAMODEL_TYPE === 'As Suggested Metamodel') { - // monolithStore - // .uploadFile(values.FILE, insightId) - // .then((res: { fileName: string; fileLocation: string }[]) => { - // const file = res[0].fileLocation; - // monolithStore - // .runQuery( - // `PredictMetamodel(filePath=["${file}"], delimiter=["${values.DELIMETER}"], rowCount=[false])`, - // ) - // .then((res) => { - // const output = res.pixelReturn[0].output; - // setIsLoading(false); - // // format response to send to Form - // setMetamodel(output); - // }); - // }); - // } - // if (values.METAMODEL_TYPE === 'As Flat Table') { - // monolithStore - // .uploadFile(values.FILE, insightId) - // .then((res: { fileName: string; fileLocation: string }[]) => { - // const file = res[0].fileLocation; - // monolithStore - // .runQuery( - // `PredictDataTypes(filePath=["${file}"], delimiter=["${values.DELIMETER}"], rowCount=[false])`, - // ) - // .then((res) => { - // setIsLoading(false); - // setPredictDataTypes(res); - // }); - // }); - // } - - /** Drag and Drop: END */ - }; - - return ( - - formSubmit(vals)} - /> - - ); + values.name + }"],functionDetails=[${JSON.stringify(values.fields)}]);`; + } + + monolithStore.runQuery(pixel).then((response) => { + const output = response.pixelReturn[0].output, + operationType = response.pixelReturn[0].operationType; + + setIsLoading(false); + + if (operationType.indexOf("ERROR") > -1) { + notification.add({ + color: "error", + message: output, + }); + return; + } + + notification.add({ + color: "success", + message: `Successfully added function to catalog`, + }); + navigate(`/engine/function/${output.database_id}`); + }); + return; + } + + /** Connect to External: START */ + // I'll be hitting this reactor if dbDriver is in RDBMSTypeEnum on BE + // if (values.type === 'connect') { + // const pixel = `ExternalJdbcTablesAndViews(conDetails=[ + // ${JSON.stringify(values.conDetails)} + // ])`; + + // const resp = await monolithStore.runQuery(pixel); + // const output = resp.pixelReturn[0].output, + // operationType = resp.pixelReturn[0].operationType; + + // setIsLoading(false); + + // if (operationType.indexOf('ERROR') > -1) { + // notification.add({ + // color: 'error', + // message: output, + // }); + // } else { + // setMetamodel(output); + // } + // return; + // } + /** Connect to External: END */ + + /** Drag and Drop: START */ + + // if (values.METAMODEL_TYPE === 'As Suggested Metamodel') { + // monolithStore + // .uploadFile(values.FILE, insightId) + // .then((res: { fileName: string; fileLocation: string }[]) => { + // const file = res[0].fileLocation; + // monolithStore + // .runQuery( + // `PredictMetamodel(filePath=["${file}"], delimiter=["${values.DELIMETER}"], rowCount=[false])`, + // ) + // .then((res) => { + // const output = res.pixelReturn[0].output; + // setIsLoading(false); + // // format response to send to Form + // setMetamodel(output); + // }); + // }); + // } + // if (values.METAMODEL_TYPE === 'As Flat Table') { + // monolithStore + // .uploadFile(values.FILE, insightId) + // .then((res: { fileName: string; fileLocation: string }[]) => { + // const file = res[0].fileLocation; + // monolithStore + // .runQuery( + // `PredictDataTypes(filePath=["${file}"], delimiter=["${values.DELIMETER}"], rowCount=[false])`, + // ) + // .then((res) => { + // setIsLoading(false); + // setPredictDataTypes(res); + // }); + // }); + // } + + /** Drag and Drop: END */ + }; + + return ( + + formSubmit(vals)} + /> + + ); }; diff --git a/packages/client/src/pages/import/ImportLayout.tsx b/packages/client/src/pages/import/ImportLayout.tsx index 83f04e7a8a..3da3148d8e 100644 --- a/packages/client/src/pages/import/ImportLayout.tsx +++ b/packages/client/src/pages/import/ImportLayout.tsx @@ -1,78 +1,77 @@ -import { useEffect, useMemo, useState } from 'react'; -import { Outlet } from 'react-router-dom'; -import { LoadingScreen } from '@/components/ui'; - -import { StepperContext, StepperContextType } from '@/contexts'; +import { useEffect, useMemo, useState } from "react"; +import { Outlet } from "react-router-dom"; +import { LoadingScreen } from "@/components/ui"; +import { StepperContext, type StepperContextType } from "@/contexts"; export const ImportLayout = (props) => { - const { children } = props; + const { children } = props; - const [isLoading, setIsLoading] = - useState(false); - const [internalSteps, setInternalSteps] = useState< - StepperContextType['steps'] - >([]); - const [internalActiveStepIdx, setInternalActiveStepIdx] = - useState(-1); + const [isLoading, setIsLoading] = + useState(false); + const [internalSteps, setInternalSteps] = useState< + StepperContextType["steps"] + >([]); + const [internalActiveStepIdx, setInternalActiveStepIdx] = + useState(-1); - /** - * Get the active step - */ - const activeStep = useMemo(() => { - if ( - internalActiveStepIdx !== -1 && - internalSteps[internalActiveStepIdx] - ) { - return internalSteps[internalActiveStepIdx]; - } + /** + * Get the active step + */ + const activeStep = useMemo(() => { + if ( + internalActiveStepIdx !== -1 && + internalSteps[internalActiveStepIdx] + ) { + return internalSteps[internalActiveStepIdx]; + } - return null; - }, [internalSteps, internalActiveStepIdx]); + return null; + }, [internalSteps, internalActiveStepIdx]); - /** - * Update the steps in the flow - * - * step - step to add - * activeStepIdx - new step idx - */ - const setSteps: StepperContextType['setSteps'] = ( - updatedSteps, - updatedActiveStepIdx, - ) => { - // set the step - setInternalSteps(updatedSteps); + /** + * Update the steps in the flow + * + * step - step to add + * activeStepIdx - new step idx + */ + const setSteps: StepperContextType["setSteps"] = ( + updatedSteps, + updatedActiveStepIdx, + ) => { + // set the step + setInternalSteps(updatedSteps); - // navigate if open - if (updatedActiveStepIdx) { - setInternalActiveStepIdx(updatedActiveStepIdx); - } - }; + // navigate if open + if (updatedActiveStepIdx) { + setInternalActiveStepIdx(updatedActiveStepIdx); + } + }; - /** - * Set the new active step - * - * activeStepIdx - new step idx - */ - const setActiveStep: StepperContextType['setActiveStep'] = ( - updatedActiveStepIdx, - ) => { - setInternalActiveStepIdx(updatedActiveStepIdx); - }; + /** + * Set the new active step + * + * activeStepIdx - new step idx + */ + const setActiveStep: StepperContextType["setActiveStep"] = ( + updatedActiveStepIdx, + ) => { + setInternalActiveStepIdx(updatedActiveStepIdx); + }; - return ( - - {isLoading && } - {children}{' '} - - ); + return ( + + {isLoading && } + {children}{" "} + + ); }; diff --git a/packages/client/src/pages/import/ImportPage.tsx b/packages/client/src/pages/import/ImportPage.tsx index d255340fdc..f4258fe7e9 100644 --- a/packages/client/src/pages/import/ImportPage.tsx +++ b/packages/client/src/pages/import/ImportPage.tsx @@ -1,26 +1,25 @@ -import { ImportPageContent } from './ImportPageContent'; -import { ImportLayout } from './ImportLayout'; - -import { ENGINE_TYPES } from '@/types'; +import type { ENGINE_TYPES } from "@/types"; +import { ImportLayout } from "./ImportLayout"; +import { ImportPageContent } from "./ImportPageContent"; /** TODO: Refactor */ interface ImportPageProps { - /** - * Name of the section - */ - name: string; + /** + * Name of the section + */ + name: string; - /** - * What engine are you importing - */ - type: ENGINE_TYPES; + /** + * What engine are you importing + */ + type: ENGINE_TYPES; } export const ImportPage: React.FC = ({ name, type }) => { - return ( - <> - - - - - ); + return ( + <> + + + + + ); }; diff --git a/packages/client/src/pages/import/ImportPageContent.tsx b/packages/client/src/pages/import/ImportPageContent.tsx index ed86447060..6a0f6e1342 100644 --- a/packages/client/src/pages/import/ImportPageContent.tsx +++ b/packages/client/src/pages/import/ImportPageContent.tsx @@ -16,752 +16,748 @@ * - /import/model/OpenAi */ -import React, { useEffect, useRef } from 'react'; - +import Tooltip from "@mui/material/Tooltip"; +import React, { useEffect, useRef } from "react"; +import { useNavigate } from "react-router-dom"; import { - Breadcrumbs, - Card, - styled, - Search, - Typography, - Box, - Grid, - Tabs, - Tab, - Stack, - Link, -} from '@semoss/ui'; - -import { UploadData } from '../../components/import/refactor/UploadData'; -import { CopyDatabaseForm } from '../../components/import/refactor/CopyDatabaseForm'; -import { BuildDb } from '@/assets/img/BuildDb'; -import { ConnectModel } from '@/assets/img/ConnectModel'; -import { ConnectDb } from '@/assets/img/ConnectDb'; -import { CopyDb } from '@/assets/img/CopyDb'; -import { ConnectStorage } from '@/assets/img/ConnectStorage'; - -import { useStepper } from '@/hooks'; -import { useNavigate } from 'react-router-dom'; - -import { CONNECTION_OPTIONS } from './import.constants'; -import { EstablishConnectionPage, ImportConnectionPage } from '.'; -import { Help } from '@/components/help'; -import Tooltip from '@mui/material/Tooltip'; -import { ENGINE_TYPES } from '@/types'; - -const StyledContainer = styled('div')(({ theme }) => ({ - display: 'flex', - width: 'auto', - flexDirection: 'column', - alignItems: 'flex-start', + Box, + Breadcrumbs, + Card, + Grid, + Link, + Search, + Stack, + styled, + Tab, + Tabs, + Typography, +} from "@semoss/ui"; +import { BuildDb } from "@/assets/img/BuildDb"; +import { ConnectDb } from "@/assets/img/ConnectDb"; +import { ConnectModel } from "@/assets/img/ConnectModel"; +import { ConnectStorage } from "@/assets/img/ConnectStorage"; +import { CopyDb } from "@/assets/img/CopyDb"; +import { Help } from "@/components/help"; +import { useStepper } from "@/hooks"; +import type { ENGINE_TYPES } from "@/types"; +import { CopyDatabaseForm } from "../../components/import/refactor/CopyDatabaseForm"; +import { UploadData } from "../../components/import/refactor/UploadData"; +import { EstablishConnectionPage, ImportConnectionPage } from "."; +import { CONNECTION_OPTIONS } from "./import.constants"; + +const StyledContainer = styled("div")(({ theme }) => ({ + display: "flex", + width: "auto", + flexDirection: "column", + alignItems: "flex-start", })); -const StyledSearchbarContainer = styled('div')(({ theme }) => ({ - display: 'flex', - width: '100%', - alignItems: 'flex-start', - gap: theme.spacing(3), +const StyledSearchbarContainer = styled("div")(({ theme }) => ({ + display: "flex", + width: "100%", + alignItems: "flex-start", + gap: theme.spacing(3), })); -const StyledStack = styled('div')(({ theme }) => ({ - display: 'flex', - flexDirection: 'column', - gap: theme.spacing(1), +const StyledStack = styled("div")(({ theme }) => ({ + display: "flex", + flexDirection: "column", + gap: theme.spacing(1), })); const StyledCard = styled(Card, { - shouldForwardProp: (prop) => prop !== 'disabled', + shouldForwardProp: (prop) => prop !== "disabled", })<{ - disabled: boolean; + disabled: boolean; }>(({ theme, disabled }) => { - return { - backgroundColor: disabled ? theme.palette.grey['100'] : 'white', - '&:hover': { - boxShadow: disabled - ? '0px 5px 22px 0px rgba(0, 0, 0, 0.04), 0px 4px 4px 0.5px rgba(0, 0, 0, 0.03)' - : `0px 5px 22px 0px ${theme.palette.primaryContrast['shadow']}`, - cursor: 'pointer', - }, - }; + return { + backgroundColor: disabled ? theme.palette.grey["100"] : "white", + "&:hover": { + boxShadow: disabled + ? "0px 5px 22px 0px rgba(0, 0, 0, 0.04), 0px 4px 4px 0.5px rgba(0, 0, 0, 0.03)" + : `0px 5px 22px 0px ${theme.palette.primaryContrast["shadow"]}`, + cursor: "pointer", + }, + }; }); const StyledCardContent = styled(Card.Content)(() => ({ - display: 'flex', - padding: '16px', - flexDirection: 'column', - justifyContent: 'center', - alignItems: 'center', - gap: '16px', - alignSelf: 'stretch', + display: "flex", + padding: "16px", + flexDirection: "column", + justifyContent: "center", + alignItems: "center", + gap: "16px", + alignSelf: "stretch", })); const StyledBox = styled(Box)({ - boxShadow: '0px 5px 22px 0px rgba(0, 0, 0, 0.06)', - width: '100%', - padding: '16px 16px 16px 16px', - marginBottom: '32px', + boxShadow: "0px 5px 22px 0px rgba(0, 0, 0, 0.06)", + width: "100%", + padding: "16px 16px 16px 16px", + marginBottom: "32px", }); -const StyledInnerBox = styled('div')<{ isModel?: boolean }>( - ({ theme, isModel }) => ({ - display: 'flex', - alignItems: isModel ? 'flex-start' : 'center', - gap: theme.spacing(1), - flexDirection: isModel ? 'column' : 'row', - }), +const StyledInnerBox = styled("div")<{ isModel?: boolean }>( + ({ theme, isModel }) => ({ + display: "flex", + alignItems: isModel ? "flex-start" : "center", + gap: theme.spacing(1), + flexDirection: isModel ? "column" : "row", + }), ); -const StyledCardImage = styled('img')<{ isModel?: boolean }>(({ isModel }) => ({ - display: 'flex', - height: '30px', - width: '30px', - alignItems: 'flex-start', - gap: '10px', - alignSelf: 'stretch', - overflowClipMargin: 'content-box', - overflow: 'clip', - objectFit: 'cover', - borderRadius: isModel ? '8px' : 'inherit', +const StyledCardImage = styled("img")<{ isModel?: boolean }>(({ isModel }) => ({ + display: "flex", + height: "30px", + width: "30px", + alignItems: "flex-start", + gap: "10px", + alignSelf: "stretch", + overflowClipMargin: "content-box", + overflow: "clip", + objectFit: "cover", + borderRadius: isModel ? "8px" : "inherit", })); -const StyledCardText = styled('p')({ - overflow: 'hidden', - textOverflow: 'ellipsis', - whiteSpace: 'nowrap', - margin: '0', +const StyledCardText = styled("p")({ + overflow: "hidden", + textOverflow: "ellipsis", + whiteSpace: "nowrap", + margin: "0", }); -const StyledCardModelText = styled('p')({ - overflow: 'hidden', - textOverflow: 'ellipsis', - whiteSpace: 'nowrap', - margin: '2px 0 0', - alignSelf: 'stretch', - fontSize: '14px', - fontWeight: '500', - lineHeight: '143%', - letterSpacing: '0.17px', - color: '#212121', +const StyledCardModelText = styled("p")({ + overflow: "hidden", + textOverflow: "ellipsis", + whiteSpace: "nowrap", + margin: "2px 0 0", + alignSelf: "stretch", + fontSize: "14px", + fontWeight: "500", + lineHeight: "143%", + letterSpacing: "0.17px", + color: "#212121", }); const StyledTypographyText = styled(Typography)((theme) => ({ - display: 'flex', - alignItems: 'center', - padding: '0 10px', - backgroundColor: '#EBEBEB', - borderRadius: '16px', - marginLeft: 'auto !important', - fontSize: '13px', - color: '#212121', + display: "flex", + alignItems: "center", + padding: "0 10px", + backgroundColor: "#EBEBEB", + borderRadius: "16px", + marginLeft: "auto !important", + fontSize: "13px", + color: "#212121", })); const StyledFormTypeBox = styled(Box, { - shouldForwardProp: (prop) => prop !== 'disabled', + shouldForwardProp: (prop) => prop !== "disabled", })<{ - disabled: boolean; + disabled: boolean; }>(({ theme, disabled }) => { - return { - maxWidth: '215px', - maxHeight: '75px', - borderRadius: '12px', - cursor: 'pointer', - display: 'block', - justifyContent: 'center', - alignItems: 'center', - border: '1px solid rgba(0,0,0,0.1)', - padding: '16px 24px', - boxShadow: - '0px 5px 22px 0px rgba(0, 0, 0, 0.04), 0px 4px 4px 0.5px rgba(0, 0, 0, 0.03)', - backgroundColor: disabled ? theme.palette.grey['100'] : 'white', - - '&:hover': { - cursor: 'pointer', - boxShadow: disabled - ? '0px 5px 22px 0px rgba(0, 0, 0, 0.04), 0px 4px 4px 0.5px rgba(0, 0, 0, 0.03)' - : `0px 5px 22px 0px ${theme.palette.primaryContrast['shadow']}`, - }, - }; + return { + maxWidth: "215px", + maxHeight: "75px", + borderRadius: "12px", + cursor: "pointer", + display: "block", + justifyContent: "center", + alignItems: "center", + border: "1px solid rgba(0,0,0,0.1)", + padding: "16px 24px", + boxShadow: + "0px 5px 22px 0px rgba(0, 0, 0, 0.04), 0px 4px 4px 0.5px rgba(0, 0, 0, 0.03)", + backgroundColor: disabled ? theme.palette.grey["100"] : "white", + + "&:hover": { + cursor: "pointer", + boxShadow: disabled + ? "0px 5px 22px 0px rgba(0, 0, 0, 0.04), 0px 4px 4px 0.5px rgba(0, 0, 0, 0.03)" + : `0px 5px 22px 0px ${theme.palette.primaryContrast["shadow"]}`, + }, + }; }); const StyledFormTypeModelBox = styled(Box, { - shouldForwardProp: (prop) => prop !== 'disabled', + shouldForwardProp: (prop) => prop !== "disabled", })<{ - disabled: boolean; + disabled: boolean; }>(({ disabled }) => { - return { - maxWidth: '215px', - borderRadius: '8px', - cursor: 'pointer', - display: 'block', - justifyContent: 'center', - alignItems: 'center', - border: '1px solid #C4C4C4', - padding: '16px', - backgroundColor: '#fff', - opacity: disabled ? 0.6 : 1, - - '&:hover': { - cursor: disabled ? 'auto' : 'pointer', - border: disabled ? '1px solid #C4C4C4' : '1.5px solid #0471F0', - backgroundColor: disabled ? 'white' : '#F5F9FE', - }, - }; + return { + maxWidth: "215px", + borderRadius: "8px", + cursor: "pointer", + display: "block", + justifyContent: "center", + alignItems: "center", + border: "1px solid #C4C4C4", + padding: "16px", + backgroundColor: "#fff", + opacity: disabled ? 0.6 : 1, + + "&:hover": { + cursor: disabled ? "auto" : "pointer", + border: disabled ? "1px solid #C4C4C4" : "1.5px solid #0471F0", + backgroundColor: disabled ? "white" : "#F5F9FE", + }, + }; }); -const StyledSpan = styled('span')({ - '&:hover': { - cursor: 'pointer', - }, +const StyledSpan = styled("span")({ + "&:hover": { + cursor: "pointer", + }, }); const StyledCategoryTitle = styled(Box)({ - fontSize: '20px', - fontWeight: 'bold', - padding: '16px', + fontSize: "20px", + fontWeight: "bold", + padding: "16px", }); const StyledTab = styled(Tab)({ - fontSize: '14px', - fontWeight: '500', - letterSpacing: '0.4px', - color: 'rgba(0, 0, 0, 0.60)', + fontSize: "14px", + fontWeight: "500", + letterSpacing: "0.4px", + color: "rgba(0, 0, 0, 0.60)", }); const IconMapper = { - 'Connect to Database': , - 'Copy Database': , - 'Build Database': , - 'Connect to Storage': , - 'Connect to Model': , - 'Connect to Vector Database': , - 'Connect to Function': , + "Connect to Database": , + "Copy Database": , + "Build Database": , + "Connect to Storage": , + "Connect to Model": , + "Connect to Vector Database": , + "Connect to Function": , }; interface ImportPageContentProps { - /** - * What engine are you trying to import - */ - name: string; - - /** - * What engine are you trying to import - */ - type: ENGINE_TYPES; + /** + * What engine are you trying to import + */ + name: string; + + /** + * What engine are you trying to import + */ + type: ENGINE_TYPES; } export const ImportPageContent: React.FC = ({ - name, - type, + name, + type, }) => { - const { steps, activeStep, setSteps, setIsLoading, isLoading } = - useStepper(); - - const navigate = useNavigate(); - - const [importSearch, setImportSearch] = React.useState(''); - const [search, setSearch] = React.useState(''); - - const [connectionOptions, setConnectionOptions] = - React.useState(CONNECTION_OPTIONS); - const [selectedTab, setSelectedTab] = React.useState(0); - - const modelOptions = connectionOptions.MODEL; - - const scrollToTopRef = useRef(null); - - const isModelPage = steps.length > 0 && steps[0].data === 'MODEL'; - - const ModelCard = ({ model, setSteps, steps }) => { - const textRef = useRef(null); - const [isTruncated, setIsTruncated] = React.useState(false); - - useEffect(() => { - const el = textRef.current; - if (el) { - setIsTruncated(el.scrollWidth > el.clientWidth); - } - }, [model.name]); - - const cardContent = ( - { - if (!model.disable) { - setSteps( - [ - ...steps, - { - id: model.id, - title: model.name, - description: `Fill out ${ - model.name - } details in order to add ${steps[0].data.toLowerCase()} to catalog`, - data: model.fields, - }, - ], - steps.length + 1, - ); - } - }} - > - - {model.disable ? ( - - - - Coming Soon - - - ) : ( - - )} - - - {model.name} - - - - ); - - return isTruncated ? ( - - {cardContent} - - ) : ( - cardContent - ); - }; - - const getTabLabels = () => { - const tabs = new Set(); - tabs.add('All'); - - const commercial = modelOptions['Commercially Hosted']; - if (commercial && typeof commercial === 'object') { - Object.keys(commercial).forEach((key) => tabs.add(key)); - } - - ['Locally Hosted', 'Embedded', 'File Uploads'].forEach((key) => { - if (modelOptions[key]) { - tabs.add(key); - } - }); - - return Array.from(tabs); - }; - - const tabLabels = getTabLabels(); - - const getAllModels = () => { - let allModels: any[] = []; - - const commercial = modelOptions['Commercially Hosted']; - if (commercial && typeof commercial === 'object') { - Object.values(commercial).forEach((models: any) => { - allModels = allModels.concat(models); - }); - } - - ['Locally Hosted', 'Embedded', 'File Uploads'].forEach((key) => { - const models = modelOptions[key]; - if (Array.isArray(models)) { - allModels = allModels.concat(models); - } - }); - - return allModels; - }; - - const getModelsForTab = (tab: string) => { - if (tab === 'All') return getAllModels(); - - const commercial = modelOptions['Commercially Hosted']; - if (commercial && commercial[tab]) { - return commercial[tab]; - } - - if (modelOptions[tab]) { - return modelOptions[tab]; - } - - return []; - }; - - useEffect(() => { - const paramedStep = { - title: '', - description: '', - data: '', - }; - - // Based on where you came from in application, we can skip first step in connection process - switch (type.toLowerCase()) { - case '': - break; - case 'database': - paramedStep.title = 'Connect to Database'; - paramedStep.description = - "In today's data-driven world, the ability to effortlessly establish connections with various database types is pivotal for unlocking the full potential of your applications and analytical processes. Whether you're a developer, data analyst, or business professional, this page serves as your gateway to understanding the array of database options at your disposal."; - paramedStep.data = 'DATABASE'; - - setSteps([...steps, paramedStep], steps.length + 1); - break; - case 'model': - paramedStep.title = 'Connect to Model'; - paramedStep.description = - "In an era fueled by information, the seamless interlinking of various databases stands as a cornerstone for unlocking the untapped potential of LLM applications. Whether you're a seasoned AI practitioner, a language aficionado, or an industry visionary, this page serves as your guiding star to grasp the spectrum of database options available within the LLM landscape."; - paramedStep.data = 'MODEL'; - - setSteps([...steps, paramedStep], steps.length + 1); - break; - case 'vector': - paramedStep.title = 'Connect to Vector Database'; - paramedStep.description = - "In an era fueled by information, the seamless interlinking of various databases stands as a cornerstone for unlocking the untapped potential of LLM applications. Whether you're a seasoned AI practitioner, a language aficionado, or an industry visionary, this page serves as your guiding star to grasp the spectrum of database options available within the LLM landscape."; - paramedStep.data = 'VECTOR'; - - setSteps([...steps, paramedStep], steps.length + 1); - break; - case 'function': - paramedStep.title = 'Connect to Function'; - paramedStep.description = - "In an era fueled by information, the seamless interlinking of various databases stands as a cornerstone for unlocking the untapped potential of LLM applications. Whether you're a seasoned AI practitioner, a language aficionado, or an industry visionary, this page serves as your guiding star to grasp the spectrum of database options available within the LLM landscape."; - paramedStep.data = 'FUNCTION'; - - setSteps([...steps, paramedStep], steps.length + 1); - break; - case 'storage': - paramedStep.title = 'Connect to Storage'; - paramedStep.description = - "In an era fueled by information, the seamless interlinking of various databases stands as a cornerstone for unlocking the untapped potential of LLM applications. Whether you're a seasoned AI practitioner, a language aficionado, or an industry visionary, this page serves as your guiding star to grasp the spectrum of database options available within the LLM landscape."; - paramedStep.data = 'STORAGE'; - - setSteps([...steps, paramedStep], steps.length + 1); - break; - } - }, [type]); - - useEffect(() => { - const scrollIntoView = () => { - if (scrollToTopRef.current) { - scrollToTopRef.current.scrollIntoView({ - behavior: 'smooth', - block: 'center', - inline: 'start', - }); - } - }; - - const delayScroll = () => { - setTimeout(scrollIntoView, 100); // 5000 milliseconds = 5 seconds - }; - - delayScroll(); // Trigger the delayed scroll when the component mounts - }, [steps.length]); - - useEffect(() => { - setUniqueIdsOnConnectionOptions(); - }, []); - - const setUniqueIdsOnConnectionOptions = async () => { - setIsLoading(true); - await assignUniqueIds(CONNECTION_OPTIONS); - setIsLoading(false); - - setConnectionOptions(CONNECTION_OPTIONS); - }; - - /** - * Assigns unique IDs for each connection type - * @param obj - * @param prefix - */ - function assignUniqueIds(obj, prefix = '') { - if (Array.isArray(obj)) { - // If it's an array, iterate through its elements - for (let i = 0; i < obj.length; i++) { - assignUniqueIds(obj[i], `${prefix}[${i}]`); - } - } else if (typeof obj === 'object' && obj !== null) { - // If it's an object, iterate through its properties - for (const key in obj) { - // if (obj.hasOwnProperty(key)) { - const currentPrefix = prefix ? `${prefix}.${key}` : key; - - // Assign unique ID to the 'name', 'disable', 'fields' properties - if (key === 'name' || key === 'disable' || key === 'fields') { - obj[`id`] = `${currentPrefix}${obj['name']}`; - } - - // Recursively traverse nested objects - assignUniqueIds(obj[key], currentPrefix); - // } - } - } - } - - const renderModelsGrid = (models) => ( - - {models - .filter((m) => - m.name.toLowerCase().includes(search.toLowerCase()), - ) - .map((model, idx) => ( - - - - ))} - - ); - - const mapEngineOptions = () => { - const entries = Object.values(connectionOptions[steps[0].data]); - - // Change in structure, quick 20 minute ask from Leadership - if (Array.isArray(entries[0])) { - return ( - - {Object.entries(connectionOptions[steps[0].data]).map( - (kv: [string, any[]], i) => { - return ( - - - {kv[0]} - - - - - {kv[1].map((stage, idx) => { - if ( - stage.name - .toLowerCase() - .includes( - search.toLowerCase(), - ) - ) { - return ( - - { - if ( - !stage.disable - ) { - setSteps( - [ - ...steps, - { - id: `${kv[0]}.${stage.name}`, - title: stage.name, - description: `Fill out ${ - stage.name - } details in order to add ${steps[0].data.toLowerCase()} to catalog`, - data: stage.fields, - }, - ], - steps.length + - 1, - ); - } - }} - > - - - - { - stage.name - } - - - - - ); - } - })} - - - - ); - }, - )} - - ); - } else { - const e = Object.entries(connectionOptions[steps[0].data]); - e.shift(); - - return ( - - setSelectedTab(newValue)} - variant="scrollable" - sx={{ mt: 2, borderBottom: '2px solid #E0E0E0' }} - > - {tabLabels.map((label, i) => ( - - ))} - - - {renderModelsGrid( - getModelsForTab(tabLabels[selectedTab]), - )} - - - ); - } - }; - return ( - - - {steps.length ? ( - - { - setSteps([], -1); - if (window.history.length > 1) { - navigate(-1); - } else { - navigate('/'); - } - }} - > - {name} Catalog - - {steps.map((step, i) => { - return ( - { - const newSteps = []; - for (let j = 0; j < i + 1; j++) { - newSteps.push(steps[j]); - } - - setSteps(newSteps, i + 1); - }} - > - {step.title} - - ); - })} - - ) : ( -
 
- )} - - {steps.length && steps[steps.length - 1].title} - - - {steps.length && steps[steps.length - 1].description} - -
- - {/* Search Second Step: TODO - only one search */} - {steps.length === 1 && - steps[0].title !== 'Copy Database' && - steps[0].title !== 'Upload Database' && ( - - { - setSearch(e.target.value); - }} - fullWidth - /> - - )} - - {/* When Step changes scroll top into view */} -
-   -
- - {/* Step 2a: Selection for options that require more info */} - {/* This is shared between vector, function, database, model and storage */} - {steps.length === 1 && - steps[0].title !== 'Copy Database' && - steps[0].title !== 'Upload Database' && - !isLoading && - mapEngineOptions()} - - {/* Step 2b: Show Form for Copy and Upload ( this is only a 2-step process) */} - {steps.length === 1 && - (steps[0].title === 'Copy Database' || - steps[0].title === 'Upload Database') && ( - - {steps[0].title === 'Copy Database' ? ( - - ) : ( - - )} - - )} - - {/* Step 3: Will be the form to capture specific engine connection details */} - {steps.length === 2 && } - - {/* Step 4: If there is a step in the process after inputting connection details: metamodel for example */} - {steps.length === 3 && } -
- -
- ); + const { steps, activeStep, setSteps, setIsLoading, isLoading } = + useStepper(); + + const navigate = useNavigate(); + + const [importSearch, setImportSearch] = React.useState(""); + const [search, setSearch] = React.useState(""); + + const [connectionOptions, setConnectionOptions] = + React.useState(CONNECTION_OPTIONS); + const [selectedTab, setSelectedTab] = React.useState(0); + + const modelOptions = connectionOptions.MODEL; + + const scrollToTopRef = useRef(null); + + const isModelPage = steps.length > 0 && steps[0].data === "MODEL"; + + const ModelCard = ({ model, setSteps, steps }) => { + const textRef = useRef(null); + const [isTruncated, setIsTruncated] = React.useState(false); + + useEffect(() => { + const el = textRef.current; + if (el) { + setIsTruncated(el.scrollWidth > el.clientWidth); + } + }, [model.name]); + + const cardContent = ( + { + if (!model.disable) { + setSteps( + [ + ...steps, + { + id: model.id, + title: model.name, + description: `Fill out ${ + model.name + } details in order to add ${steps[0].data.toLowerCase()} to catalog`, + data: model.fields, + }, + ], + steps.length + 1, + ); + } + }} + > + + {model.disable ? ( + + + + Coming Soon + + + ) : ( + + )} + + + {model.name} + + + + ); + + return isTruncated ? ( + + {cardContent} + + ) : ( + cardContent + ); + }; + + const getTabLabels = () => { + const tabs = new Set(); + tabs.add("All"); + + const commercial = modelOptions["Commercially Hosted"]; + if (commercial && typeof commercial === "object") { + Object.keys(commercial).forEach((key) => tabs.add(key)); + } + + ["Locally Hosted", "Embedded", "File Uploads"].forEach((key) => { + if (modelOptions[key]) { + tabs.add(key); + } + }); + + return Array.from(tabs); + }; + + const tabLabels = getTabLabels(); + + const getAllModels = () => { + let allModels: any[] = []; + + const commercial = modelOptions["Commercially Hosted"]; + if (commercial && typeof commercial === "object") { + Object.values(commercial).forEach((models: any) => { + allModels = allModels.concat(models); + }); + } + + ["Locally Hosted", "Embedded", "File Uploads"].forEach((key) => { + const models = modelOptions[key]; + if (Array.isArray(models)) { + allModels = allModels.concat(models); + } + }); + + return allModels; + }; + + const getModelsForTab = (tab: string) => { + if (tab === "All") return getAllModels(); + + const commercial = modelOptions["Commercially Hosted"]; + if (commercial && commercial[tab]) { + return commercial[tab]; + } + + if (modelOptions[tab]) { + return modelOptions[tab]; + } + + return []; + }; + + useEffect(() => { + const paramedStep = { + title: "", + description: "", + data: "", + }; + + // Based on where you came from in application, we can skip first step in connection process + switch (type.toLowerCase()) { + case "": + break; + case "database": + paramedStep.title = "Connect to Database"; + paramedStep.description = + "In today's data-driven world, the ability to effortlessly establish connections with various database types is pivotal for unlocking the full potential of your applications and analytical processes. Whether you're a developer, data analyst, or business professional, this page serves as your gateway to understanding the array of database options at your disposal."; + paramedStep.data = "DATABASE"; + + setSteps([...steps, paramedStep], steps.length + 1); + break; + case "model": + paramedStep.title = "Connect to Model"; + paramedStep.description = + "In an era fueled by information, the seamless interlinking of various databases stands as a cornerstone for unlocking the untapped potential of LLM applications. Whether you're a seasoned AI practitioner, a language aficionado, or an industry visionary, this page serves as your guiding star to grasp the spectrum of database options available within the LLM landscape."; + paramedStep.data = "MODEL"; + + setSteps([...steps, paramedStep], steps.length + 1); + break; + case "vector": + paramedStep.title = "Connect to Vector Database"; + paramedStep.description = + "In an era fueled by information, the seamless interlinking of various databases stands as a cornerstone for unlocking the untapped potential of LLM applications. Whether you're a seasoned AI practitioner, a language aficionado, or an industry visionary, this page serves as your guiding star to grasp the spectrum of database options available within the LLM landscape."; + paramedStep.data = "VECTOR"; + + setSteps([...steps, paramedStep], steps.length + 1); + break; + case "function": + paramedStep.title = "Connect to Function"; + paramedStep.description = + "In an era fueled by information, the seamless interlinking of various databases stands as a cornerstone for unlocking the untapped potential of LLM applications. Whether you're a seasoned AI practitioner, a language aficionado, or an industry visionary, this page serves as your guiding star to grasp the spectrum of database options available within the LLM landscape."; + paramedStep.data = "FUNCTION"; + + setSteps([...steps, paramedStep], steps.length + 1); + break; + case "storage": + paramedStep.title = "Connect to Storage"; + paramedStep.description = + "In an era fueled by information, the seamless interlinking of various databases stands as a cornerstone for unlocking the untapped potential of LLM applications. Whether you're a seasoned AI practitioner, a language aficionado, or an industry visionary, this page serves as your guiding star to grasp the spectrum of database options available within the LLM landscape."; + paramedStep.data = "STORAGE"; + + setSteps([...steps, paramedStep], steps.length + 1); + break; + } + }, [type]); + + useEffect(() => { + const scrollIntoView = () => { + if (scrollToTopRef.current) { + scrollToTopRef.current.scrollIntoView({ + behavior: "smooth", + block: "center", + inline: "start", + }); + } + }; + + const delayScroll = () => { + setTimeout(scrollIntoView, 100); // 5000 milliseconds = 5 seconds + }; + + delayScroll(); // Trigger the delayed scroll when the component mounts + }, [steps.length]); + + useEffect(() => { + setUniqueIdsOnConnectionOptions(); + }, []); + + const setUniqueIdsOnConnectionOptions = async () => { + setIsLoading(true); + await assignUniqueIds(CONNECTION_OPTIONS); + setIsLoading(false); + + setConnectionOptions(CONNECTION_OPTIONS); + }; + + /** + * Assigns unique IDs for each connection type + * @param obj + * @param prefix + */ + function assignUniqueIds(obj, prefix = "") { + if (Array.isArray(obj)) { + // If it's an array, iterate through its elements + for (let i = 0; i < obj.length; i++) { + assignUniqueIds(obj[i], `${prefix}[${i}]`); + } + } else if (typeof obj === "object" && obj !== null) { + // If it's an object, iterate through its properties + for (const key in obj) { + // if (obj.hasOwnProperty(key)) { + const currentPrefix = prefix ? `${prefix}.${key}` : key; + + // Assign unique ID to the 'name', 'disable', 'fields' properties + if (key === "name" || key === "disable" || key === "fields") { + obj[`id`] = `${currentPrefix}${obj["name"]}`; + } + + // Recursively traverse nested objects + assignUniqueIds(obj[key], currentPrefix); + // } + } + } + } + + const renderModelsGrid = (models) => ( + + {models + .filter((m) => + m.name.toLowerCase().includes(search.toLowerCase()), + ) + .map((model, idx) => ( + + + + ))} + + ); + + const mapEngineOptions = () => { + const entries = Object.values(connectionOptions[steps[0].data]); + + // Change in structure, quick 20 minute ask from Leadership + if (Array.isArray(entries[0])) { + return ( + + {Object.entries(connectionOptions[steps[0].data]).map( + (kv: [string, any[]], i) => { + return ( + + + {kv[0]} + + + + + {kv[1].map((stage, idx) => { + if ( + stage.name + .toLowerCase() + .includes( + search.toLowerCase(), + ) + ) { + return ( + + { + if ( + !stage.disable + ) { + setSteps( + [ + ...steps, + { + id: `${kv[0]}.${stage.name}`, + title: stage.name, + description: `Fill out ${ + stage.name + } details in order to add ${steps[0].data.toLowerCase()} to catalog`, + data: stage.fields, + }, + ], + steps.length + + 1, + ); + } + }} + > + + + + { + stage.name + } + + + + + ); + } + })} + + + + ); + }, + )} + + ); + } else { + const e = Object.entries(connectionOptions[steps[0].data]); + e.shift(); + + return ( + + setSelectedTab(newValue)} + variant="scrollable" + sx={{ mt: 2, borderBottom: "2px solid #E0E0E0" }} + > + {tabLabels.map((label, i) => ( + + ))} + + + {renderModelsGrid( + getModelsForTab(tabLabels[selectedTab]), + )} + + + ); + } + }; + return ( + + + {steps.length ? ( + + { + setSteps([], -1); + if (window.history.length > 1) { + navigate(-1); + } else { + navigate("/"); + } + }} + > + {name} Catalog + + {steps.map((step, i) => { + return ( + { + const newSteps = []; + for (let j = 0; j < i + 1; j++) { + newSteps.push(steps[j]); + } + + setSteps(newSteps, i + 1); + }} + > + {step.title} + + ); + })} + + ) : ( +
 
+ )} + + {steps.length && steps[steps.length - 1].title} + + + {steps.length && steps[steps.length - 1].description} + +
+ + {/* Search Second Step: TODO - only one search */} + {steps.length === 1 && + steps[0].title !== "Copy Database" && + steps[0].title !== "Upload Database" && ( + + { + setSearch(e.target.value); + }} + fullWidth + /> + + )} + + {/* When Step changes scroll top into view */} +
+   +
+ + {/* Step 2a: Selection for options that require more info */} + {/* This is shared between vector, function, database, model and storage */} + {steps.length === 1 && + steps[0].title !== "Copy Database" && + steps[0].title !== "Upload Database" && + !isLoading && + mapEngineOptions()} + + {/* Step 2b: Show Form for Copy and Upload ( this is only a 2-step process) */} + {steps.length === 1 && + (steps[0].title === "Copy Database" || + steps[0].title === "Upload Database") && ( + + {steps[0].title === "Copy Database" ? ( + + ) : ( + + )} + + )} + + {/* Step 3: Will be the form to capture specific engine connection details */} + {steps.length === 2 && } + + {/* Step 4: If there is a step in the process after inputting connection details: metamodel for example */} + {steps.length === 3 && } +
+ +
+ ); }; diff --git a/packages/client/src/pages/import/import.constants.ts b/packages/client/src/pages/import/import.constants.ts index 6fefc81b3a..6fca721107 100644 --- a/packages/client/src/pages/import/import.constants.ts +++ b/packages/client/src/pages/import/import.constants.ts @@ -1,15562 +1,15565 @@ //Drag and Drop Data -import CSV from '@/assets/img/CSV.svg'; -import EXCEL from '@/assets/img/EXCEL.png'; -import TSV from '@/assets/img/TSV.svg'; -import SQLITE from '@/assets/img/SQLITE.png'; -import H2_DB from '@/assets/img/H2_DB.png'; -import NEO4J from '@/assets/img/NEO4J.png'; -import TINKER from '@/assets/img/TINKER.png'; -import ZIP from '@/assets/img/ZIP.png'; -//Connect to an External Database -import ASTER from '@/assets/img/ASTER.png'; -import ATHENA from '@/assets/img/ATHENA.png'; -import BIGQUERY from '@/assets/img/BIGQUERY.png'; -import CASSANDRA from '@/assets/img/CASSANDRA.png'; -import CLICKHOUSE from '@/assets/img/CLICKHOUSE.png'; -import DATABRICKS from '@/assets/img/DATABRICKS.png'; -import DATASTAX from '@/assets/img/DATASTAX.png'; -import DB2 from '@/assets/img/DB2.png'; -import DERBY from '@/assets/img/DERBY.png'; -import ELASTIC_SEARCH from '@/assets/img/ELASTIC_SEARCH.svg'; -import HIVE from '@/assets/img/HIVE.jpg'; -import IMPALA from '@/assets/img/IMPALA.png'; -import MARIA_DB from '@/assets/img/MARIA_DB.png'; -import MYSQL from '@/assets/img/MYSQL.png'; -import OPEN_SEARCH from '@/assets/img/OPEN_SEARCH.png'; -import ORACLE from '@/assets/img/ORACLE.png'; -import PHOENIX from '@/assets/img/PHOENIX.png'; -import POSTGRES from '@/assets/img/POSTGRES.png'; -import REDSHIFT from '@/assets/img/REDSHIFT.png'; -import SAP_HANA from '@/assets/img/SAP_HANA.png'; -import SEMOSS from '@/assets/img/SEMOSS_BLUE_LOGO.svg'; -import SNOWFLAKE from '@/assets/img/SNOWFLAKE.png'; -import SQL_SERVER from '@/assets/img/SQL_SERVER.png'; -import TERADATA from '@/assets/img/TERADATA.png'; -import TIBCO from '@/assets/img/TIBCO.png'; -import TRINO from '@/assets/img/TRINO.jpg'; + //Add Storage -import AMAZON_S3 from '@/assets/img/Amazon_S3.png'; -import AZURE_BLOB from '@/assets/img/AZURE_BLOB.png'; -import AZURE_SPEECH_TO_TEXT from '@/assets/img/AZURE_SPEECH_TO_TEXT.png'; -import CEPH from '@/assets/img/CEPH.png'; -import DREAMHOST from '@/assets/img/DREAMHOST.png'; -import DROPBOX from '@/assets/img/dropbox.png'; -import GOOGLE_CLOUD from '@/assets/img/GOOGLE_CLOUD_STORAGE.png'; -import GOOGLE_DRIVE from '@/assets/img/GOOGLE_DRIVE.png'; -import LOCAL_FILE_SYSTEM from '@/assets/img/LOCAL_FILE_SYSTEM.png'; -import MINIO from '@/assets/img/MINIO.png'; -import NETWORK_FILE_SYSTEM from '@/assets/img/NETWORK_FILE_SYSTEM.png'; -import ONEDRIVE from '@/assets/img/ONEDRIVE.png'; -import SFTP from '@/assets/img/SFTP.png'; -//Commercial Models -import OPEN_AI from '@/assets/img/OPEN_AI.png'; -import AZURE_OPEN_AI from '@/assets/img/OPEN_AI.png'; -import CLAUDE from '@/assets/img/CLAUDE_AI.png'; -import VERTEX from '@/assets/img/VERTEX_AI.png'; -import Amazon_Titan from '@/assets/img/Amazon_Titan.png'; +import AMAZON_S3 from "@/assets/img/Amazon_S3.png"; +import Amazon_Titan from "@/assets/img/Amazon_Titan.png"; +//Connect to an External Database +import ASTER from "@/assets/img/ASTER.png"; +import ATHENA from "@/assets/img/ATHENA.png"; +import AWS_COMPREHEND from "@/assets/img/AWS_COMPREHEND.png"; +import AWS_POLLY from "@/assets/img/AWS_POLLY.png"; +import AWS_TEXTRACT from "@/assets/img/AWS_TEXTRACT.png"; +import AWS_TRANSCRIBE from "@/assets/img/AWS_TRANSCRIBE.png"; +import AZURE_BLOB from "@/assets/img/AZURE_BLOB.png"; +import AZURE_SPEECH_TO_TEXT from "@/assets/img/AZURE_SPEECH_TO_TEXT.png"; +import BERT from "@/assets/img/BERT.png"; +import BIGQUERY from "@/assets/img/BIGQUERY.png"; +import BLOCKS from "@/assets/img/Blocks.svg"; +import BLOCKS_SELECTED from "@/assets/img/Blocks_Selected.svg"; //Local Models -import BRAIN from '@/assets/img/BRAIN.png'; -import META from '@/assets/img/META.png'; -import FALCON from '@/assets/img/FALCON_AI.png'; -import VICUNA from '@/assets/img/VICUNA.jpg'; -import MOSAIC from '@/assets/img/MOSAIC.png'; -import DOLLY from '@/assets/img/DOLLY_AI.jpg'; -import FLAN from '@/assets/img/FLAN.jpg'; -import BERT from '@/assets/img/BERT.png'; -import ELEUTHER from '@/assets/img/ELEUTHER_AI.png'; -import NEMO from '@/assets/img/NEMO.png'; -import GOOGLE from '@/assets/img/google.png'; +import BRAIN from "@/assets/img/BRAIN.png"; +import CASSANDRA from "@/assets/img/CASSANDRA.png"; +import CEPH from "@/assets/img/CEPH.png"; +import CHROMADB from "@/assets/img/CHROMADB.png"; +import CLAUDE from "@/assets/img/CLAUDE_AI.png"; +import CLICKHOUSE from "@/assets/img/CLICKHOUSE.png"; +import CSV from "@/assets/img/CSV.svg"; +import DATABRICKS from "@/assets/img/DATABRICKS.png"; +import DATASTAX from "@/assets/img/DATASTAX.png"; +import DB2 from "@/assets/img/DB2.png"; +import DERBY from "@/assets/img/DERBY.png"; +import DOLLY from "@/assets/img/DOLLY_AI.jpg"; +import DREAMHOST from "@/assets/img/DREAMHOST.png"; +import DROPBOX from "@/assets/img/dropbox.png"; +import ELASTIC_SEARCH from "@/assets/img/ELASTIC_SEARCH.svg"; +import ELEUTHER from "@/assets/img/ELEUTHER_AI.png"; +import EXCEL from "@/assets/img/EXCEL.png"; +import FALCON from "@/assets/img/FALCON_AI.png"; +import FILES from "@/assets/img/Files.svg"; +import FILES_SELECTED from "@/assets/img/Files_Selected.svg"; +import FLAN from "@/assets/img/FLAN.jpg"; +import GOOGLE_CLOUD from "@/assets/img/GOOGLE_CLOUD_STORAGE.png"; +import GOOGLE_DRIVE from "@/assets/img/GOOGLE_DRIVE.png"; +import GOOGLE_OCR from "@/assets/img/GOOGLE_OCR.png"; +import GOOGLE_SPEECH_TO_TEXT from "@/assets/img/GOOGLE_SPEECH_TO_TEXT.png"; +import GOOGLE from "@/assets/img/google.png"; +import H2_DB from "@/assets/img/H2_DB.png"; +import HIVE from "@/assets/img/HIVE.jpg"; +import IMPALA from "@/assets/img/IMPALA.png"; +import LAYERS from "@/assets/img/Layers.svg"; +import LAYERS_SELECTED from "@/assets/img/Layers_Selected.svg"; +import LOCAL_FILE_SYSTEM from "@/assets/img/LOCAL_FILE_SYSTEM.png"; +import MARIA_DB from "@/assets/img/MARIA_DB.png"; +import META from "@/assets/img/META.png"; +import MILVUS from "@/assets/img/MILVUS.png"; +import MINIO from "@/assets/img/MINIO.png"; +import MOSAIC from "@/assets/img/MOSAIC.png"; +import MYSQL from "@/assets/img/MYSQL.png"; +import NEMO from "@/assets/img/NEMO.png"; +import NEO4J from "@/assets/img/NEO4J.png"; +import NETWORK_FILE_SYSTEM from "@/assets/img/NETWORK_FILE_SYSTEM.png"; +import NOTEBOOK from "@/assets/img/Notebook.svg"; +import NOTEBOOK_SELECTED from "@/assets/img/Notebook_Selected.svg"; +import ONEDRIVE from "@/assets/img/ONEDRIVE.png"; +//Commercial Models +import OPEN_AI from "@/assets/img/OPEN_AI.png"; +import AZURE_OPEN_AI from "@/assets/img/OPEN_AI.png"; +import OPEN_SEARCH from "@/assets/img/OPEN_SEARCH.png"; +import ORACLE from "@/assets/img/ORACLE.png"; //Embedded Models -import ORCA from '@/assets/img/ORCA.png'; -import STABILITY_AI from '@/assets/img/STABILITY_AI.png'; -import REPLIT from '@/assets/img/REPLIT_CODE.png'; +import ORCA from "@/assets/img/ORCA.png"; +import PHOENIX from "@/assets/img/PHOENIX.png"; +import PINECONE from "@/assets/img/PINECONE.png"; +import POSTGRES from "@/assets/img/POSTGRES.png"; +import REDSHIFT from "@/assets/img/REDSHIFT.png"; +import REPLIT from "@/assets/img/REPLIT_CODE.png"; // Functions -import RESTAPI from '@/assets/img/rest-api.svg'; -import AWS_COMPREHEND from '@/assets/img/AWS_COMPREHEND.png'; -import AWS_POLLY from '@/assets/img/AWS_POLLY.png'; -import GOOGLE_SPEECH_TO_TEXT from '@/assets/img/GOOGLE_SPEECH_TO_TEXT.png'; -import GOOGLE_OCR from '@/assets/img/GOOGLE_OCR.png'; -import AWS_TEXTRACT from '@/assets/img/AWS_TEXTRACT.png'; -import AWS_TRANSCRIBE from '@/assets/img/AWS_TRANSCRIBE.png'; -//Vector -import MICROSOFT from '@/assets/loginProviders/microsoft.png'; -import CHROMADB from '@/assets/img/CHROMADB.png'; -import MILVUS from '@/assets/img/MILVUS.png'; -import PINECONE from '@/assets/img/PINECONE.png'; -import WEVIATE from '@/assets/img/WEVIATE.png'; +import RESTAPI from "@/assets/img/rest-api.svg"; +import SAP_HANA from "@/assets/img/SAP_HANA.png"; +import SEMOSS from "@/assets/img/SEMOSS_BLUE_LOGO.svg"; +import SETTINGS_SELECTED from "@/assets/img/Setting_Selected.svg"; //Sidebar icons -import SETTINGS from '@/assets/img/Settings.svg'; -import NOTEBOOK from '@/assets/img/Notebook.svg'; -import FILES from '@/assets/img/Files.svg'; -import VARIABLES from '@/assets/img/Variable.svg'; -import BLOCKS from '@/assets/img/Blocks.svg'; -import LAYERS from '@/assets/img/Layers.svg'; -import SETTINGS_SELECTED from '@/assets/img/Setting_Selected.svg'; -import NOTEBOOK_SELECTED from '@/assets/img/Notebook_Selected.svg'; -import FILES_SELECTED from '@/assets/img/Files_Selected.svg'; -import VARIABLES_SELECTED from '@/assets/img/Variables_Selected.svg'; -import BLOCKS_SELECTED from '@/assets/img/Blocks_Selected.svg'; -import LAYERS_SELECTED from '@/assets/img/Layers_Selected.svg'; +import SETTINGS from "@/assets/img/Settings.svg"; +import SFTP from "@/assets/img/SFTP.png"; +import SNOWFLAKE from "@/assets/img/SNOWFLAKE.png"; +import SQL_SERVER from "@/assets/img/SQL_SERVER.png"; +import SQLITE from "@/assets/img/SQLITE.png"; +import STABILITY_AI from "@/assets/img/STABILITY_AI.png"; +import TERADATA from "@/assets/img/TERADATA.png"; +import TIBCO from "@/assets/img/TIBCO.png"; +import TINKER from "@/assets/img/TINKER.png"; +import TRINO from "@/assets/img/TRINO.jpg"; +import TSV from "@/assets/img/TSV.svg"; +import VARIABLES from "@/assets/img/Variable.svg"; +import VARIABLES_SELECTED from "@/assets/img/Variables_Selected.svg"; +import VERTEX from "@/assets/img/VERTEX_AI.png"; +import VICUNA from "@/assets/img/VICUNA.jpg"; +import WEVIATE from "@/assets/img/WEVIATE.png"; +import ZIP from "@/assets/img/ZIP.png"; +//Vector +import MICROSOFT from "@/assets/loginProviders/microsoft.png"; // TODO: Get rid of this and throw it into Connection Options export const stepsOne = [ - { - name: 'Connect to Database', - description: - "In today's data-driven world, the ability to effortlessly establish connections with various database types is pivotal for unlocking the full potential of your applications and analytical processes. Whether you're a developer, data analyst, or business professional, this page serves as your gateway to understanding the array of database options at your disposal.", - disabled: false, - data: 'DATABASE', - }, - { - name: 'Copy Database', - description: '', - disabled: true, - data: 'COPY_DATABASE', // DOES NOT MATTER AT THE MOMENT, Tie this into one DS - }, - { - name: 'Build Database', - description: '', - disabled: true, - data: 'BUILD_DATABASE', // DOES NOT MATTER AT THE MOMENT, Tie this into one DS - }, - { - name: 'Connect to Model', - description: - "In an era fueled by information, the seamless interlinking of various databases stands as a cornerstone for unlocking the untapped potential of LLM applications. Whether you're a seasoned AI practitioner, a language aficionado, or an industry visionary, this page serves as your guiding star to grasp the spectrum of database options available within the LLM landscape.", - disabled: false, - data: 'MODEL', - }, - { - name: 'Connect to Storage', - description: '', - disabled: false, - data: 'STORAGE', - }, - { - name: 'Connect to Vector Database', - description: '', - disabled: false, - data: 'VECTOR', - }, - { - name: 'Connect to Function', - description: - "In an era fueled by information, the seamless interlinking of various databases stands as a cornerstone for unlocking the untapped potential of LLM applications. Whether you're a seasoned AI practitioner, a language aficionado, or an industry visionary, this page serves as your guiding star to grasp the spectrum of database options available within the LLM landscape.", - disabled: false, - data: 'FUNCTION', - }, + { + name: "Connect to Database", + description: + "In today's data-driven world, the ability to effortlessly establish connections with various database types is pivotal for unlocking the full potential of your applications and analytical processes. Whether you're a developer, data analyst, or business professional, this page serves as your gateway to understanding the array of database options at your disposal.", + disabled: false, + data: "DATABASE", + }, + { + name: "Copy Database", + description: "", + disabled: true, + data: "COPY_DATABASE", // DOES NOT MATTER AT THE MOMENT, Tie this into one DS + }, + { + name: "Build Database", + description: "", + disabled: true, + data: "BUILD_DATABASE", // DOES NOT MATTER AT THE MOMENT, Tie this into one DS + }, + { + name: "Connect to Model", + description: + "In an era fueled by information, the seamless interlinking of various databases stands as a cornerstone for unlocking the untapped potential of LLM applications. Whether you're a seasoned AI practitioner, a language aficionado, or an industry visionary, this page serves as your guiding star to grasp the spectrum of database options available within the LLM landscape.", + disabled: false, + data: "MODEL", + }, + { + name: "Connect to Storage", + description: "", + disabled: false, + data: "STORAGE", + }, + { + name: "Connect to Vector Database", + description: "", + disabled: false, + data: "VECTOR", + }, + { + name: "Connect to Function", + description: + "In an era fueled by information, the seamless interlinking of various databases stands as a cornerstone for unlocking the untapped potential of LLM applications. Whether you're a seasoned AI practitioner, a language aficionado, or an industry visionary, this page serves as your guiding star to grasp the spectrum of database options available within the LLM landscape.", + disabled: false, + data: "FUNCTION", + }, ]; export type EngineFields = { - name: string; - fields: { - fieldName: string; - label: string; - defaultValue: string; - options: { - component: string; - options?: { value: string; display: string }[]; - pixel?: string; // Pixel to populate options for select - }; - disabled: boolean; - rules: Record; // react hook form - pixel?: string; // used to populate default value - }[]; + name: string; + fields: { + fieldName: string; + label: string; + defaultValue: string; + options: { + component: string; + options?: { value: string; display: string }[]; + pixel?: string; // Pixel to populate options for select + }; + disabled: boolean; + rules: Record; // react hook form + pixel?: string; // used to populate default value + }[]; }[]; // TODO: Type out Connection Options export const CONNECTION_OPTIONS = { - MODEL: { - 'Commercially Hosted': { - OpenAI: [ - { - name: 'GPT-3.5', - disable: false, - icon: OPEN_AI, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: 'OPEN_AI', - options: { - component: 'select', - options: [ - { - display: 'Open AI', - value: 'OPEN_AI', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'OPEN_AI_KEY', - label: 'Open AI Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'gpt-3.5-turbo', - options: { - component: 'select', - options: [ - { - display: 'gpt-3.5-turbo', - value: 'gpt-3.5-turbo', - }, - { - display: 'gpt-4-32k', - value: 'gpt-4-32k', - }, - ], - }, - disabled: true, - hidden: true, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: - "import genai_client;${VAR_NAME} = genai_client.OpenAiClient(model_name = '${MODEL}', api_key = '${OPEN_AI_KEY}', chat_type = '${CHAT_TYPE}')", - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'GPT-4', - disable: false, - icon: OPEN_AI, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: 'OPEN_AI', - options: { - component: 'select', - options: [ - { - display: 'Open AI', - value: 'OPEN_AI', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'OPEN_AI_KEY', - label: 'Open AI Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'gpt-4-32k', - options: { - component: 'select', - options: [ - { - display: 'gpt-4-32k', - value: 'gpt-4-32k', - }, - ], - }, - disabled: true, - hidden: true, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: - "import genai_client;${VAR_NAME} = genai_client.OpenAiClient(model_name = '${MODEL}', api_key = '${OPEN_AI_KEY}', chat_type = '${CHAT_TYPE}')", - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'Text-Davinci', - disable: false, - icon: OPEN_AI, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: 'OPEN_AI', - options: { - component: 'select', - options: [ - { - display: 'Open AI', - value: 'OPEN_AI', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'OPEN_AI_KEY', - label: 'Open AI Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'text-davinci', - options: { - component: 'select', - options: [ - { - display: 'text-davinci', - value: 'text-davinci', - }, - ], - }, - disabled: true, - hidden: true, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: - "from genai_client import OpenAiEmbedder;${VAR_NAME} = OpenAiEmbedder(model_name = '${MODEL}', api_key = '${OPEN_AI_KEY}')", - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'DALL E', - disable: false, - icon: OPEN_AI, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: 'OPEN_AI', - options: { - component: 'select', - options: [ - { - display: 'Open AI', - value: 'OPEN_AI', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'OPEN_AI_KEY', - label: 'Open AI Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'dall e', - options: { - component: 'select', - options: [ - { - display: 'dall e', - value: 'dall e', - }, - ], - }, - disabled: true, - hidden: true, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - ], - Azure: [ - { - name: 'Azure Open AI', - disable: false, - icon: AZURE_OPEN_AI, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: 'OPEN_AI', - options: { - component: 'select', - options: [ - { - display: 'Open AI', - value: 'OPEN_AI', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'OPEN_AI_KEY', - label: 'Azure Open AI Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL', - label: 'Deployment Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Azure Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: - "import genai_client;${VAR_NAME} = genai_client.AzureOpenAiClient(api_key = '${OPEN_AI_KEY}', endpoint = '${ENDPOINT}', model_name = '${MODEL}', chat_type = '${CHAT_TYPE}')", - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'Azure Open AI ADA Embedder', - disable: false, - icon: AZURE_OPEN_AI, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( [VALUE] ) ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'TAG', - label: 'Tag', - defaultValue: 'embeddings', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: 'OPEN_AI', - options: { - component: 'select', - options: [ - { - display: 'Open AI', - value: 'OPEN_AI', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'text-embedding-ada-002', - options: { - component: 'select', - options: [ - { - display: 'text-embedding-ada-002', - value: 'text-embedding-ada-002', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'OPEN_AI_KEY', - label: 'Azure Open AI API Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Azure Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'API_VERSION', - label: 'API version', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: - "from genai_client import AzureOpenAiEmbedder;${VAR_NAME} = AzureOpenAiEmbedder(model_name = '${MODEL}', endpoint = '${ENDPOINT}', api_key = '${OPEN_AI_KEY}', api_version = '${API_VERSION}')", - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: true }, - defaultValue: '4000', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - ], - 'AWS Bedrock': [ - { - name: 'Claude', - disable: false, - icon: CLAUDE, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: 'This field is required', - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: 'BEDROCK', - options: { - component: 'select', - options: [ - { - display: 'Bedrock', - value: 'BEDROCK', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'AWS_REGION', - label: 'Aws Region', - defaultValue: 'us-east-1', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'AWS_ACCESS_KEY', - label: 'Aws Access Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'AWS_SECRET_KEY', - label: 'Aws Secret Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: - "import genai_client;${VAR_NAME} = genai_client.BedrockClient(modelId = '${MODEL}', secret_key = '${AWS_SECRET_KEY}', access_key = '${AWS_ACCESS_KEY}', region='${AWS_REGION}')", - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - ], - 'Google GCP': [ - { - name: 'Palm Bison', - disable: false, - icon: VERTEX, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: 'VERTEX', - options: { - component: 'select', - options: [ - { - display: 'Vertex', - value: 'VERTEX', - }, - ], - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'text-bison', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'GCP_REGION', - label: 'GCP Region', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'text', - options: { - component: 'select', - options: [ - { - display: 'chat', - value: 'chat', - }, - { - display: 'code', - value: 'code', - }, - { - display: 'codechat', - value: 'codechat', - }, - { - display: 'generative', - value: 'generative', - }, - { - display: 'text', - value: 'text', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: - "import genai_client;${VAR_NAME} = genai_client.VertexClient(model_name = '${MODEL}', service_account_key_file = '${SERVICE_ACCOUNT_FILE}', region='${GCP_REGION}', chat_type='${CHAT_TYPE}')", - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'Palm Chat Bison', - disable: false, - icon: VERTEX, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: 'VERTEX', - options: { - component: 'select', - options: [ - { - display: 'Vertex', - value: 'VERTEX', - }, - ], - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'text-bison', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'GCP_REGION', - label: 'GCP Region', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'text', - options: { - component: 'select', - options: [ - { - display: 'chat', - value: 'chat', - }, - { - display: 'code', - value: 'code', - }, - { - display: 'codechat', - value: 'codechat', - }, - { - display: 'generative', - value: 'generative', - }, - { - display: 'text', - value: 'text', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: - "import genai_client;${VAR_NAME} = genai_client.VertexClient(model_name = '${MODEL}', service_account_key_file = '${SERVICE_ACCOUNT_FILE}', region='${GCP_REGION}', chat_type='${CHAT_TYPE}')", - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'Palm Code Bison', - disable: false, - icon: VERTEX, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: 'VERTEX', - options: { - component: 'select', - options: [ - { - display: 'Vertex', - value: 'VERTEX', - }, - ], - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'text-bison', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'GCP_REGION', - label: 'GCP Region', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'text', - options: { - component: 'select', - options: [ - { - display: 'chat', - value: 'chat', - }, - { - display: 'code', - value: 'code', - }, - { - display: 'codechat', - value: 'codechat', - }, - { - display: 'generative', - value: 'generative', - }, - { - display: 'text', - value: 'text', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: - "import genai_client;${VAR_NAME} = genai_client.VertexClient(model_name = '${MODEL}', service_account_key_file = '${SERVICE_ACCOUNT_FILE}', region='${GCP_REGION}', chat_type='${CHAT_TYPE}')", - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'Gemini', - disable: false, - icon: VERTEX, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( [VALUE] ) ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: 'VERTEX', - options: { - component: 'select', - options: [ - { - display: 'Vertex', - value: 'VERTEX', - }, - ], - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'gemini-1.5-pro-002', - options: { - component: 'select', - options: [ - { - display: 'gemini-1.5-pro-002', - value: 'gemini-1.5-pro-002', - }, - { - display: 'gemini-2.0-flash-001', - value: 'gemini-2.0-flash-001', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'GCP_REGION', - label: 'GCP Region', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'generative', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'FILE', - label: 'Upload Service Account File', - defaultValue: null, - options: { - component: 'file-upload', - }, - disabled: true, - secondary: true, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: - "import genai_client;${VAR_NAME} = genai_client.VertexClient(model_name = '${MODEL}', service_account_key_file = '${SERVICE_ACCOUNT_FILE}', service_account_credentials = ${SERVICE_ACCOUNT_CREDENTIALS}, region='${GCP_REGION}', chat_type='${CHAT_TYPE}')", - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - ], - 'NVIDIA NIM Models': [ - { - name: 'embed-qa-4', - disable: false, - icon: NEMO, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: 'OPEN_AI', - options: { - component: 'select', - options: [ - { - display: 'Open AI', - value: 'OPEN_AI', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'OPEN_AI_KEY', - label: 'Open AI Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: - 'mistralai/mixtral-8x7b-instruct-v0.1', - options: { - component: 'select', - options: [ - { - display: - 'mistralai/mixtral-8x7b-instruct-v0.1', - value: 'mistralai/mixtral-8x7b-instruct-v0.1', - }, - ], - }, - disabled: true, - hidden: true, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: - "import genai_client;${VAR_NAME} = genai_client.OpenAiClient(endpoint = 'https://integrate.api.nvidia.com/v1', model_name='${MODEL_TYPE}', chat_type = '${CHAT_TYPE}', api_key='${OPEN_AI_KEY}', template={ \"mixtral.default.nocontext\":\"[INST] $question [/INST]\"}, template_name='mixtral.default.nocontext')", - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'rerank-qa-mistral-4b', - disable: false, - icon: NEMO, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: 'OPEN_AI', - options: { - component: 'select', - options: [ - { - display: 'Open AI', - value: 'OPEN_AI', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'OPEN_AI_KEY', - label: 'Open AI Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: - 'mistralai/mixtral-8x7b-instruct-v0.1', - options: { - component: 'select', - options: [ - { - display: - 'mistralai/mixtral-8x7b-instruct-v0.1', - value: 'mistralai/mixtral-8x7b-instruct-v0.1', - }, - ], - }, - disabled: true, - hidden: true, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: - "import genai_client;${VAR_NAME} = genai_client.OpenAiClient(endpoint = 'https://integrate.api.nvidia.com/v1', model_name='${MODEL_TYPE}', chat_type = '${CHAT_TYPE}', api_key='${OPEN_AI_KEY}', template={ \"mixtral.default.nocontext\":\"[INST] $question [/INST]\"}, template_name='mixtral.default.nocontext')", - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - ], - }, - 'Locally Hosted': [ - { - name: 'Bert', - disable: false, - icon: BERT, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'Bert', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: '', - options: { - component: 'select', - options: [ - { - display: 'Text Generation', - value: 'TEXT_GENERATION', - }, - { - display: 'vLLM (Fast Chat)', - value: 'FAST_CHAT', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'Dolly', - disable: false, - icon: DOLLY, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'Dolly', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: '', - options: { - component: 'select', - options: [ - { - display: 'Text Generation', - value: 'TEXT_GENERATION', - }, - { - display: 'vLLM (Fast Chat)', - value: 'FAST_CHAT', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'Eleuther GPTJ', - disable: false, - icon: ELEUTHER, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'Eleuther GPTJ', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: '', - options: { - component: 'select', - options: [ - { - display: 'Text Generation', - value: 'TEXT_GENERATION', - }, - { - display: 'vLLM (Fast Chat)', - value: 'FAST_CHAT', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'Falcon', - disable: false, - icon: FALCON, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'Falcon', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: '', - options: { - component: 'select', - options: [ - { - display: 'Text Generation', - value: 'TEXT_GENERATION', - }, - { - display: 'vLLM (Fast Chat)', - value: 'FAST_CHAT', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'Flan T5 Large', - disable: false, - icon: FLAN, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'Flan T5 Large', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: '', - options: { - component: 'select', - options: [ - { - display: 'Text Generation', - value: 'TEXT_GENERATION', - }, - { - display: 'vLLM (Fast Chat)', - value: 'FAST_CHAT', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'Flan T5 XXL', - disable: false, - icon: FLAN, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'Flan T5 XXL', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: '', - options: { - component: 'select', - options: [ - { - display: 'Text Generation', - value: 'TEXT_GENERATION', - }, - { - display: 'vLLM (Fast Chat)', - value: 'FAST_CHAT', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'Guanaco', - disable: false, - icon: BRAIN, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'Guanaco', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: '', - options: { - component: 'select', - options: [ - { - display: 'Text Generation', - value: 'TEXT_GENERATION', - }, - { - display: 'vLLM (Fast Chat)', - value: 'FAST_CHAT', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'Llama2 7B', - disable: false, - icon: META, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'meta-llama/Llama-2-7b', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: '', - options: { - component: 'select', - options: [ - { - display: 'Text Generation', - value: 'TEXT_GENERATION', - }, - { - display: 'vLLM (Fast Chat)', - value: 'FAST_CHAT', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'Llama2 13B', - disable: false, - icon: META, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'meta-llama/Llama-2-13b', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: '', - options: { - component: 'select', - options: [ - { - display: 'Text Generation', - value: 'TEXT_GENERATION', - }, - { - display: 'vLLM (Fast Chat)', - value: 'FAST_CHAT', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'Llama2 70B', - disable: false, - icon: META, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'meta-llama/Llama-2-70b', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: '', - options: { - component: 'select', - options: [ - { - display: 'Text Generation', - value: 'TEXT_GENERATION', - }, - { - display: 'vLLM (Fast Chat)', - value: 'FAST_CHAT', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'Mosaic ML', - disable: false, - icon: MOSAIC, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'Mosaic ML', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: '', - options: { - component: 'select', - options: [ - { - display: 'Text Generation', - value: 'TEXT_GENERATION', - }, - { - display: 'vLLM (Fast Chat)', - value: 'FAST_CHAT', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'Replit code model – 3b', - disable: false, - icon: REPLIT, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'Replit code model – 3b', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: '', - options: { - component: 'select', - options: [ - { - display: 'Text Generation', - value: 'TEXT_GENERATION', - }, - { - display: 'vLLM (Fast Chat)', - value: 'FAST_CHAT', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'StableBeluga2', - disable: false, - icon: BRAIN, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'StableBeluga2', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: '', - options: { - component: 'select', - options: [ - { - display: 'Text Generation', - value: 'TEXT_GENERATION', - }, - { - display: 'vLLM (Fast Chat)', - value: 'FAST_CHAT', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'Vicuna', - disable: false, - icon: VICUNA, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'Vicuna', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: '', - options: { - component: 'select', - options: [ - { - display: 'Text Generation', - value: 'TEXT_GENERATION', - }, - { - display: 'vLLM (Fast Chat)', - value: 'FAST_CHAT', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'Wizard 13B', - disable: false, - icon: BRAIN, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'Wizard 13B', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: '', - options: { - component: 'select', - options: [ - { - display: 'Text Generation', - value: 'TEXT_GENERATION', - }, - { - display: 'vLLM (Fast Chat)', - value: 'FAST_CHAT', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'Wizard Coder', - disable: false, - icon: BRAIN, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'WizardLM/WizardCoder-15B-V1.0', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: '', - options: { - component: 'select', - options: [ - { - display: 'Text Generation', - value: 'TEXT_GENERATION', - }, - { - display: 'vLLM (Fast Chat)', - value: 'FAST_CHAT', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - ], - Embedded: [ - { - name: 'NeMo', - disable: true, - icon: NEMO, - fields: [], - }, - { - name: 'Orca', - disable: false, - icon: ORCA, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'Orca', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: '', - options: { - component: 'select', - options: [ - { - display: 'Embedded', - value: 'EMBEDDED', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'AWS TITAN TEXT EMBEDDINGS', - disable: true, - icon: Amazon_Titan, - fields: [ - { - fieldName: 'NAME', - label: 'Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: 'AWS_TITAN_TEXT_EMBEDDINGS', - options: { - component: 'select', - options: [ - { - display: 'AWS TITAN TEXT EMBEDDINGS', - value: 'AWS_TITAN_TEXT_EMBEDDINGS', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: 'amazon.titan-embed-text-v2:0', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'AWS_REGION', - label: 'Aws Region', - defaultValue: 'us-east-1', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'AWS_ACCESS_KEY', - label: 'Aws Access Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'AWS_SECRET_KEY', - label: 'Aws Secret Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - ], - }, - { - name: 'Stablity AI', - disable: true, - icon: STABILITY_AI, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: '', - options: { - component: 'select', - options: [ - { - display: 'Embedded', - value: 'EMBEDDED', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - { - name: 'Replit Code Model', - disable: true, - icon: REPLIT, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MODEL', - label: 'Model', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'MODEL_TYPE', - label: 'Type', - defaultValue: '', - options: { - component: 'select', - options: [ - { - display: 'Embedded', - value: 'EMBEDDED', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'VAR_NAME', - label: 'Variable Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHAT_TYPE', - label: 'Chat Type', - defaultValue: 'chat-completion', - options: { - component: 'select', - options: [ - { - display: 'chat-completion', - value: 'chat-completion', - }, - { - display: 'completion', - value: 'completion', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INIT_MODEL_ENGINE', - label: 'Init Script', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_CONVERSATION_HISTORY', - label: 'Keep Conversation History', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MAX_TOKENS', - label: 'Max Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - { - fieldName: 'MAX_INPUT_TOKENS', - label: 'Max Input Tokens', - rules: { required: false }, - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - }, - ], - }, - ], - 'File Uploads': [ - { - name: 'ZIP', - disable: false, - icon: ZIP, - fields: [ - { - fieldName: 'ZIP', - label: 'Zip File', - defaultValue: null, - options: { - component: 'file-upload', - }, - disabled: true, - rules: { required: true }, - }, - ], - }, - ], - }, - FUNCTION: { - Function: [ - { - name: 'AWS Image Text Extraction', - disable: false, - icon: AWS_TEXTRACT, - fields: [ - { - fieldName: 'FUNCTION_TYPE', - label: 'Function Type', - defaultValue: 'AWS_TEXTRACT', - options: { - component: 'select', - options: [ - { - display: 'AWS TEXTRACT', - value: 'AWS_TEXTRACT', - }, - { - display: 'AWS REKOGNITION', - value: 'AWS_REKOGNITION', - }, - ], - }, - disabled: false, - hidden: false, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ACCESS_KEY', - label: 'Access Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'SECRET_KEY', - label: 'Secret Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'REGION', - label: 'Region', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'S3BUCKETENGINEID', - label: 'S3 Bucket Engine Id', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_NAME', - label: 'Function Name (metadata)', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_DESCRIPTION', - label: 'Function Description (metadata)', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_REQUIRED_PARAMETERS', - label: 'Function Required Parameters', - defaultValue: '["isFilePresentInS3","filePath"]', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - ], - }, - { - name: 'AWS Polly', - disable: false, - icon: AWS_POLLY, - fields: [ - { - fieldName: 'FUNCTION_TYPE', - label: 'Function Type', - defaultValue: 'AWS_POLLY', + MODEL: { + "Commercially Hosted": { + OpenAI: [ + { + name: "GPT-3.5", + disable: false, + icon: OPEN_AI, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "OPEN_AI", + options: { + component: "select", + options: [ + { + display: "Open AI", + value: "OPEN_AI", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "OPEN_AI_KEY", + label: "Open AI Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "gpt-3.5-turbo", + options: { + component: "select", + options: [ + { + display: "gpt-3.5-turbo", + value: "gpt-3.5-turbo", + }, + { + display: "gpt-4-32k", + value: "gpt-4-32k", + }, + ], + }, + disabled: true, + hidden: true, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: + "import genai_client;${VAR_NAME} = genai_client.OpenAiClient(model_name = '${MODEL}', api_key = '${OPEN_AI_KEY}', chat_type = '${CHAT_TYPE}')", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "GPT-4", + disable: false, + icon: OPEN_AI, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "OPEN_AI", + options: { + component: "select", + options: [ + { + display: "Open AI", + value: "OPEN_AI", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "OPEN_AI_KEY", + label: "Open AI Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "gpt-4-32k", + options: { + component: "select", + options: [ + { + display: "gpt-4-32k", + value: "gpt-4-32k", + }, + ], + }, + disabled: true, + hidden: true, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: + "import genai_client;${VAR_NAME} = genai_client.OpenAiClient(model_name = '${MODEL}', api_key = '${OPEN_AI_KEY}', chat_type = '${CHAT_TYPE}')", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "Text-Davinci", + disable: false, + icon: OPEN_AI, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "OPEN_AI", + options: { + component: "select", + options: [ + { + display: "Open AI", + value: "OPEN_AI", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "OPEN_AI_KEY", + label: "Open AI Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "text-davinci", + options: { + component: "select", + options: [ + { + display: "text-davinci", + value: "text-davinci", + }, + ], + }, + disabled: true, + hidden: true, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: + "from genai_client import OpenAiEmbedder;${VAR_NAME} = OpenAiEmbedder(model_name = '${MODEL}', api_key = '${OPEN_AI_KEY}')", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "DALL E", + disable: false, + icon: OPEN_AI, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "OPEN_AI", + options: { + component: "select", + options: [ + { + display: "Open AI", + value: "OPEN_AI", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "OPEN_AI_KEY", + label: "Open AI Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "dall e", + options: { + component: "select", + options: [ + { + display: "dall e", + value: "dall e", + }, + ], + }, + disabled: true, + hidden: true, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + ], + Azure: [ + { + name: "Azure Open AI", + disable: false, + icon: AZURE_OPEN_AI, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "OPEN_AI", + options: { + component: "select", + options: [ + { + display: "Open AI", + value: "OPEN_AI", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "OPEN_AI_KEY", + label: "Azure Open AI Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL", + label: "Deployment Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Azure Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: + "import genai_client;${VAR_NAME} = genai_client.AzureOpenAiClient(api_key = '${OPEN_AI_KEY}', endpoint = '${ENDPOINT}', model_name = '${MODEL}', chat_type = '${CHAT_TYPE}')", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "Azure Open AI ADA Embedder", + disable: false, + icon: AZURE_OPEN_AI, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: "CheckEngineName ( [VALUE] ) ;", + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "TAG", + label: "Tag", + defaultValue: "embeddings", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "OPEN_AI", + options: { + component: "select", + options: [ + { + display: "Open AI", + value: "OPEN_AI", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "text-embedding-ada-002", + options: { + component: "select", + options: [ + { + display: "text-embedding-ada-002", + value: "text-embedding-ada-002", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "OPEN_AI_KEY", + label: "Azure Open AI API Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Azure Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "API_VERSION", + label: "API version", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: + "from genai_client import AzureOpenAiEmbedder;${VAR_NAME} = AzureOpenAiEmbedder(model_name = '${MODEL}', endpoint = '${ENDPOINT}', api_key = '${OPEN_AI_KEY}', api_version = '${API_VERSION}')", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: true }, + defaultValue: "4000", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + ], + "AWS Bedrock": [ + { + name: "Claude", + disable: false, + icon: CLAUDE, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: "This field is required", + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "BEDROCK", + options: { + component: "select", + options: [ + { + display: "Bedrock", + value: "BEDROCK", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "AWS_REGION", + label: "Aws Region", + defaultValue: "us-east-1", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "AWS_ACCESS_KEY", + label: "Aws Access Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "AWS_SECRET_KEY", + label: "Aws Secret Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: + "import genai_client;${VAR_NAME} = genai_client.BedrockClient(modelId = '${MODEL}', secret_key = '${AWS_SECRET_KEY}', access_key = '${AWS_ACCESS_KEY}', region='${AWS_REGION}')", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + ], + "Google GCP": [ + { + name: "Palm Bison", + disable: false, + icon: VERTEX, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "VERTEX", + options: { + component: "select", + options: [ + { + display: "Vertex", + value: "VERTEX", + }, + ], + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "text-bison", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "GCP_REGION", + label: "GCP Region", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "text", + options: { + component: "select", + options: [ + { + display: "chat", + value: "chat", + }, + { + display: "code", + value: "code", + }, + { + display: "codechat", + value: "codechat", + }, + { + display: "generative", + value: "generative", + }, + { + display: "text", + value: "text", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: + "import genai_client;${VAR_NAME} = genai_client.VertexClient(model_name = '${MODEL}', service_account_key_file = '${SERVICE_ACCOUNT_FILE}', region='${GCP_REGION}', chat_type='${CHAT_TYPE}')", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "Palm Chat Bison", + disable: false, + icon: VERTEX, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "VERTEX", + options: { + component: "select", + options: [ + { + display: "Vertex", + value: "VERTEX", + }, + ], + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "text-bison", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "GCP_REGION", + label: "GCP Region", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "text", + options: { + component: "select", + options: [ + { + display: "chat", + value: "chat", + }, + { + display: "code", + value: "code", + }, + { + display: "codechat", + value: "codechat", + }, + { + display: "generative", + value: "generative", + }, + { + display: "text", + value: "text", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: + "import genai_client;${VAR_NAME} = genai_client.VertexClient(model_name = '${MODEL}', service_account_key_file = '${SERVICE_ACCOUNT_FILE}', region='${GCP_REGION}', chat_type='${CHAT_TYPE}')", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "Palm Code Bison", + disable: false, + icon: VERTEX, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "VERTEX", + options: { + component: "select", + options: [ + { + display: "Vertex", + value: "VERTEX", + }, + ], + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "text-bison", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "GCP_REGION", + label: "GCP Region", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "text", + options: { + component: "select", + options: [ + { + display: "chat", + value: "chat", + }, + { + display: "code", + value: "code", + }, + { + display: "codechat", + value: "codechat", + }, + { + display: "generative", + value: "generative", + }, + { + display: "text", + value: "text", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: + "import genai_client;${VAR_NAME} = genai_client.VertexClient(model_name = '${MODEL}', service_account_key_file = '${SERVICE_ACCOUNT_FILE}', region='${GCP_REGION}', chat_type='${CHAT_TYPE}')", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "Gemini", + disable: false, + icon: VERTEX, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: "CheckEngineName ( [VALUE] ) ;", + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "VERTEX", + options: { + component: "select", + options: [ + { + display: "Vertex", + value: "VERTEX", + }, + ], + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "gemini-1.5-pro-002", + options: { + component: "select", + options: [ + { + display: "gemini-1.5-pro-002", + value: "gemini-1.5-pro-002", + }, + { + display: "gemini-2.0-flash-001", + value: "gemini-2.0-flash-001", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "GCP_REGION", + label: "GCP Region", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "generative", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "FILE", + label: "Upload Service Account File", + defaultValue: null, + options: { + component: "file-upload", + }, + disabled: true, + secondary: true, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: + "import genai_client;${VAR_NAME} = genai_client.VertexClient(model_name = '${MODEL}', service_account_key_file = '${SERVICE_ACCOUNT_FILE}', service_account_credentials = ${SERVICE_ACCOUNT_CREDENTIALS}, region='${GCP_REGION}', chat_type='${CHAT_TYPE}')", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + ], + "NVIDIA NIM Models": [ + { + name: "embed-qa-4", + disable: false, + icon: NEMO, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "OPEN_AI", + options: { + component: "select", + options: [ + { + display: "Open AI", + value: "OPEN_AI", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "OPEN_AI_KEY", + label: "Open AI Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: + "mistralai/mixtral-8x7b-instruct-v0.1", + options: { + component: "select", + options: [ + { + display: + "mistralai/mixtral-8x7b-instruct-v0.1", + value: "mistralai/mixtral-8x7b-instruct-v0.1", + }, + ], + }, + disabled: true, + hidden: true, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: + "import genai_client;${VAR_NAME} = genai_client.OpenAiClient(endpoint = 'https://integrate.api.nvidia.com/v1', model_name='${MODEL_TYPE}', chat_type = '${CHAT_TYPE}', api_key='${OPEN_AI_KEY}', template={ \"mixtral.default.nocontext\":\"[INST] $question [/INST]\"}, template_name='mixtral.default.nocontext')", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "rerank-qa-mistral-4b", + disable: false, + icon: NEMO, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "OPEN_AI", + options: { + component: "select", + options: [ + { + display: "Open AI", + value: "OPEN_AI", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "OPEN_AI_KEY", + label: "Open AI Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: + "mistralai/mixtral-8x7b-instruct-v0.1", + options: { + component: "select", + options: [ + { + display: + "mistralai/mixtral-8x7b-instruct-v0.1", + value: "mistralai/mixtral-8x7b-instruct-v0.1", + }, + ], + }, + disabled: true, + hidden: true, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: + "import genai_client;${VAR_NAME} = genai_client.OpenAiClient(endpoint = 'https://integrate.api.nvidia.com/v1', model_name='${MODEL_TYPE}', chat_type = '${CHAT_TYPE}', api_key='${OPEN_AI_KEY}', template={ \"mixtral.default.nocontext\":\"[INST] $question [/INST]\"}, template_name='mixtral.default.nocontext')", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + ], + }, + "Locally Hosted": [ + { + name: "Bert", + disable: false, + icon: BERT, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "Bert", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "", + options: { + component: "select", + options: [ + { + display: "Text Generation", + value: "TEXT_GENERATION", + }, + { + display: "vLLM (Fast Chat)", + value: "FAST_CHAT", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "Dolly", + disable: false, + icon: DOLLY, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "Dolly", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "", + options: { + component: "select", + options: [ + { + display: "Text Generation", + value: "TEXT_GENERATION", + }, + { + display: "vLLM (Fast Chat)", + value: "FAST_CHAT", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "Eleuther GPTJ", + disable: false, + icon: ELEUTHER, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "Eleuther GPTJ", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "", + options: { + component: "select", + options: [ + { + display: "Text Generation", + value: "TEXT_GENERATION", + }, + { + display: "vLLM (Fast Chat)", + value: "FAST_CHAT", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "Falcon", + disable: false, + icon: FALCON, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "Falcon", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "", + options: { + component: "select", + options: [ + { + display: "Text Generation", + value: "TEXT_GENERATION", + }, + { + display: "vLLM (Fast Chat)", + value: "FAST_CHAT", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "Flan T5 Large", + disable: false, + icon: FLAN, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "Flan T5 Large", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "", + options: { + component: "select", + options: [ + { + display: "Text Generation", + value: "TEXT_GENERATION", + }, + { + display: "vLLM (Fast Chat)", + value: "FAST_CHAT", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "Flan T5 XXL", + disable: false, + icon: FLAN, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "Flan T5 XXL", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "", + options: { + component: "select", + options: [ + { + display: "Text Generation", + value: "TEXT_GENERATION", + }, + { + display: "vLLM (Fast Chat)", + value: "FAST_CHAT", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "Guanaco", + disable: false, + icon: BRAIN, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "Guanaco", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "", + options: { + component: "select", + options: [ + { + display: "Text Generation", + value: "TEXT_GENERATION", + }, + { + display: "vLLM (Fast Chat)", + value: "FAST_CHAT", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "Llama2 7B", + disable: false, + icon: META, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "meta-llama/Llama-2-7b", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "", + options: { + component: "select", + options: [ + { + display: "Text Generation", + value: "TEXT_GENERATION", + }, + { + display: "vLLM (Fast Chat)", + value: "FAST_CHAT", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "Llama2 13B", + disable: false, + icon: META, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "meta-llama/Llama-2-13b", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "", + options: { + component: "select", + options: [ + { + display: "Text Generation", + value: "TEXT_GENERATION", + }, + { + display: "vLLM (Fast Chat)", + value: "FAST_CHAT", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "Llama2 70B", + disable: false, + icon: META, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "meta-llama/Llama-2-70b", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "", + options: { + component: "select", + options: [ + { + display: "Text Generation", + value: "TEXT_GENERATION", + }, + { + display: "vLLM (Fast Chat)", + value: "FAST_CHAT", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "Mosaic ML", + disable: false, + icon: MOSAIC, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "Mosaic ML", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "", + options: { + component: "select", + options: [ + { + display: "Text Generation", + value: "TEXT_GENERATION", + }, + { + display: "vLLM (Fast Chat)", + value: "FAST_CHAT", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "Replit code model – 3b", + disable: false, + icon: REPLIT, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "Replit code model – 3b", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "", + options: { + component: "select", + options: [ + { + display: "Text Generation", + value: "TEXT_GENERATION", + }, + { + display: "vLLM (Fast Chat)", + value: "FAST_CHAT", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "StableBeluga2", + disable: false, + icon: BRAIN, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "StableBeluga2", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "", + options: { + component: "select", + options: [ + { + display: "Text Generation", + value: "TEXT_GENERATION", + }, + { + display: "vLLM (Fast Chat)", + value: "FAST_CHAT", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "Vicuna", + disable: false, + icon: VICUNA, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "Vicuna", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "", + options: { + component: "select", + options: [ + { + display: "Text Generation", + value: "TEXT_GENERATION", + }, + { + display: "vLLM (Fast Chat)", + value: "FAST_CHAT", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "Wizard 13B", + disable: false, + icon: BRAIN, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "Wizard 13B", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "", + options: { + component: "select", + options: [ + { + display: "Text Generation", + value: "TEXT_GENERATION", + }, + { + display: "vLLM (Fast Chat)", + value: "FAST_CHAT", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "Wizard Coder", + disable: false, + icon: BRAIN, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "WizardLM/WizardCoder-15B-V1.0", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "", + options: { + component: "select", + options: [ + { + display: "Text Generation", + value: "TEXT_GENERATION", + }, + { + display: "vLLM (Fast Chat)", + value: "FAST_CHAT", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + ], + Embedded: [ + { + name: "NeMo", + disable: true, + icon: NEMO, + fields: [], + }, + { + name: "Orca", + disable: false, + icon: ORCA, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "Orca", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "", + options: { + component: "select", + options: [ + { + display: "Embedded", + value: "EMBEDDED", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "AWS TITAN TEXT EMBEDDINGS", + disable: true, + icon: Amazon_Titan, + fields: [ + { + fieldName: "NAME", + label: "Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "AWS_TITAN_TEXT_EMBEDDINGS", + options: { + component: "select", + options: [ + { + display: "AWS TITAN TEXT EMBEDDINGS", + value: "AWS_TITAN_TEXT_EMBEDDINGS", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "amazon.titan-embed-text-v2:0", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "AWS_REGION", + label: "Aws Region", + defaultValue: "us-east-1", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "AWS_ACCESS_KEY", + label: "Aws Access Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "AWS_SECRET_KEY", + label: "Aws Secret Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + ], + }, + { + name: "Stablity AI", + disable: true, + icon: STABILITY_AI, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "", + options: { + component: "select", + options: [ + { + display: "Embedded", + value: "EMBEDDED", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + { + name: "Replit Code Model", + disable: true, + icon: REPLIT, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MODEL", + label: "Model", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "MODEL_TYPE", + label: "Type", + defaultValue: "", + options: { + component: "select", + options: [ + { + display: "Embedded", + value: "EMBEDDED", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "VAR_NAME", + label: "Variable Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHAT_TYPE", + label: "Chat Type", + defaultValue: "chat-completion", + options: { + component: "select", + options: [ + { + display: "chat-completion", + value: "chat-completion", + }, + { + display: "completion", + value: "completion", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INIT_MODEL_ENGINE", + label: "Init Script", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_CONVERSATION_HISTORY", + label: "Keep Conversation History", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MAX_TOKENS", + label: "Max Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + { + fieldName: "MAX_INPUT_TOKENS", + label: "Max Input Tokens", + rules: { required: false }, + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + }, + ], + }, + ], + "File Uploads": [ + { + name: "ZIP", + disable: false, + icon: ZIP, + fields: [ + { + fieldName: "ZIP", + label: "Zip File", + defaultValue: null, + options: { + component: "file-upload", + }, + disabled: true, + rules: { required: true }, + }, + ], + }, + ], + }, + FUNCTION: { + Function: [ + { + name: "AWS Image Text Extraction", + disable: false, + icon: AWS_TEXTRACT, + fields: [ + { + fieldName: "FUNCTION_TYPE", + label: "Function Type", + defaultValue: "AWS_TEXTRACT", + options: { + component: "select", + options: [ + { + display: "AWS TEXTRACT", + value: "AWS_TEXTRACT", + }, + { + display: "AWS REKOGNITION", + value: "AWS_REKOGNITION", + }, + ], + }, + disabled: false, + hidden: false, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ACCESS_KEY", + label: "Access Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "SECRET_KEY", + label: "Secret Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "REGION", + label: "Region", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "S3BUCKETENGINEID", + label: "S3 Bucket Engine Id", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_NAME", + label: "Function Name (metadata)", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_DESCRIPTION", + label: "Function Description (metadata)", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_REQUIRED_PARAMETERS", + label: "Function Required Parameters", + defaultValue: '["isFilePresentInS3","filePath"]', + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + ], + }, + { + name: "AWS Polly", + disable: false, + icon: AWS_POLLY, + fields: [ + { + fieldName: "FUNCTION_TYPE", + label: "Function Type", + defaultValue: "AWS_POLLY", - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ACCESS_KEY', - label: 'Access Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'SECRET_KEY', - label: 'Secret Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'REGION', - label: 'Region', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_NAME', - label: 'Function Name (metadata)', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_DESCRIPTION', - label: 'Function Description (metadata)', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_REQUIRED_PARAMETERS', - label: 'Function Required Parameters', - defaultValue: '["extractedText","nameOfTheAudioFile"]', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - ], - }, - { - name: 'AWS Transcribe', - disable: false, - icon: AWS_TRANSCRIBE, - fields: [ - { - fieldName: 'FUNCTION_TYPE', - label: 'Function Type', - defaultValue: 'AWS_Transcribe', + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ACCESS_KEY", + label: "Access Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "SECRET_KEY", + label: "Secret Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "REGION", + label: "Region", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_NAME", + label: "Function Name (metadata)", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_DESCRIPTION", + label: "Function Description (metadata)", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_REQUIRED_PARAMETERS", + label: "Function Required Parameters", + defaultValue: '["extractedText","nameOfTheAudioFile"]', + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + ], + }, + { + name: "AWS Transcribe", + disable: false, + icon: AWS_TRANSCRIBE, + fields: [ + { + fieldName: "FUNCTION_TYPE", + label: "Function Type", + defaultValue: "AWS_Transcribe", - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ACCESS_KEY', - label: 'Access Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'SECRET_KEY', - label: 'Secret Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'REGION', - label: 'Region', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'S3BUCKETENGINEID', - label: 'S3 Bucket Engine Id', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_NAME', - label: 'Function Name (metadata)', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_DESCRIPTION', - label: 'Function Description (metadata)', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_REQUIRED_PARAMETERS', - label: 'Function Required Parameters', - defaultValue: '["isFilePresentInS3","filePath"]', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - ], - }, - { - name: 'AWS Comprehend', - disable: false, - icon: AWS_COMPREHEND, - fields: [ - { - fieldName: 'FUNCTION_TYPE', - label: 'Function Type', - defaultValue: 'AWS_COMPREHEND', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'ACCESS_KEY', - label: 'Access Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'SECRET_KEY', - label: 'Secret Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'REGION', - label: 'Region', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_REQUIRED_PARAMETERS', - label: 'Function Required Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_NAME', - label: 'Function Name (metadata)', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_DESCRIPTION', - label: 'Function Description (metadata)', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - ], - }, - { - name: 'Azure Document Intelligence', - disable: false, - icon: RESTAPI, - fields: [ - { - fieldName: 'FUNCTION_TYPE', - label: 'Function Type', - defaultValue: - 'AZURE_DOCUMENT_INTELLIGENCE_CUSTOM_EMBEDDINGS', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'URL', - label: 'URL', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'API_KEY', - label: 'API Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - ], - }, - { - name: 'Azure Speech To Text', - disable: false, - icon: AZURE_SPEECH_TO_TEXT, - fields: [ - { - fieldName: 'FUNCTION_TYPE', - label: 'Function Type', - defaultValue: 'AZURE SPEECH TO TEXT', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'SPEECH_KEY', - label: 'Speech Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'SPEECH_REGION', - label: 'Speech region', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_REQUIRED_PARAMETERS', - label: 'Function Required Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_NAME', - label: 'Function Name (metadata)', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_DESCRIPTION', - label: 'Function Description (metadata)', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - ], - }, - { - name: 'Google Speech To Text', - disable: false, - icon: GOOGLE_SPEECH_TO_TEXT, - fields: [ - { - fieldName: 'FUNCTION_TYPE', - label: 'Function Type', - defaultValue: 'GOOGLE_SPEECH_TO_TEXT', + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ACCESS_KEY", + label: "Access Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "SECRET_KEY", + label: "Secret Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "REGION", + label: "Region", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "S3BUCKETENGINEID", + label: "S3 Bucket Engine Id", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_NAME", + label: "Function Name (metadata)", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_DESCRIPTION", + label: "Function Description (metadata)", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_REQUIRED_PARAMETERS", + label: "Function Required Parameters", + defaultValue: '["isFilePresentInS3","filePath"]', + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + ], + }, + { + name: "AWS Comprehend", + disable: false, + icon: AWS_COMPREHEND, + fields: [ + { + fieldName: "FUNCTION_TYPE", + label: "Function Type", + defaultValue: "AWS_COMPREHEND", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "ACCESS_KEY", + label: "Access Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "SECRET_KEY", + label: "Secret Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "REGION", + label: "Region", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_REQUIRED_PARAMETERS", + label: "Function Required Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_NAME", + label: "Function Name (metadata)", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_DESCRIPTION", + label: "Function Description (metadata)", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + ], + }, + { + name: "Azure Document Intelligence", + disable: false, + icon: RESTAPI, + fields: [ + { + fieldName: "FUNCTION_TYPE", + label: "Function Type", + defaultValue: + "AZURE_DOCUMENT_INTELLIGENCE_CUSTOM_EMBEDDINGS", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "URL", + label: "URL", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "API_KEY", + label: "API Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + ], + }, + { + name: "Azure Speech To Text", + disable: false, + icon: AZURE_SPEECH_TO_TEXT, + fields: [ + { + fieldName: "FUNCTION_TYPE", + label: "Function Type", + defaultValue: "AZURE SPEECH TO TEXT", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "SPEECH_KEY", + label: "Speech Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "SPEECH_REGION", + label: "Speech region", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_REQUIRED_PARAMETERS", + label: "Function Required Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_NAME", + label: "Function Name (metadata)", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_DESCRIPTION", + label: "Function Description (metadata)", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + ], + }, + { + name: "Google Speech To Text", + disable: false, + icon: GOOGLE_SPEECH_TO_TEXT, + fields: [ + { + fieldName: "FUNCTION_TYPE", + label: "Function Type", + defaultValue: "GOOGLE_SPEECH_TO_TEXT", - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FILE', - label: 'Upload Service Account File', - defaultValue: null, - options: { - component: 'file-upload', - }, - disabled: true, - secondary: true, - rules: { required: true }, - }, - { - fieldName: 'GOOGLE_BUCKET_ENGINEID', - label: 'Google Bucket Engine Id', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_NAME', - label: 'Function Name (metadata)', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_DESCRIPTION', - label: 'Function Description (metadata)', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_REQUIRED_PARAMETERS', - label: 'Function Required Parameters', - defaultValue: '["isFilePresentInBucket","filePath"]', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - ], - }, - { - name: 'Google OCR', - disable: false, - icon: GOOGLE_OCR, - fields: [ - { - fieldName: 'FUNCTION_TYPE', - label: 'Function Type', - defaultValue: 'GOOGLE_OCR', + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FILE", + label: "Upload Service Account File", + defaultValue: null, + options: { + component: "file-upload", + }, + disabled: true, + secondary: true, + rules: { required: true }, + }, + { + fieldName: "GOOGLE_BUCKET_ENGINEID", + label: "Google Bucket Engine Id", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_NAME", + label: "Function Name (metadata)", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_DESCRIPTION", + label: "Function Description (metadata)", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_REQUIRED_PARAMETERS", + label: "Function Required Parameters", + defaultValue: '["isFilePresentInBucket","filePath"]', + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + ], + }, + { + name: "Google OCR", + disable: false, + icon: GOOGLE_OCR, + fields: [ + { + fieldName: "FUNCTION_TYPE", + label: "Function Type", + defaultValue: "GOOGLE_OCR", - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'PROJECT_ID', - label: 'Project Id', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'PROCESSOR_ID', - label: 'Processor Id', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'REGION', - label: 'Region', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FILE', - label: 'Upload Service Account File', - defaultValue: null, - options: { - component: 'file-upload', - }, - disabled: true, - secondary: true, - rules: { required: true }, - }, - { - fieldName: 'GOOGLE_BUCKET_ENGINEID', - label: 'Google Bucket Engine Id', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_NAME', - label: 'Function Name (metadata)', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_DESCRIPTION', - label: 'Function Description (metadata)', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_REQUIRED_PARAMETERS', - label: 'Function Required Parameters', - defaultValue: '["isFilePresentInBucket","filePath"]', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - ], - }, - { - name: 'REST', - disable: false, - icon: RESTAPI, - fields: [ - { - fieldName: 'FUNCTION_TYPE', - label: 'Function Type', - defaultValue: 'REST', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'URL', - label: 'URL', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'HTTP_METHOD', - label: 'Http Method', - defaultValue: 'POST', - options: { - component: 'select', - options: [ - { - display: 'GET', - value: 'GET', - }, - { - display: 'HEAD', - value: 'HEAD', - }, - { - display: 'POST', - value: 'POST', - }, - { - display: 'PUT', - value: 'PUT', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CONTENT_TYPE', - label: 'POST Message Body Type', - defaultValue: 'json', - options: { - component: 'select', - options: [ - { - display: 'json', - value: 'json', - }, - { - display: 'x-www-form-urlencoded', - value: 'x-www-form-urlencoded', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'HEADERS', - label: 'Http Headers', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'FUNCTION_PARAMETERS', - label: 'Function Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_REQUIRED_PARAMETERS', - label: 'Function Required Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_NAME', - label: 'Function Name (metadata)', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'FUNCTION_DESCRIPTION', - label: 'Function Description (metadata)', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - ], - }, - ], - 'File Uploads': [ - { - name: 'ZIP', - disable: false, - icon: ZIP, - fields: [ - { - fieldName: 'ZIP', - label: 'Zip File', - defaultValue: null, - options: { - component: 'file-upload', - }, - disabled: true, - rules: { required: true }, - }, - ], - }, - ], - }, - VECTOR: { - Connections: [ - { - name: 'Azure AI Search', - disable: false, - icon: MICROSOFT, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'VECTOR_TYPE', - label: 'Type', - defaultValue: 'AZURE_AI_SEARCH', - options: { - component: 'text-field', - }, - disabled: true, - hidden: true, - rules: { required: true }, - }, - { - fieldName: 'EMBEDDER_ENGINE_ID', - label: 'Embedder', - defaultValue: '', - options: { - component: 'select', - options: [], - pixel: `MyEngines ( metaKeys = [] , metaFilters = [{ "tag" : "embeddings" }] , engineTypes = [ 'MODEL' ] ) ;`, - optionDisplay: 'database_name', - optionValue: 'database_id', - }, - disabled: false, - rules: { required: true }, - helperText: - 'The registered model engine responsible for converting input strings into fixed-size vectors, known as embeddings, capturing semantic information for downstream machine learning and natural language processing tasks.', - }, - { - fieldName: 'INDEX_CLASSES', - label: 'Index Classes', - defaultValue: 'default', - options: { - component: 'text-field', - }, - disabled: true, - hidden: true, - rules: { required: true }, - }, - { - fieldName: 'CHUNKING_STRATEGY', - label: 'Chunking Strategy', - defaultValue: 'ALL', - options: { - component: 'select', - options: [ - { - display: 'Token', - value: 'ALL', - }, - { - display: 'Page by page', - value: 'PAGE_BY_PAGE', - }, - { - display: 'Markdown', - value: 'MARKDOWN', - } - ], - }, - disabled: false, - hidden: false, - rules: { required: true }, - displayRules: { - hideOtherFields: [ - { - fieldName: 'CONTENT_LENGTH', - value: ['PAGE_BY_PAGE', 'MARKDOWN'], - }, - ], - }, - }, - { - fieldName: 'CONTENT_LENGTH', - label: 'Content Length', - defaultValue: '512', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - helperText: - "The content length represents the upper limit of tokens within a chunk, as determined by the embedder's tokenizer.", - }, - { - fieldName: 'CONTENT_OVERLAP', - label: 'Content Overlap', - defaultValue: '20', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - helperText: - 'The number of tokens from prior chunks that are carried over into the current chunk when processing content.', - }, - { - fieldName: 'HOSTNAME', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'API_KEY', - label: 'API Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'API_VERSION', - label: 'API Version', - defaultValue: '2024-07-01', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "PROJECT_ID", + label: "Project Id", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "PROCESSOR_ID", + label: "Processor Id", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "REGION", + label: "Region", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FILE", + label: "Upload Service Account File", + defaultValue: null, + options: { + component: "file-upload", + }, + disabled: true, + secondary: true, + rules: { required: true }, + }, + { + fieldName: "GOOGLE_BUCKET_ENGINEID", + label: "Google Bucket Engine Id", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_NAME", + label: "Function Name (metadata)", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_DESCRIPTION", + label: "Function Description (metadata)", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_REQUIRED_PARAMETERS", + label: "Function Required Parameters", + defaultValue: '["isFilePresentInBucket","filePath"]', + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + ], + }, + { + name: "REST", + disable: false, + icon: RESTAPI, + fields: [ + { + fieldName: "FUNCTION_TYPE", + label: "Function Type", + defaultValue: "REST", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "URL", + label: "URL", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "HTTP_METHOD", + label: "Http Method", + defaultValue: "POST", + options: { + component: "select", + options: [ + { + display: "GET", + value: "GET", + }, + { + display: "HEAD", + value: "HEAD", + }, + { + display: "POST", + value: "POST", + }, + { + display: "PUT", + value: "PUT", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CONTENT_TYPE", + label: "POST Message Body Type", + defaultValue: "json", + options: { + component: "select", + options: [ + { + display: "json", + value: "json", + }, + { + display: "x-www-form-urlencoded", + value: "x-www-form-urlencoded", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "HEADERS", + label: "Http Headers", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "FUNCTION_PARAMETERS", + label: "Function Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_REQUIRED_PARAMETERS", + label: "Function Required Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_NAME", + label: "Function Name (metadata)", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "FUNCTION_DESCRIPTION", + label: "Function Description (metadata)", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + ], + }, + ], + "File Uploads": [ + { + name: "ZIP", + disable: false, + icon: ZIP, + fields: [ + { + fieldName: "ZIP", + label: "Zip File", + defaultValue: null, + options: { + component: "file-upload", + }, + disabled: true, + rules: { required: true }, + }, + ], + }, + ], + }, + VECTOR: { + Connections: [ + { + name: "Azure AI Search", + disable: false, + icon: MICROSOFT, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "VECTOR_TYPE", + label: "Type", + defaultValue: "AZURE_AI_SEARCH", + options: { + component: "text-field", + }, + disabled: true, + hidden: true, + rules: { required: true }, + }, + { + fieldName: "EMBEDDER_ENGINE_ID", + label: "Embedder", + defaultValue: "", + options: { + component: "select", + options: [], + pixel: `MyEngines ( metaKeys = [] , metaFilters = [{ "tag" : "embeddings" }] , engineTypes = [ 'MODEL' ] ) ;`, + optionDisplay: "database_name", + optionValue: "database_id", + }, + disabled: false, + rules: { required: true }, + helperText: + "The registered model engine responsible for converting input strings into fixed-size vectors, known as embeddings, capturing semantic information for downstream machine learning and natural language processing tasks.", + }, + { + fieldName: "INDEX_CLASSES", + label: "Index Classes", + defaultValue: "default", + options: { + component: "text-field", + }, + disabled: true, + hidden: true, + rules: { required: true }, + }, + { + fieldName: "CHUNKING_STRATEGY", + label: "Chunking Strategy", + defaultValue: "ALL", + options: { + component: "select", + options: [ + { + display: "Token", + value: "ALL", + }, + { + display: "Page by page", + value: "PAGE_BY_PAGE", + }, + { + display: "Markdown", + value: "MARKDOWN", + }, + ], + }, + disabled: false, + hidden: false, + rules: { required: true }, + displayRules: { + hideOtherFields: [ + { + fieldName: "CONTENT_LENGTH", + value: ["PAGE_BY_PAGE", "MARKDOWN"], + }, + ], + }, + }, + { + fieldName: "CONTENT_LENGTH", + label: "Content Length", + defaultValue: "512", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + helperText: + "The content length represents the upper limit of tokens within a chunk, as determined by the embedder's tokenizer.", + }, + { + fieldName: "CONTENT_OVERLAP", + label: "Content Overlap", + defaultValue: "20", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + helperText: + "The number of tokens from prior chunks that are carried over into the current chunk when processing content.", + }, + { + fieldName: "HOSTNAME", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "API_KEY", + label: "API Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "API_VERSION", + label: "API Version", + defaultValue: "2024-07-01", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, - { - fieldName: 'INDEX_NAME', - label: 'Index Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, pattern: { - value: /^[a-z0-9](?:[a-z0-9-]{0,126}[a-z0-9])?$/, - message: 'Index name must only contain lowercase letters, digits or dashes, cannot start or end with dashes and is limited to 128 characters', - }, - }, - }, + { + fieldName: "INDEX_NAME", + label: "Index Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[a-z0-9](?:[a-z0-9-]{0,126}[a-z0-9])?$/, + message: + "Index name must only contain lowercase letters, digits or dashes, cannot start or end with dashes and is limited to 128 characters", + }, + }, + }, - { - fieldName: 'DIMENSION_SIZE', - label: 'Embedding Dimension Size', - defaultValue: '1024', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - }, - { - fieldName: 'METHOD_NAME', - label: 'Method Name', - defaultValue: 'hnsw', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - advanced: true, - }, - { - fieldName: 'SPACE_TYPE', - label: 'Space Type', - defaultValue: 'l2', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - advanced: true, - }, - { - fieldName: 'INDEX_ENGINE', - label: 'Index Engine', - defaultValue: 'lucene', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - advanced: true, - }, - { - fieldName: 'EF_CONSTRUCTION', - label: 'EF Construction', - defaultValue: '128', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - advanced: true, - }, - { - fieldName: 'M_VALUE', - label: 'M Value', - defaultValue: '10', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^(4|5|6|7|8|9|10)$/, - message: - 'Permitted values are between 4 and 10', - }, - }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'EMBEDDINGS', - label: 'Embeddings', - defaultValue: null, - options: { - component: 'file-upload', - }, - disabled: true, - secondary: true, - rules: {}, - }, - { - fieldName: 'DISTANCE_METHOD', - label: 'Distance Method', - defaultValue: 'euclidean', - options: { - component: 'select', - options: [ - { - display: 'Cosine similarity', - value: 'cosine', - }, - { - display: 'Squared Euclidean (L2) distance', - value: 'euclidean', - }, - ], - }, - disabled: false, - rules: { required: false }, - advanced: true, - helperText: '', - }, - { - fieldName: 'RETAIN_EXTRACTED_TEXT', - label: 'Retain Extracted Text', - defaultValue: 'false', - options: { - component: 'select', - options: [ - { - display: 'False', - value: 'false', - }, - { - display: 'True', - value: 'true', - }, - ], - }, - disabled: false, - rules: { required: false }, - advanced: true, - }, - ], - }, - { - name: 'Chroma', - disable: false, - icon: CHROMADB, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'VECTOR_TYPE', - label: 'Type', - defaultValue: 'CHROMA', - options: { - component: 'text-field', - }, - hidden: true, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'DESCRIPTION', - label: 'Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'EMBEDDER_ENGINE_ID', - label: 'Embedder', - defaultValue: '', - options: { - component: 'select', - options: [], - pixel: `MyEngines ( metaKeys = [] , metaFilters = [{ "tag" : "embeddings" }] , engineTypes = [ 'MODEL' ] ) ;`, - optionDisplay: 'database_name', - optionValue: 'database_id', - }, - disabled: false, - rules: { required: true }, - helperText: - 'The registered model engine responsible for converting input strings into fixed-size vectors, known as embeddings, capturing semantic information for downstream machine learning and natural language processing tasks.', - }, - { - fieldName: 'INDEX_CLASSES', - label: 'Index Classes', - defaultValue: 'default', - options: { - component: 'text-field', - }, - hidden: true, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'CHUNKING_STRATEGY', - label: 'Chunking Strategy', - defaultValue: 'ALL', - options: { - component: 'select', - options: [ - { - display: 'Token', - value: 'ALL', - }, - { - display: 'Page by page', - value: 'PAGE_BY_PAGE', - }, - { - display: 'Markdown', - value: 'MARKDOWN', - }, - ], - }, - disabled: false, - hidden: false, - rules: { required: true }, - displayRules: { - hideOtherFields: [ - { - fieldName: 'CONTENT_LENGTH', - value: ['PAGE_BY_PAGE', 'MARKDOWN'], - }, - ], - }, - }, - { - fieldName: 'CONTENT_LENGTH', - label: 'Content Length', - defaultValue: '512', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - helperText: - "The content length represents the upper limit of tokens within a chunk, as determined by the embedder's tokenizer.", - }, - { - fieldName: 'CONTENT_OVERLAP', - label: 'Content Overlap', - defaultValue: '20', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - helperText: - 'The number of tokens from prior chunks that are carried over into the current chunk when processing content.', - }, - { - fieldName: 'HOSTNAME', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'API_KEY', - label: 'API Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CHROMA_COLLECTION_NAME', - label: 'Collection Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'true', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'EMBEDDINGS', - label: 'Embeddings', - defaultValue: null, - options: { - component: 'file-upload', - }, - disabled: true, - secondary: true, - rules: {}, - }, - { - fieldName: 'DISTANCE_METHOD', - label: 'Distance Method', - defaultValue: 'cosine', - options: { - component: 'select', - options: [ - { - display: 'Cosine Similarity', - value: 'cosine', - }, - { - display: 'Euclidean Distance', - value: 'l2', - }, - { - display: 'Inner Product', - value: 'ip', - }, - ], - }, - disabled: false, - rules: { required: false }, - advanced: true, - helperText: '', - }, - ], - }, - { - name: 'Elastic Search', - disable: false, - icon: ELASTIC_SEARCH, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'VECTOR_TYPE', - label: 'Type', - defaultValue: 'ELASTIC_SEARCH', - options: { - component: 'text-field', - }, - disabled: true, - hidden: true, - rules: { required: true }, - }, - { - fieldName: 'DESCRIPTION', - label: 'Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'EMBEDDER_ENGINE_ID', - label: 'Embedder', - defaultValue: '', - options: { - component: 'select', - options: [], - pixel: `MyEngines ( metaKeys = [] , metaFilters = [{ "tag" : "embeddings" }] , engineTypes = [ 'MODEL' ] ) ;`, - optionDisplay: 'database_name', - optionValue: 'database_id', - }, - disabled: false, - rules: { required: true }, - helperText: - 'The registered model engine responsible for converting input strings into fixed-size vectors, known as embeddings, capturing semantic information for downstream machine learning and natural language processing tasks.', - }, - { - fieldName: 'INDEX_CLASSES', - label: 'Index Classes', - defaultValue: 'default', - options: { - component: 'text-field', - }, - disabled: true, - hidden: true, - rules: { required: true }, - }, - { - fieldName: 'CHUNKING_STRATEGY', - label: 'Chunking Strategy', - defaultValue: 'ALL', - options: { - component: 'select', - options: [ - { - display: 'Token', - value: 'ALL', - }, - { - display: 'Page by page', - value: 'PAGE_BY_PAGE', - }, - { - display: 'Markdown', - value: 'MARKDOWN', - }, - ], - }, - disabled: false, - hidden: false, - rules: { required: true }, - displayRules: { - hideOtherFields: [ - { - fieldName: 'CONTENT_LENGTH', - value: ['PAGE_BY_PAGE', 'MARKDOWN'], - }, - ], - }, - }, - { - fieldName: 'CONTENT_LENGTH', - label: 'Content Length', - defaultValue: '512', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - helperText: - "The content length represents the upper limit of tokens within a chunk, as determined by the embedder's tokenizer.", - }, - { - fieldName: 'CONTENT_OVERLAP', - label: 'Content Overlap', - defaultValue: '20', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - helperText: - 'The number of tokens from prior chunks that are carried over into the current chunk when processing content.', - }, - { - fieldName: 'HOSTNAME', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'API_KEY', - label: 'API Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'API_KEY_ID', - label: 'API Key ID', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'INDEX_NAME', - label: 'Index Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'true', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'EMBEDDINGS', - label: 'Embeddings', - defaultValue: null, - options: { - component: 'file-upload', - }, - disabled: true, - secondary: true, - rules: {}, - }, - { - fieldName: 'DIMENSION_SIZE', - label: 'Embedding Dimension Size', - defaultValue: '-1', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: -1 }, - advanced: true, - }, - { - fieldName: 'DISTANCE_METHOD', - label: 'Distance Method', - defaultValue: 'cosine', - options: { - component: 'select', - options: [ - { - display: 'Cosine Similarity', - value: 'cosine', - }, - { - display: 'Euclidean Distance', - value: 'l2_norm', - }, - { - display: 'Dot Product', - value: 'dot_product', - }, - { - display: 'Max Inner Product', - value: 'max_inner_product', - }, - ], - }, - disabled: false, - rules: { required: false }, - advanced: true, - helperText: '', - }, - { - fieldName: 'METHOD_NAME', - label: 'Method Name', - defaultValue: 'hnsw', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - advanced: true, - }, - { - fieldName: 'SPACE_TYPE', - label: 'Space Type', - defaultValue: 'l2', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - advanced: true, - }, - { - fieldName: 'INDEX_ENGINE', - label: 'Index Engine', - defaultValue: 'lucene', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - advanced: true, - }, - { - fieldName: 'EF_CONSTRUCTION', - label: 'EF Construction', - defaultValue: '128', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - advanced: true, - }, - { - fieldName: 'M_VALUE', - label: 'M Value', - defaultValue: '24', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - advanced: true, - }, - ], - }, - { - name: 'FAISS', - disable: false, - icon: META, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'VECTOR_TYPE', - label: 'Type', - defaultValue: 'FAISS', - options: { - component: 'text-field', - }, - hidden: true, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'DESCRIPTION', - label: 'Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'EMBEDDER_ENGINE_ID', - label: 'Embedder', - defaultValue: '', - options: { - component: 'select', - options: [], - pixel: `MyEngines ( metaKeys = [] , metaFilters = [{ "tag" : "embeddings" }] , engineTypes = [ 'MODEL' ] ) ;`, - optionDisplay: 'database_name', - optionValue: 'database_id', - }, - disabled: false, - rules: { required: true }, - helperText: - 'The registered model engine responsible for converting input strings into fixed-size vectors, known as embeddings, capturing semantic information for downstream machine learning and natural language processing tasks.', - }, - { - fieldName: 'INDEX_CLASSES', - label: 'Index Classes', - defaultValue: 'default', - options: { - component: 'text-field', - }, - hidden: true, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'CHUNKING_STRATEGY', - label: 'Chunking Strategy', - defaultValue: 'ALL', - options: { - component: 'select', - options: [ - { - display: 'Token', - value: 'ALL', - }, - { - display: 'Page by page', - value: 'PAGE_BY_PAGE', - }, - { - display: 'Markdown', - value: 'MARKDOWN', - }, - ], - }, - disabled: false, - hidden: false, - rules: { required: true }, - displayRules: { - hideOtherFields: [ - { - fieldName: 'CONTENT_LENGTH', - value: ['PAGE_BY_PAGE', 'MARKDOWN'], - }, - ], - }, - }, - { - fieldName: 'CONTENT_LENGTH', - label: 'Content Length', - defaultValue: '512', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - helperText: - "The content length represents the upper limit of tokens within a chunk, as determined by the embedder's tokenizer.", - }, - { - fieldName: 'CONTENT_OVERLAP', - label: 'Content Overlap', - defaultValue: '20', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - helperText: - 'The number of tokens from prior chunks that are carried over into the current chunk when processing content.', - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'true', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'EMBEDDINGS', - label: 'Embeddings', - defaultValue: null, - options: { - component: 'file-upload', - }, - disabled: true, - secondary: true, - rules: {}, - }, - { - fieldName: 'DISTANCE_METHOD', - label: 'Distance Method', - defaultValue: 'Squared Euclidean (L2) distance', - options: { - component: 'select', - options: [ - { - display: 'Squared Euclidean (L2) distance', - value: 'Squared Euclidean (L2) distance', - }, - { - display: 'cosine similarity', - value: 'cosine similarity', - }, - ], - }, - disabled: false, - rules: { required: false }, - advanced: true, - helperText: '', - }, - ], - }, - { - name: 'Milvus', - disable: false, - icon: MILVUS, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'VECTOR_TYPE', - label: 'Type', - defaultValue: 'MILVUS', - options: { - component: 'text-field', - }, - disabled: true, - hidden: true, - rules: { required: true }, - }, - { - fieldName: 'DESCRIPTION', - label: 'Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'EMBEDDER_ENGINE_ID', - label: 'Embedder', - defaultValue: '', - options: { - component: 'select', - options: [], - pixel: `MyEngines ( metaKeys = [] , metaFilters = [{ "tag" : "embeddings" }] , engineTypes = [ 'MODEL' ] ) ;`, - optionDisplay: 'database_name', - optionValue: 'database_id', - }, - disabled: false, - rules: { required: true }, - helperText: - 'The registered model engine responsible for converting input strings into fixed-size vectors, known as embeddings, capturing semantic information for downstream machine learning and natural language processing tasks.', - }, - { - fieldName: 'INDEX_CLASSES', - label: 'Index Classes', - defaultValue: 'default', - options: { - component: 'text-field', - }, - disabled: true, - hidden: true, - rules: { required: true }, - }, - { - fieldName: 'CHUNKING_STRATEGY', - label: 'Chunking Strategy', - defaultValue: 'ALL', - options: { - component: 'select', - options: [ - { - display: 'Token', - value: 'ALL', - }, - { - display: 'Page by page', - value: 'PAGE_BY_PAGE', - }, - { - display: 'Markdown', - value: 'MARKDOWN', - }, - ], - }, - disabled: false, - hidden: false, - rules: { required: true }, - displayRules: { - hideOtherFields: [ - { - fieldName: 'CONTENT_LENGTH', - value: ['PAGE_BY_PAGE', 'MARKDOWN'], - }, - ], - }, - }, - { - fieldName: 'CONTENT_LENGTH', - label: 'Content Length', - defaultValue: '512', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - helperText: - "The content length represents the upper limit of tokens within a chunk, as determined by the embedder's tokenizer.", - }, - { - fieldName: 'CONTENT_OVERLAP', - label: 'Content Overlap', - defaultValue: '20', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - helperText: - 'The number of tokens from prior chunks that are carried over into the current chunk when processing content.', - }, - { - fieldName: 'HOSTNAME', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'DATABASE_NAME', - label: 'Database', - defaultValue: 'default_database', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - helperText: - 'Only update this value if you have a dedicated cluster', - }, - { - fieldName: 'COLLECTION_NAME', - label: 'Collection', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'API_KEY', - label: 'API Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'DIMENSION_SIZE', - label: 'Embedding Dimension Size', - defaultValue: '0', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 1 }, - advanced: false, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'true', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'EMBEDDINGS', - label: 'Embeddings', - defaultValue: null, - options: { - component: 'file-upload', - }, - disabled: true, - secondary: true, - rules: {}, - }, - { - fieldName: 'DISTANCE_METHOD', - label: 'Distance Method', - defaultValue: 'COSINE', - options: { - component: 'select', - options: [ - { - display: 'Cosine Similarity', - value: 'COSINE', - }, - { - display: 'Euclidean Distance', - value: 'L2', - }, - { - display: 'Inner Product', - value: 'ip ', - }, - ], - }, - disabled: false, - rules: { required: false }, - advanced: true, - helperText: '', - }, - { - fieldName: 'INDEX_TYPE', - label: 'Index Type', - defaultValue: 'HNSW', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - advanced: true, - }, - { - fieldName: 'EF_CONSTRUCTION', - label: 'EF Construction', - defaultValue: '128', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - advanced: true, - }, - { - fieldName: 'M_VALUE', - label: 'M Value', - defaultValue: '24', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - advanced: true, - }, - ], - }, - { - name: 'Open Search', - disable: false, - icon: OPEN_SEARCH, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'VECTOR_TYPE', - label: 'Type', - defaultValue: 'OPEN_SEARCH', - options: { - component: 'text-field', - }, - disabled: true, - hidden: true, - rules: { required: true }, - }, - { - fieldName: 'DESCRIPTION', - label: 'Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'EMBEDDER_ENGINE_ID', - label: 'Embedder', - defaultValue: '', - options: { - component: 'select', - options: [], - pixel: `MyEngines ( metaKeys = [] , metaFilters = [{ "tag" : "embeddings" }] , engineTypes = [ 'MODEL' ] ) ;`, - optionDisplay: 'database_name', - optionValue: 'database_id', - }, - disabled: false, - rules: { required: true }, - helperText: - 'The registered model engine responsible for converting input strings into fixed-size vectors, known as embeddings, capturing semantic information for downstream machine learning and natural language processing tasks.', - }, - { - fieldName: 'INDEX_CLASSES', - label: 'Index Classes', - defaultValue: 'default', - options: { - component: 'text-field', - }, - disabled: true, - hidden: true, - rules: { required: true }, - }, - { - fieldName: 'CHUNKING_STRATEGY', - label: 'Chunking Strategy', - defaultValue: 'ALL', - options: { - component: 'select', - options: [ - { - display: 'Token', - value: 'ALL', - }, - { - display: 'Page by page', - value: 'PAGE_BY_PAGE', - }, - { - display: 'Markdown', - value: 'MARKDOWN', - }, - ], - }, - disabled: false, - hidden: false, - rules: { required: true }, - displayRules: { - hideOtherFields: [ - { - fieldName: 'CONTENT_LENGTH', - value: ['PAGE_BY_PAGE', 'MARKDOWN'], - }, - ], - }, - }, - { - fieldName: 'CONTENT_LENGTH', - label: 'Content Length', - defaultValue: '512', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - helperText: - "The content length represents the upper limit of tokens within a chunk, as determined by the embedder's tokenizer.", - }, - { - fieldName: 'CONTENT_OVERLAP', - label: 'Content Overlap', - defaultValue: '20', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - helperText: - 'The number of tokens from prior chunks that are carried over into the current chunk when processing content.', - }, - { - fieldName: 'HOSTNAME', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'INDEX_NAME', - label: 'Index Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'DIMENSION_SIZE', - label: 'Embedding Dimension Size', - defaultValue: '0', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 1 }, - advanced: false, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'true', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'EMBEDDINGS', - label: 'Embeddings', - defaultValue: null, - options: { - component: 'file-upload', - }, - disabled: true, - secondary: true, - rules: {}, - }, - { - fieldName: 'DISTANCE_METHOD', - label: 'Distance Method', - defaultValue: 'cosinesimil', - options: { - component: 'select', - options: [ - { - display: 'Cosine Similarity', - value: 'cosinesimil', - }, - { - display: 'Euclidean Distance', - value: 'l2', - }, - { - display: 'Inner Product', - value: 'innerproduct ', - }, - ], - }, - disabled: false, - rules: { required: false }, - advanced: true, - helperText: '', - }, - { - fieldName: 'METHOD_NAME', - label: 'Method Name', - defaultValue: 'hnsw', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - advanced: true, - }, - { - fieldName: 'INDEX_ENGINE', - label: 'Index Engine', - defaultValue: 'lucene', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - advanced: true, - }, - { - fieldName: 'EF_CONSTRUCTION', - label: 'EF Construction', - defaultValue: '128', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - advanced: true, - }, - { - fieldName: 'M_VALUE', - label: 'M Value', - defaultValue: '24', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - advanced: true, - }, - ], - }, - { - name: 'PGVector', - disable: false, - icon: POSTGRES, - fields: [ - { - fieldName: 'VECTOR_TYPE', - label: 'Type', - defaultValue: 'PGVECTOR', - options: { - component: 'text-field', - }, - disabled: true, - hidden: true, - rules: { required: true }, - }, - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'POSTGRES', - options: { - component: 'text-field', - }, - disabled: true, - hidden: true, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DESCRIPTION', - label: 'Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '5432', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'database', - label: 'Database', - defaultValue: 'postgres', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: 'public', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'EMBEDDER_ENGINE_ID', - label: 'Embedder', - defaultValue: '', - options: { - component: 'select', - options: [], - pixel: `MyEngines ( metaKeys = [] , metaFilters = [{ "tag" : "embeddings" }] , engineTypes = [ 'MODEL' ] ) ;`, - optionDisplay: 'database_name', - optionValue: 'database_id', - }, - disabled: false, - rules: { required: true }, - helperText: - 'The registered model engine responsible for converting input strings into fixed-size vectors, known as embeddings, capturing semantic information for downstream machine learning and natural language processing tasks.', - }, - { - fieldName: 'PGVECTOR_TABLE_NAME', - label: 'PGVector Table Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CHUNKING_STRATEGY', - label: 'Chunking Strategy', - defaultValue: 'ALL', - options: { - component: 'select', - options: [ - { - display: 'Token', - value: 'ALL', - }, - { - display: 'Page by page', - value: 'PAGE_BY_PAGE', - }, - { - display: 'Markdown', - value: 'MARKDOWN', - }, - ], - }, - disabled: false, - hidden: false, - rules: { required: true }, - displayRules: { - hideOtherFields: [ - { - fieldName: 'CONTENT_LENGTH', - value: ['PAGE_BY_PAGE', 'MARKDOWN'], - }, - ], - }, - }, - { - fieldName: 'CONTENT_LENGTH', - label: 'Content Length', - defaultValue: '512', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - helperText: - "The content length represents the upper limit of tokens within a chunk, as determined by the embedder's tokenizer.", - }, - { - fieldName: 'CONTENT_OVERLAP', - label: 'Content Overlap', - defaultValue: '20', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - helperText: - 'The number of tokens from prior chunks that are carried over into the current chunk when processing content.', - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'true', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'EMBEDDINGS', - label: 'Embeddings', - defaultValue: null, - options: { - component: 'file-upload', - }, - disabled: true, - secondary: true, - rules: {}, - }, - { - fieldName: 'DISTANCE_METHOD', - label: 'Distance Method', - defaultValue: 'Squared Euclidean (L2) distance', - options: { - component: 'select', - options: [ - { - display: 'Squared Euclidean (L2) distance', - value: 'Squared Euclidean (L2) distance', - }, - { - display: 'cosine similarity', - value: 'cosine similarity', - }, - ], - }, - disabled: false, - rules: { required: false }, - advanced: true, - helperText: '', - }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, - { - name: 'Pinecone', - disable: false, - icon: PINECONE, - fields: [ - { - fieldName: 'NAME', - label: 'Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'VECTOR_TYPE', - label: 'Type', - defaultValue: 'PINECONE', - options: { - component: 'text-field', - }, - disabled: true, - hidden: true, - rules: { required: true }, - }, - { - fieldName: 'DESCRIPTION', - label: 'Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'EMBEDDER_ENGINE_ID', - label: 'Embedder', - defaultValue: '', - options: { - component: 'select', - options: [], - pixel: `MyEngines ( metaKeys = [] , metaFilters = [{ "tag" : "embeddings" }] , engineTypes = [ 'MODEL' ] ) ;`, - optionDisplay: 'database_name', - optionValue: 'database_id', - }, - disabled: false, - rules: { required: true }, - helperText: - 'The registered model engine responsible for converting input strings into fixed-size vectors, known as embeddings, capturing semantic information for downstream machine learning and natural language processing tasks.', - }, - { - fieldName: 'INDEX_CLASSES', - label: 'Index Classes', - defaultValue: 'default', - options: { - component: 'text-field', - }, - disabled: true, - hidden: true, - rules: { required: true }, - }, - { - fieldName: 'CHUNKING_STRATEGY', - label: 'Chunking Strategy', - defaultValue: 'ALL', - options: { - component: 'select', - options: [ - { - display: 'Token', - value: 'ALL', - }, - { - display: 'Page by page', - value: 'PAGE_BY_PAGE', - }, - { - display: 'Markdown', - value: 'MARKDOWN', - }, - ], - }, - disabled: false, - hidden: false, - rules: { required: true }, - displayRules: { - hideOtherFields: [ - { - fieldName: 'CONTENT_LENGTH', - value: ['PAGE_BY_PAGE', 'MARKDOWN'], - }, - ], - }, - }, - { - fieldName: 'CONTENT_LENGTH', - label: 'Content Length', - defaultValue: '512', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - helperText: - "The content length represents the upper limit of tokens within a chunk, as determined by the embedder's tokenizer.", - }, - { - fieldName: 'CONTENT_OVERLAP', - label: 'Content Overlap', - defaultValue: '20', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - helperText: - 'The number of tokens from prior chunks that are carried over into the current chunk when processing content.', - }, - { - fieldName: 'HOSTNAME', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'API_KEY', - label: 'API Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'NAMESPACE', - label: 'Namespace', - defaultValue: null, - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'true', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'EMBEDDINGS', - label: 'Embeddings', - defaultValue: null, - options: { - component: 'file-upload', - }, - disabled: true, - secondary: true, - rules: {}, - }, - // right now, below is not used - // BE does not create the index if it doesn't exist - // { - // fieldName: 'DISTANCE_METHOD', - // label: 'Distance Method', - // defaultValue: 'cosine', - // options: { - // component: 'select', - // options: [ - // { - // display: 'Euclidean Distance', - // value: 'euclidean', - // }, - // { - // display: 'Cosine Similarity', - // value: 'cosine', - // }, - // { - // display: 'Dot Product', - // value: 'dotproduct', - // }, - // ], - // }, - // disabled: false, - // rules: { required: false }, - // advanced: true, - // helperText: '', - // }, - ], - }, - { - name: 'Weaviate', - disable: false, - icon: WEVIATE, - fields: [ - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'VECTOR_TYPE', - label: 'Type', - defaultValue: 'WEAVIATE', - options: { - component: 'text-field', - }, - disabled: true, - hidden: true, - rules: { required: true }, - }, - { - fieldName: 'DESCRIPTION', - label: 'Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'EMBEDDER_ENGINE_ID', - label: 'Embedder', - defaultValue: '', - options: { - component: 'select', - options: [], - pixel: `MyEngines ( metaKeys = [] , metaFilters = [{ "tag" : "embeddings" }] , engineTypes = [ 'MODEL' ] ) ;`, - optionDisplay: 'database_name', - optionValue: 'database_id', - }, - disabled: false, - rules: { required: true }, - helperText: - 'The registered model engine responsible for converting input strings into fixed-size vectors, known as embeddings, capturing semantic information for downstream machine learning and natural language processing tasks.', - }, - { - fieldName: 'INDEX_CLASSES', - label: 'Index Classes', - defaultValue: 'default', - options: { - component: 'text-field', - }, - disabled: true, - hidden: true, - rules: { required: true }, - }, - { - fieldName: 'CHUNKING_STRATEGY', - label: 'Chunking Strategy', - defaultValue: 'ALL', - options: { - component: 'select', - options: [ - { - display: 'Token', - value: 'ALL', - }, - { - display: 'Page by page', - value: 'PAGE_BY_PAGE', - }, - { - display: 'Markdown', - value: 'MARKDOWN', - }, - ], - }, - disabled: false, - hidden: false, - rules: { required: true }, - displayRules: { - hideOtherFields: [ - { - fieldName: 'CONTENT_LENGTH', - value: ['PAGE_BY_PAGE', 'MARKDOWN'], - }, - ], - }, - }, - { - fieldName: 'CONTENT_LENGTH', - label: 'Content Length', - defaultValue: '512', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - helperText: - "The content length represents the upper limit of tokens within a chunk, as determined by the embedder's tokenizer.", - }, - { - fieldName: 'CONTENT_OVERLAP', - label: 'Content Overlap', - defaultValue: '20', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - helperText: - 'The number of tokens from prior chunks that are carried over into the current chunk when processing content.', - }, - { - fieldName: 'HOSTNAME', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'API_KEY', - label: 'API Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'WEAVIATE_CLASSNAME', - label: 'Weaviate Classname', - defaultValue: 'Vector_Table', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'AUTOCUT_DEFAULT', - label: 'Autocut default', - defaultValue: '1', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'KEEP_INPUT_OUTPUT', - label: 'Record Questions and Responses', - defaultValue: 'true', - options: { - component: 'select', - options: [ - { - display: 'true', - value: 'true', - }, - { - display: 'false', - value: 'false', - }, - ], - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'EMBEDDINGS', - label: 'Embeddings', - defaultValue: null, - options: { - component: 'file-upload', - }, - disabled: true, - secondary: true, - rules: {}, - }, - { - fieldName: 'DISTANCE_METHOD', - label: 'Distance Method', - defaultValue: 'Squared Euclidean (L2) distance', - options: { - component: 'select', - options: [ - { - display: 'Squared Euclidean (L2) distance', - value: 'Squared Euclidean (L2) distance', - }, - { - display: 'cosine similarity', - value: 'cosine similarity', - }, - ], - }, - disabled: false, - rules: { required: false }, - advanced: true, - helperText: '', - }, - ], - }, - ], - 'File Uploads': [ - { - name: 'ZIP', - disable: false, - icon: ZIP, - fields: [ - { - fieldName: 'ZIP', - label: 'Zip File', - defaultValue: null, - options: { - component: 'file-upload', - }, - disabled: true, - rules: { required: true }, - }, - ], - }, - ], - }, - DATABASE: { - 'File Uploads': [ - { - name: 'ZIP', - description: 'Drop a zip file', - disable: false, - icon: ZIP, - fields: [ - { - fieldName: 'ZIP', - label: 'Zip File', - defaultValue: null, - options: { - component: 'file-upload', - }, - disabled: true, - rules: { required: true }, - }, - ], - }, - { - name: 'CSV', - disable: true, - icon: CSV, - fields: [ - // baseUpload - // PredictDataTypes - { - fieldName: 'ZIP', - label: 'Zip File', - defaultValue: null, - options: { - component: 'file-upload', - }, - disabled: true, - rules: { required: true }, - }, - ], - }, - { - name: 'Excel', - disable: true, - icon: EXCEL, - fields: [], - }, - { - name: 'TSV', - disable: true, - icon: TSV, - fields: [], - }, - { - name: 'SQLite', - disable: true, - icon: SQLITE, - fields: [], - }, - { - name: 'H2', - disable: true, - icon: H2_DB, - fields: [], - }, - { - name: 'Neo4J', - disable: true, - icon: NEO4J, - fields: [], - }, - { - name: 'Tinker', - disable: true, - icon: TINKER, - fields: [], - }, - ], - Connections: [ - { - name: 'Aster', - disable: false, - icon: ASTER, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'ASTER_DB', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, - { - name: 'Athena', - disable: false, - icon: ATHENA, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'ATHENA', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'region', - label: 'Region', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'accessKey', - label: 'Access Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'secretKey', - label: 'Secret Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'output', - label: 'Output', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, + { + fieldName: "DIMENSION_SIZE", + label: "Embedding Dimension Size", + defaultValue: "1024", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + }, + { + fieldName: "METHOD_NAME", + label: "Method Name", + defaultValue: "hnsw", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + advanced: true, + }, + { + fieldName: "SPACE_TYPE", + label: "Space Type", + defaultValue: "l2", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + advanced: true, + }, + { + fieldName: "INDEX_ENGINE", + label: "Index Engine", + defaultValue: "lucene", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + advanced: true, + }, + { + fieldName: "EF_CONSTRUCTION", + label: "EF Construction", + defaultValue: "128", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + advanced: true, + }, + { + fieldName: "M_VALUE", + label: "M Value", + defaultValue: "10", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^(4|5|6|7|8|9|10)$/, + message: + "Permitted values are between 4 and 10", + }, + }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "EMBEDDINGS", + label: "Embeddings", + defaultValue: null, + options: { + component: "file-upload", + }, + disabled: true, + secondary: true, + rules: {}, + }, + { + fieldName: "DISTANCE_METHOD", + label: "Distance Method", + defaultValue: "euclidean", + options: { + component: "select", + options: [ + { + display: "Cosine similarity", + value: "cosine", + }, + { + display: "Squared Euclidean (L2) distance", + value: "euclidean", + }, + ], + }, + disabled: false, + rules: { required: false }, + advanced: true, + helperText: "", + }, + { + fieldName: "RETAIN_EXTRACTED_TEXT", + label: "Retain Extracted Text", + defaultValue: "false", + options: { + component: "select", + options: [ + { + display: "False", + value: "false", + }, + { + display: "True", + value: "true", + }, + ], + }, + disabled: false, + rules: { required: false }, + advanced: true, + }, + ], + }, + { + name: "Chroma", + disable: false, + icon: CHROMADB, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "VECTOR_TYPE", + label: "Type", + defaultValue: "CHROMA", + options: { + component: "text-field", + }, + hidden: true, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "DESCRIPTION", + label: "Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "EMBEDDER_ENGINE_ID", + label: "Embedder", + defaultValue: "", + options: { + component: "select", + options: [], + pixel: `MyEngines ( metaKeys = [] , metaFilters = [{ "tag" : "embeddings" }] , engineTypes = [ 'MODEL' ] ) ;`, + optionDisplay: "database_name", + optionValue: "database_id", + }, + disabled: false, + rules: { required: true }, + helperText: + "The registered model engine responsible for converting input strings into fixed-size vectors, known as embeddings, capturing semantic information for downstream machine learning and natural language processing tasks.", + }, + { + fieldName: "INDEX_CLASSES", + label: "Index Classes", + defaultValue: "default", + options: { + component: "text-field", + }, + hidden: true, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "CHUNKING_STRATEGY", + label: "Chunking Strategy", + defaultValue: "ALL", + options: { + component: "select", + options: [ + { + display: "Token", + value: "ALL", + }, + { + display: "Page by page", + value: "PAGE_BY_PAGE", + }, + { + display: "Markdown", + value: "MARKDOWN", + }, + ], + }, + disabled: false, + hidden: false, + rules: { required: true }, + displayRules: { + hideOtherFields: [ + { + fieldName: "CONTENT_LENGTH", + value: ["PAGE_BY_PAGE", "MARKDOWN"], + }, + ], + }, + }, + { + fieldName: "CONTENT_LENGTH", + label: "Content Length", + defaultValue: "512", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + helperText: + "The content length represents the upper limit of tokens within a chunk, as determined by the embedder's tokenizer.", + }, + { + fieldName: "CONTENT_OVERLAP", + label: "Content Overlap", + defaultValue: "20", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + helperText: + "The number of tokens from prior chunks that are carried over into the current chunk when processing content.", + }, + { + fieldName: "HOSTNAME", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "API_KEY", + label: "API Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CHROMA_COLLECTION_NAME", + label: "Collection Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "true", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "EMBEDDINGS", + label: "Embeddings", + defaultValue: null, + options: { + component: "file-upload", + }, + disabled: true, + secondary: true, + rules: {}, + }, + { + fieldName: "DISTANCE_METHOD", + label: "Distance Method", + defaultValue: "cosine", + options: { + component: "select", + options: [ + { + display: "Cosine Similarity", + value: "cosine", + }, + { + display: "Euclidean Distance", + value: "l2", + }, + { + display: "Inner Product", + value: "ip", + }, + ], + }, + disabled: false, + rules: { required: false }, + advanced: true, + helperText: "", + }, + ], + }, + { + name: "Elastic Search", + disable: false, + icon: ELASTIC_SEARCH, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "VECTOR_TYPE", + label: "Type", + defaultValue: "ELASTIC_SEARCH", + options: { + component: "text-field", + }, + disabled: true, + hidden: true, + rules: { required: true }, + }, + { + fieldName: "DESCRIPTION", + label: "Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "EMBEDDER_ENGINE_ID", + label: "Embedder", + defaultValue: "", + options: { + component: "select", + options: [], + pixel: `MyEngines ( metaKeys = [] , metaFilters = [{ "tag" : "embeddings" }] , engineTypes = [ 'MODEL' ] ) ;`, + optionDisplay: "database_name", + optionValue: "database_id", + }, + disabled: false, + rules: { required: true }, + helperText: + "The registered model engine responsible for converting input strings into fixed-size vectors, known as embeddings, capturing semantic information for downstream machine learning and natural language processing tasks.", + }, + { + fieldName: "INDEX_CLASSES", + label: "Index Classes", + defaultValue: "default", + options: { + component: "text-field", + }, + disabled: true, + hidden: true, + rules: { required: true }, + }, + { + fieldName: "CHUNKING_STRATEGY", + label: "Chunking Strategy", + defaultValue: "ALL", + options: { + component: "select", + options: [ + { + display: "Token", + value: "ALL", + }, + { + display: "Page by page", + value: "PAGE_BY_PAGE", + }, + { + display: "Markdown", + value: "MARKDOWN", + }, + ], + }, + disabled: false, + hidden: false, + rules: { required: true }, + displayRules: { + hideOtherFields: [ + { + fieldName: "CONTENT_LENGTH", + value: ["PAGE_BY_PAGE", "MARKDOWN"], + }, + ], + }, + }, + { + fieldName: "CONTENT_LENGTH", + label: "Content Length", + defaultValue: "512", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + helperText: + "The content length represents the upper limit of tokens within a chunk, as determined by the embedder's tokenizer.", + }, + { + fieldName: "CONTENT_OVERLAP", + label: "Content Overlap", + defaultValue: "20", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + helperText: + "The number of tokens from prior chunks that are carried over into the current chunk when processing content.", + }, + { + fieldName: "HOSTNAME", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "API_KEY", + label: "API Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "API_KEY_ID", + label: "API Key ID", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "INDEX_NAME", + label: "Index Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "true", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "EMBEDDINGS", + label: "Embeddings", + defaultValue: null, + options: { + component: "file-upload", + }, + disabled: true, + secondary: true, + rules: {}, + }, + { + fieldName: "DIMENSION_SIZE", + label: "Embedding Dimension Size", + defaultValue: "-1", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: -1 }, + advanced: true, + }, + { + fieldName: "DISTANCE_METHOD", + label: "Distance Method", + defaultValue: "cosine", + options: { + component: "select", + options: [ + { + display: "Cosine Similarity", + value: "cosine", + }, + { + display: "Euclidean Distance", + value: "l2_norm", + }, + { + display: "Dot Product", + value: "dot_product", + }, + { + display: "Max Inner Product", + value: "max_inner_product", + }, + ], + }, + disabled: false, + rules: { required: false }, + advanced: true, + helperText: "", + }, + { + fieldName: "METHOD_NAME", + label: "Method Name", + defaultValue: "hnsw", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + advanced: true, + }, + { + fieldName: "SPACE_TYPE", + label: "Space Type", + defaultValue: "l2", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + advanced: true, + }, + { + fieldName: "INDEX_ENGINE", + label: "Index Engine", + defaultValue: "lucene", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + advanced: true, + }, + { + fieldName: "EF_CONSTRUCTION", + label: "EF Construction", + defaultValue: "128", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + advanced: true, + }, + { + fieldName: "M_VALUE", + label: "M Value", + defaultValue: "24", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + advanced: true, + }, + ], + }, + { + name: "FAISS", + disable: false, + icon: META, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "VECTOR_TYPE", + label: "Type", + defaultValue: "FAISS", + options: { + component: "text-field", + }, + hidden: true, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "DESCRIPTION", + label: "Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "EMBEDDER_ENGINE_ID", + label: "Embedder", + defaultValue: "", + options: { + component: "select", + options: [], + pixel: `MyEngines ( metaKeys = [] , metaFilters = [{ "tag" : "embeddings" }] , engineTypes = [ 'MODEL' ] ) ;`, + optionDisplay: "database_name", + optionValue: "database_id", + }, + disabled: false, + rules: { required: true }, + helperText: + "The registered model engine responsible for converting input strings into fixed-size vectors, known as embeddings, capturing semantic information for downstream machine learning and natural language processing tasks.", + }, + { + fieldName: "INDEX_CLASSES", + label: "Index Classes", + defaultValue: "default", + options: { + component: "text-field", + }, + hidden: true, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "CHUNKING_STRATEGY", + label: "Chunking Strategy", + defaultValue: "ALL", + options: { + component: "select", + options: [ + { + display: "Token", + value: "ALL", + }, + { + display: "Page by page", + value: "PAGE_BY_PAGE", + }, + { + display: "Markdown", + value: "MARKDOWN", + }, + ], + }, + disabled: false, + hidden: false, + rules: { required: true }, + displayRules: { + hideOtherFields: [ + { + fieldName: "CONTENT_LENGTH", + value: ["PAGE_BY_PAGE", "MARKDOWN"], + }, + ], + }, + }, + { + fieldName: "CONTENT_LENGTH", + label: "Content Length", + defaultValue: "512", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + helperText: + "The content length represents the upper limit of tokens within a chunk, as determined by the embedder's tokenizer.", + }, + { + fieldName: "CONTENT_OVERLAP", + label: "Content Overlap", + defaultValue: "20", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + helperText: + "The number of tokens from prior chunks that are carried over into the current chunk when processing content.", + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "true", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "EMBEDDINGS", + label: "Embeddings", + defaultValue: null, + options: { + component: "file-upload", + }, + disabled: true, + secondary: true, + rules: {}, + }, + { + fieldName: "DISTANCE_METHOD", + label: "Distance Method", + defaultValue: "Squared Euclidean (L2) distance", + options: { + component: "select", + options: [ + { + display: "Squared Euclidean (L2) distance", + value: "Squared Euclidean (L2) distance", + }, + { + display: "cosine similarity", + value: "cosine similarity", + }, + ], + }, + disabled: false, + rules: { required: false }, + advanced: true, + helperText: "", + }, + ], + }, + { + name: "Milvus", + disable: false, + icon: MILVUS, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "VECTOR_TYPE", + label: "Type", + defaultValue: "MILVUS", + options: { + component: "text-field", + }, + disabled: true, + hidden: true, + rules: { required: true }, + }, + { + fieldName: "DESCRIPTION", + label: "Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "EMBEDDER_ENGINE_ID", + label: "Embedder", + defaultValue: "", + options: { + component: "select", + options: [], + pixel: `MyEngines ( metaKeys = [] , metaFilters = [{ "tag" : "embeddings" }] , engineTypes = [ 'MODEL' ] ) ;`, + optionDisplay: "database_name", + optionValue: "database_id", + }, + disabled: false, + rules: { required: true }, + helperText: + "The registered model engine responsible for converting input strings into fixed-size vectors, known as embeddings, capturing semantic information for downstream machine learning and natural language processing tasks.", + }, + { + fieldName: "INDEX_CLASSES", + label: "Index Classes", + defaultValue: "default", + options: { + component: "text-field", + }, + disabled: true, + hidden: true, + rules: { required: true }, + }, + { + fieldName: "CHUNKING_STRATEGY", + label: "Chunking Strategy", + defaultValue: "ALL", + options: { + component: "select", + options: [ + { + display: "Token", + value: "ALL", + }, + { + display: "Page by page", + value: "PAGE_BY_PAGE", + }, + { + display: "Markdown", + value: "MARKDOWN", + }, + ], + }, + disabled: false, + hidden: false, + rules: { required: true }, + displayRules: { + hideOtherFields: [ + { + fieldName: "CONTENT_LENGTH", + value: ["PAGE_BY_PAGE", "MARKDOWN"], + }, + ], + }, + }, + { + fieldName: "CONTENT_LENGTH", + label: "Content Length", + defaultValue: "512", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + helperText: + "The content length represents the upper limit of tokens within a chunk, as determined by the embedder's tokenizer.", + }, + { + fieldName: "CONTENT_OVERLAP", + label: "Content Overlap", + defaultValue: "20", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + helperText: + "The number of tokens from prior chunks that are carried over into the current chunk when processing content.", + }, + { + fieldName: "HOSTNAME", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "DATABASE_NAME", + label: "Database", + defaultValue: "default_database", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + helperText: + "Only update this value if you have a dedicated cluster", + }, + { + fieldName: "COLLECTION_NAME", + label: "Collection", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "API_KEY", + label: "API Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "DIMENSION_SIZE", + label: "Embedding Dimension Size", + defaultValue: "0", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 1 }, + advanced: false, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "true", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "EMBEDDINGS", + label: "Embeddings", + defaultValue: null, + options: { + component: "file-upload", + }, + disabled: true, + secondary: true, + rules: {}, + }, + { + fieldName: "DISTANCE_METHOD", + label: "Distance Method", + defaultValue: "COSINE", + options: { + component: "select", + options: [ + { + display: "Cosine Similarity", + value: "COSINE", + }, + { + display: "Euclidean Distance", + value: "L2", + }, + { + display: "Inner Product", + value: "ip ", + }, + ], + }, + disabled: false, + rules: { required: false }, + advanced: true, + helperText: "", + }, + { + fieldName: "INDEX_TYPE", + label: "Index Type", + defaultValue: "HNSW", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + advanced: true, + }, + { + fieldName: "EF_CONSTRUCTION", + label: "EF Construction", + defaultValue: "128", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + advanced: true, + }, + { + fieldName: "M_VALUE", + label: "M Value", + defaultValue: "24", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + advanced: true, + }, + ], + }, + { + name: "Open Search", + disable: false, + icon: OPEN_SEARCH, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "VECTOR_TYPE", + label: "Type", + defaultValue: "OPEN_SEARCH", + options: { + component: "text-field", + }, + disabled: true, + hidden: true, + rules: { required: true }, + }, + { + fieldName: "DESCRIPTION", + label: "Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "EMBEDDER_ENGINE_ID", + label: "Embedder", + defaultValue: "", + options: { + component: "select", + options: [], + pixel: `MyEngines ( metaKeys = [] , metaFilters = [{ "tag" : "embeddings" }] , engineTypes = [ 'MODEL' ] ) ;`, + optionDisplay: "database_name", + optionValue: "database_id", + }, + disabled: false, + rules: { required: true }, + helperText: + "The registered model engine responsible for converting input strings into fixed-size vectors, known as embeddings, capturing semantic information for downstream machine learning and natural language processing tasks.", + }, + { + fieldName: "INDEX_CLASSES", + label: "Index Classes", + defaultValue: "default", + options: { + component: "text-field", + }, + disabled: true, + hidden: true, + rules: { required: true }, + }, + { + fieldName: "CHUNKING_STRATEGY", + label: "Chunking Strategy", + defaultValue: "ALL", + options: { + component: "select", + options: [ + { + display: "Token", + value: "ALL", + }, + { + display: "Page by page", + value: "PAGE_BY_PAGE", + }, + { + display: "Markdown", + value: "MARKDOWN", + }, + ], + }, + disabled: false, + hidden: false, + rules: { required: true }, + displayRules: { + hideOtherFields: [ + { + fieldName: "CONTENT_LENGTH", + value: ["PAGE_BY_PAGE", "MARKDOWN"], + }, + ], + }, + }, + { + fieldName: "CONTENT_LENGTH", + label: "Content Length", + defaultValue: "512", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + helperText: + "The content length represents the upper limit of tokens within a chunk, as determined by the embedder's tokenizer.", + }, + { + fieldName: "CONTENT_OVERLAP", + label: "Content Overlap", + defaultValue: "20", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + helperText: + "The number of tokens from prior chunks that are carried over into the current chunk when processing content.", + }, + { + fieldName: "HOSTNAME", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "INDEX_NAME", + label: "Index Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "DIMENSION_SIZE", + label: "Embedding Dimension Size", + defaultValue: "0", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 1 }, + advanced: false, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "true", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "EMBEDDINGS", + label: "Embeddings", + defaultValue: null, + options: { + component: "file-upload", + }, + disabled: true, + secondary: true, + rules: {}, + }, + { + fieldName: "DISTANCE_METHOD", + label: "Distance Method", + defaultValue: "cosinesimil", + options: { + component: "select", + options: [ + { + display: "Cosine Similarity", + value: "cosinesimil", + }, + { + display: "Euclidean Distance", + value: "l2", + }, + { + display: "Inner Product", + value: "innerproduct ", + }, + ], + }, + disabled: false, + rules: { required: false }, + advanced: true, + helperText: "", + }, + { + fieldName: "METHOD_NAME", + label: "Method Name", + defaultValue: "hnsw", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + advanced: true, + }, + { + fieldName: "INDEX_ENGINE", + label: "Index Engine", + defaultValue: "lucene", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + advanced: true, + }, + { + fieldName: "EF_CONSTRUCTION", + label: "EF Construction", + defaultValue: "128", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + advanced: true, + }, + { + fieldName: "M_VALUE", + label: "M Value", + defaultValue: "24", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + advanced: true, + }, + ], + }, + { + name: "PGVector", + disable: false, + icon: POSTGRES, + fields: [ + { + fieldName: "VECTOR_TYPE", + label: "Type", + defaultValue: "PGVECTOR", + options: { + component: "text-field", + }, + disabled: true, + hidden: true, + rules: { required: true }, + }, + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "POSTGRES", + options: { + component: "text-field", + }, + disabled: true, + hidden: true, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DESCRIPTION", + label: "Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "5432", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "database", + label: "Database", + defaultValue: "postgres", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "public", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "EMBEDDER_ENGINE_ID", + label: "Embedder", + defaultValue: "", + options: { + component: "select", + options: [], + pixel: `MyEngines ( metaKeys = [] , metaFilters = [{ "tag" : "embeddings" }] , engineTypes = [ 'MODEL' ] ) ;`, + optionDisplay: "database_name", + optionValue: "database_id", + }, + disabled: false, + rules: { required: true }, + helperText: + "The registered model engine responsible for converting input strings into fixed-size vectors, known as embeddings, capturing semantic information for downstream machine learning and natural language processing tasks.", + }, + { + fieldName: "PGVECTOR_TABLE_NAME", + label: "PGVector Table Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CHUNKING_STRATEGY", + label: "Chunking Strategy", + defaultValue: "ALL", + options: { + component: "select", + options: [ + { + display: "Token", + value: "ALL", + }, + { + display: "Page by page", + value: "PAGE_BY_PAGE", + }, + { + display: "Markdown", + value: "MARKDOWN", + }, + ], + }, + disabled: false, + hidden: false, + rules: { required: true }, + displayRules: { + hideOtherFields: [ + { + fieldName: "CONTENT_LENGTH", + value: ["PAGE_BY_PAGE", "MARKDOWN"], + }, + ], + }, + }, + { + fieldName: "CONTENT_LENGTH", + label: "Content Length", + defaultValue: "512", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + helperText: + "The content length represents the upper limit of tokens within a chunk, as determined by the embedder's tokenizer.", + }, + { + fieldName: "CONTENT_OVERLAP", + label: "Content Overlap", + defaultValue: "20", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + helperText: + "The number of tokens from prior chunks that are carried over into the current chunk when processing content.", + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "true", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "EMBEDDINGS", + label: "Embeddings", + defaultValue: null, + options: { + component: "file-upload", + }, + disabled: true, + secondary: true, + rules: {}, + }, + { + fieldName: "DISTANCE_METHOD", + label: "Distance Method", + defaultValue: "Squared Euclidean (L2) distance", + options: { + component: "select", + options: [ + { + display: "Squared Euclidean (L2) distance", + value: "Squared Euclidean (L2) distance", + }, + { + display: "cosine similarity", + value: "cosine similarity", + }, + ], + }, + disabled: false, + rules: { required: false }, + advanced: true, + helperText: "", + }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, + { + name: "Pinecone", + disable: false, + icon: PINECONE, + fields: [ + { + fieldName: "NAME", + label: "Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "VECTOR_TYPE", + label: "Type", + defaultValue: "PINECONE", + options: { + component: "text-field", + }, + disabled: true, + hidden: true, + rules: { required: true }, + }, + { + fieldName: "DESCRIPTION", + label: "Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "EMBEDDER_ENGINE_ID", + label: "Embedder", + defaultValue: "", + options: { + component: "select", + options: [], + pixel: `MyEngines ( metaKeys = [] , metaFilters = [{ "tag" : "embeddings" }] , engineTypes = [ 'MODEL' ] ) ;`, + optionDisplay: "database_name", + optionValue: "database_id", + }, + disabled: false, + rules: { required: true }, + helperText: + "The registered model engine responsible for converting input strings into fixed-size vectors, known as embeddings, capturing semantic information for downstream machine learning and natural language processing tasks.", + }, + { + fieldName: "INDEX_CLASSES", + label: "Index Classes", + defaultValue: "default", + options: { + component: "text-field", + }, + disabled: true, + hidden: true, + rules: { required: true }, + }, + { + fieldName: "CHUNKING_STRATEGY", + label: "Chunking Strategy", + defaultValue: "ALL", + options: { + component: "select", + options: [ + { + display: "Token", + value: "ALL", + }, + { + display: "Page by page", + value: "PAGE_BY_PAGE", + }, + { + display: "Markdown", + value: "MARKDOWN", + }, + ], + }, + disabled: false, + hidden: false, + rules: { required: true }, + displayRules: { + hideOtherFields: [ + { + fieldName: "CONTENT_LENGTH", + value: ["PAGE_BY_PAGE", "MARKDOWN"], + }, + ], + }, + }, + { + fieldName: "CONTENT_LENGTH", + label: "Content Length", + defaultValue: "512", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + helperText: + "The content length represents the upper limit of tokens within a chunk, as determined by the embedder's tokenizer.", + }, + { + fieldName: "CONTENT_OVERLAP", + label: "Content Overlap", + defaultValue: "20", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + helperText: + "The number of tokens from prior chunks that are carried over into the current chunk when processing content.", + }, + { + fieldName: "HOSTNAME", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "API_KEY", + label: "API Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "NAMESPACE", + label: "Namespace", + defaultValue: null, + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "true", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "EMBEDDINGS", + label: "Embeddings", + defaultValue: null, + options: { + component: "file-upload", + }, + disabled: true, + secondary: true, + rules: {}, + }, + // right now, below is not used + // BE does not create the index if it doesn't exist + // { + // fieldName: 'DISTANCE_METHOD', + // label: 'Distance Method', + // defaultValue: 'cosine', + // options: { + // component: 'select', + // options: [ + // { + // display: 'Euclidean Distance', + // value: 'euclidean', + // }, + // { + // display: 'Cosine Similarity', + // value: 'cosine', + // }, + // { + // display: 'Dot Product', + // value: 'dotproduct', + // }, + // ], + // }, + // disabled: false, + // rules: { required: false }, + // advanced: true, + // helperText: '', + // }, + ], + }, + { + name: "Weaviate", + disable: false, + icon: WEVIATE, + fields: [ + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "VECTOR_TYPE", + label: "Type", + defaultValue: "WEAVIATE", + options: { + component: "text-field", + }, + disabled: true, + hidden: true, + rules: { required: true }, + }, + { + fieldName: "DESCRIPTION", + label: "Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "EMBEDDER_ENGINE_ID", + label: "Embedder", + defaultValue: "", + options: { + component: "select", + options: [], + pixel: `MyEngines ( metaKeys = [] , metaFilters = [{ "tag" : "embeddings" }] , engineTypes = [ 'MODEL' ] ) ;`, + optionDisplay: "database_name", + optionValue: "database_id", + }, + disabled: false, + rules: { required: true }, + helperText: + "The registered model engine responsible for converting input strings into fixed-size vectors, known as embeddings, capturing semantic information for downstream machine learning and natural language processing tasks.", + }, + { + fieldName: "INDEX_CLASSES", + label: "Index Classes", + defaultValue: "default", + options: { + component: "text-field", + }, + disabled: true, + hidden: true, + rules: { required: true }, + }, + { + fieldName: "CHUNKING_STRATEGY", + label: "Chunking Strategy", + defaultValue: "ALL", + options: { + component: "select", + options: [ + { + display: "Token", + value: "ALL", + }, + { + display: "Page by page", + value: "PAGE_BY_PAGE", + }, + { + display: "Markdown", + value: "MARKDOWN", + }, + ], + }, + disabled: false, + hidden: false, + rules: { required: true }, + displayRules: { + hideOtherFields: [ + { + fieldName: "CONTENT_LENGTH", + value: ["PAGE_BY_PAGE", "MARKDOWN"], + }, + ], + }, + }, + { + fieldName: "CONTENT_LENGTH", + label: "Content Length", + defaultValue: "512", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + helperText: + "The content length represents the upper limit of tokens within a chunk, as determined by the embedder's tokenizer.", + }, + { + fieldName: "CONTENT_OVERLAP", + label: "Content Overlap", + defaultValue: "20", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + helperText: + "The number of tokens from prior chunks that are carried over into the current chunk when processing content.", + }, + { + fieldName: "HOSTNAME", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "API_KEY", + label: "API Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "WEAVIATE_CLASSNAME", + label: "Weaviate Classname", + defaultValue: "Vector_Table", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "AUTOCUT_DEFAULT", + label: "Autocut default", + defaultValue: "1", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "KEEP_INPUT_OUTPUT", + label: "Record Questions and Responses", + defaultValue: "true", + options: { + component: "select", + options: [ + { + display: "true", + value: "true", + }, + { + display: "false", + value: "false", + }, + ], + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "EMBEDDINGS", + label: "Embeddings", + defaultValue: null, + options: { + component: "file-upload", + }, + disabled: true, + secondary: true, + rules: {}, + }, + { + fieldName: "DISTANCE_METHOD", + label: "Distance Method", + defaultValue: "Squared Euclidean (L2) distance", + options: { + component: "select", + options: [ + { + display: "Squared Euclidean (L2) distance", + value: "Squared Euclidean (L2) distance", + }, + { + display: "cosine similarity", + value: "cosine similarity", + }, + ], + }, + disabled: false, + rules: { required: false }, + advanced: true, + helperText: "", + }, + ], + }, + ], + "File Uploads": [ + { + name: "ZIP", + disable: false, + icon: ZIP, + fields: [ + { + fieldName: "ZIP", + label: "Zip File", + defaultValue: null, + options: { + component: "file-upload", + }, + disabled: true, + rules: { required: true }, + }, + ], + }, + ], + }, + DATABASE: { + "File Uploads": [ + { + name: "ZIP", + description: "Drop a zip file", + disable: false, + icon: ZIP, + fields: [ + { + fieldName: "ZIP", + label: "Zip File", + defaultValue: null, + options: { + component: "file-upload", + }, + disabled: true, + rules: { required: true }, + }, + ], + }, + { + name: "CSV", + disable: true, + icon: CSV, + fields: [ + // baseUpload + // PredictDataTypes + { + fieldName: "ZIP", + label: "Zip File", + defaultValue: null, + options: { + component: "file-upload", + }, + disabled: true, + rules: { required: true }, + }, + ], + }, + { + name: "Excel", + disable: true, + icon: EXCEL, + fields: [], + }, + { + name: "TSV", + disable: true, + icon: TSV, + fields: [], + }, + { + name: "SQLite", + disable: true, + icon: SQLITE, + fields: [], + }, + { + name: "H2", + disable: true, + icon: H2_DB, + fields: [], + }, + { + name: "Neo4J", + disable: true, + icon: NEO4J, + fields: [], + }, + { + name: "Tinker", + disable: true, + icon: TINKER, + fields: [], + }, + ], + Connections: [ + { + name: "Aster", + disable: false, + icon: ASTER, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "ASTER_DB", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, + { + name: "Athena", + disable: false, + icon: ATHENA, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "ATHENA", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "region", + label: "Region", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "accessKey", + label: "Access Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "secretKey", + label: "Secret Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "output", + label: "Output", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, - { - name: 'BigQuery', - disable: false, - icon: BIGQUERY, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'BIG_QUERY', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: 'https://www.googleapis.com/bigquery/v2', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'projectId', - label: 'Project', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'oauthType', - label: 'OAuth Type', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'oauthServiceAcctEmail', - label: 'OAuth Service Account', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'oauthPvtKeyPath', - label: 'OAuth Service Account Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - ], - }, - { - name: 'Cassandra', - disable: false, - icon: CASSANDRA, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'CASSANDRA', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '9042', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, + { + name: "BigQuery", + disable: false, + icon: BIGQUERY, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "BIG_QUERY", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "https://www.googleapis.com/bigquery/v2", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "projectId", + label: "Project", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "oauthType", + label: "OAuth Type", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "oauthServiceAcctEmail", + label: "OAuth Service Account", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "oauthPvtKeyPath", + label: "OAuth Service Account Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + ], + }, + { + name: "Cassandra", + disable: false, + icon: CASSANDRA, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "CASSANDRA", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "9042", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, - { - name: 'Clickhouse', - disable: false, - icon: CLICKHOUSE, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'CLICKHOUSE', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '9042', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'database', - label: 'Database', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, + { + name: "Clickhouse", + disable: false, + icon: CLICKHOUSE, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "CLICKHOUSE", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "9042", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "database", + label: "Database", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, - { - name: 'DATABRICKS', - disable: false, - icon: DATABRICKS, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'DATABRICKS', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'httpPath', - label: 'HTTP Path', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'UID', - label: 'UID', - defaultValue: 'token', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'PWD', - label: 'Personal Access Token', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'database', - label: 'Database', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, + { + name: "DATABRICKS", + disable: false, + icon: DATABRICKS, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "DATABRICKS", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "httpPath", + label: "HTTP Path", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "UID", + label: "UID", + defaultValue: "token", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "PWD", + label: "Personal Access Token", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "database", + label: "Database", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, - { - name: 'DataStax', - disable: true, - icon: DATASTAX, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'DATASTAX', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'graph', - label: 'GRAPH', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: 'token', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: 'token', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - ], - }, - { - name: 'DB2', - disable: false, - icon: DB2, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'DB2', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '446', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, + { + name: "DataStax", + disable: true, + icon: DATASTAX, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "DATASTAX", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "graph", + label: "GRAPH", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "token", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "token", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + ], + }, + { + name: "DB2", + disable: false, + icon: DB2, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "DB2", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "446", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, - { - name: 'Derby', - disable: false, - icon: DERBY, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'DERBY', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '1527', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, + { + name: "Derby", + disable: false, + icon: DERBY, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "DERBY", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "1527", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, - { - name: 'Elastic Search', - disable: false, - icon: ELASTIC_SEARCH, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'ELASTIC_SEARCH', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '9200', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'httpType', - label: 'HTTP Type', - defaultValue: 'https', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - ], - }, - { - name: 'H2', - disable: false, - icon: H2_DB, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'H2_DB', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '1000', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, + { + name: "Elastic Search", + disable: false, + icon: ELASTIC_SEARCH, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "ELASTIC_SEARCH", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "9200", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "httpType", + label: "HTTP Type", + defaultValue: "https", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + ], + }, + { + name: "H2", + disable: false, + icon: H2_DB, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "H2_DB", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "1000", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, - { - name: 'Hive', - disable: false, - icon: HIVE, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'HIVE', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '1000', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, + { + name: "Hive", + disable: false, + icon: HIVE, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "HIVE", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "1000", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, - { - name: 'Impala', - disable: false, - icon: IMPALA, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'IMPALA', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '21050', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, + { + name: "Impala", + disable: false, + icon: IMPALA, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "IMPALA", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "21050", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, - { - name: 'MariaDB', - disable: false, - icon: MARIA_DB, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'MARIA_DB', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '3306', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, + { + name: "MariaDB", + disable: false, + icon: MARIA_DB, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "MARIA_DB", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "3306", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, - { - name: 'MySQL', - disable: false, - icon: MYSQL, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'MYSQL', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '3306', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, - { - name: 'Open Search', - disable: false, - icon: OPEN_SEARCH, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'OPEN_SEARCH', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '9200', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'httpPath', - label: 'HTTP Path', - defaultValue: 'https', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - ], - }, - { - name: 'Oracle', - disable: false, - icon: ORACLE, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'ORACLE', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'service', - label: 'SID Service', - defaultValue: '1521', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, + { + name: "MySQL", + disable: false, + icon: MYSQL, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "MYSQL", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "3306", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, + { + name: "Open Search", + disable: false, + icon: OPEN_SEARCH, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "OPEN_SEARCH", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "9200", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "httpPath", + label: "HTTP Path", + defaultValue: "https", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + ], + }, + { + name: "Oracle", + disable: false, + icon: ORACLE, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "ORACLE", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "service", + label: "SID Service", + defaultValue: "1521", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, - { - name: 'Phoenix', - disable: false, - icon: PHOENIX, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'PHOENIX', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '8765', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, + { + name: "Phoenix", + disable: false, + icon: PHOENIX, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "PHOENIX", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "8765", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, - { - name: 'Postgres', - disable: false, - icon: POSTGRES, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'POSTGRES', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '5432', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'database', - label: 'Database', - defaultValue: 'postgres', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: 'public', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, + { + name: "Postgres", + disable: false, + icon: POSTGRES, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "POSTGRES", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "5432", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "database", + label: "Database", + defaultValue: "postgres", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "public", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, - { - name: 'Redshift', - disable: false, - icon: REDSHIFT, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'REDSHIFT', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '5439', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'database', - label: 'Database', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, + { + name: "Redshift", + disable: false, + icon: REDSHIFT, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "REDSHIFT", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "5439", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "database", + label: "Database", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, - { - name: 'SAP Hana', - disable: false, - icon: SAP_HANA, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'SAP_HANA', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]" ) ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '30015', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, + { + name: "SAP Hana", + disable: false, + icon: SAP_HANA, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "SAP_HANA", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]" ) ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "30015", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, - { - name: 'SEMOSS', - disable: false, - icon: SEMOSS, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'SEMOSS', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '443', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'project', - label: 'Project Id', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'insight', - label: 'Insight Id', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'endpoint', - label: 'Endpoint', - defaultValue: 'Monolith', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'protocol', - label: 'Protocol', - defaultValue: 'https', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'sub_url', - label: 'Sub URL', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, + { + name: "SEMOSS", + disable: false, + icon: SEMOSS, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "SEMOSS", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "443", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "project", + label: "Project Id", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "insight", + label: "Insight Id", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "endpoint", + label: "Endpoint", + defaultValue: "Monolith", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "protocol", + label: "Protocol", + defaultValue: "https", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "sub_url", + label: "Sub URL", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, - { - name: 'Snowflake', - disable: false, - icon: SNOWFLAKE, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'SNOWFLAKE', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '443', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'warehouse', - label: 'Warehouse', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'role', - label: 'Role', - defaultValue: 'PUBLIC', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'database', - label: 'Database', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, + { + name: "Snowflake", + disable: false, + icon: SNOWFLAKE, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "SNOWFLAKE", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "443", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "warehouse", + label: "Warehouse", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "role", + label: "Role", + defaultValue: "PUBLIC", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "database", + label: "Database", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, - { - name: 'SQL Server', - disable: false, - icon: SQL_SERVER, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'SQL_SERVER', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '1433', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'database', - label: 'Database', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: 'dbo', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, + { + name: "SQL Server", + disable: false, + icon: SQL_SERVER, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "SQL_SERVER", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "1433", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "database", + label: "Database", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "dbo", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, - { - name: 'SQLITE', - disable: false, - icon: SQLITE, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'SQLITE', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '1000', - options: { - component: 'number', - }, - disabled: false, - rules: { required: false, min: 0 }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, + { + name: "SQLITE", + disable: false, + icon: SQLITE, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "SQLITE", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "1000", + options: { + component: "number", + }, + disabled: false, + rules: { required: false, min: 0 }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, - { - name: 'Teradata', - disable: false, - icon: TERADATA, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'TERADATA', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'database', - label: 'Database', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, + { + name: "Teradata", + disable: false, + icon: TERADATA, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "TERADATA", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "database", + label: "Database", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, - { - name: 'Tibco', - disable: false, - icon: TIBCO, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'TIBCO', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '1433', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, + { + name: "Tibco", + disable: false, + icon: TIBCO, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "TIBCO", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "1433", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, - { - name: 'Trino', - disable: false, - icon: TRINO, - fields: [ - { - fieldName: 'RDBMS_TYPE', - label: 'Driver Name', - defaultValue: 'TRINO', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - hidden: true, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'DATABASE_DESCRIPTION', - label: 'Database Description', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'DATABASE_TAGS', - label: 'Tags', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'hostname', - label: 'Host Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'port', - label: 'Port', - defaultValue: '1433', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - }, - { - fieldName: 'catalog', - label: 'Catalog', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'schema', - label: 'Schema', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'additional', - label: 'Additional Parameters', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'CONNECTION_URL', - label: 'JDBC Url', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'FETCH_SIZE', - label: 'Fetch Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'CONNECTION_TIMEOUT', - label: 'Connection Timeout', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'USE_CONNECTION_POOLING', - label: 'Use Connection Pooling', - defaultValue: false, - rules: { required: false }, - options: { - component: 'checkbox', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MIN_SIZE', - label: 'Pool Min Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - { - fieldName: 'POOL_MAX_SIZE', - label: 'Pool Max Size', - defaultValue: '', - rules: { required: false, min: 0 }, - options: { - component: 'number', - }, - disabled: false, - advanced: true, - }, - ], - }, - ], - }, - STORAGE: { - Storage: [ - { - name: 'Amazon S3', - disable: false, - icon: AMAZON_S3, - fields: [ - { - fieldName: 'STORAGE_TYPE', - label: 'Storage Type', - defaultValue: 'AMAZON_S3', - hidden: true, - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'S3_REGION', - label: 'Region', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'S3_BUCKET', - label: 'Bucket', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'S3_ACCESS_KEY', - label: 'Access Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - { - fieldName: 'S3_SECRET_KEY', - label: 'Secret Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - ], - }, - { - name: 'CEPH', - disable: false, - icon: CEPH, - fields: [ - { - fieldName: 'STORAGE_TYPE', - label: 'Storage Type', - defaultValue: 'CEPH', - hidden: true, - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'CEPH_ACCESS_KEY', - label: 'Access Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CEPH_SECRET_KEY', - label: 'Secret Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CEPH_ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'CEPH_BUCKET', - label: 'Root Bucket Path', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - ], - }, - { - name: 'Dreamhost', - disable: true, - icon: DREAMHOST, - fields: [ - { - fieldName: 'STORAGE_TYPE', - label: 'Storage Type', - defaultValue: '', - hidden: true, - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'S3_REGION', - label: 'S3 Region', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'S3_ACCESS_KEY', - label: 'S3 Access Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'S3_SECRET_KEY', - label: 'S3 Secret Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'S3_ENDPOINT', - label: 'S3 Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - ], - }, - { - name: 'Dropbox', - disable: false, - icon: DROPBOX, - fields: [ - { - fieldName: 'STORAGE_TYPE', - label: 'Storage Type', - defaultValue: 'DROPBOX', - hidden: true, - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'S3_REGION', - label: 'S3 Region', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'S3_ACCESS_KEY', - label: 'S3 Access Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'S3_SECRET_KEY', - label: 'S3 Secret Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'S3_ENDPOINT', - label: 'S3 Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - ], - }, - { - name: 'Google Cloud', - disable: false, - icon: GOOGLE_CLOUD, - fields: [ - { - fieldName: 'STORAGE_TYPE', - label: 'Storage Type', - defaultValue: 'GOOGLE_CLOUD_STORAGE', - hidden: true, - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'GCS_REGION', - label: 'Region', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'GCS_SERVICE_ACCOUNT_FILE', - label: 'Service Account File', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'GCS_BUCKET', - label: 'Bucket', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - ], - }, - { - name: 'Google Drive', - disable: true, - icon: GOOGLE_DRIVE, - fields: [], - }, - { - name: 'Local File System', - disable: false, - icon: LOCAL_FILE_SYSTEM, - fields: [ - { - fieldName: 'STORAGE_TYPE', - label: 'Storage Type', - defaultValue: 'LOCAL_FILE_SYSTEM', - hidden: true, - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'PATH_PREFIX', - label: 'Local Path Prefix', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - ], - }, - { - name: 'Microsoft Azure Blob Storage', - disable: false, - icon: AZURE_BLOB, - fields: [ - { - fieldName: 'STORAGE_TYPE', - label: 'Storage Type', - defaultValue: 'MICROSOFT_AZURE_BLOB_STORAGE', - hidden: true, - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'AZ_ACCOUNT_NAME', - label: 'Account Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'AZ_PRIMARY_KEY', - label: 'Primary Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'AZ_CONN_STRING', - label: 'Connection String', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'AZ_GENERATE_DYNAMIC_SAS', - label: 'Generate Dynamic SAS', - defaultValue: 'false', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - ], - }, - { - name: 'Microsoft OneDrive', - disable: true, - icon: ONEDRIVE, - fields: [ - { - fieldName: 'STORAGE_TYPE', - label: 'Storage Type', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'S3_REGION', - label: 'S3 Region', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'S3_ACCESS_KEY', - label: 'S3 Access Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'S3_SECRET_KEY', - label: 'S3 Secret Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'S3_ENDPOINT', - label: 'S3 Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - ], - }, - { - name: 'MinIO', - disable: false, - icon: MINIO, - fields: [ - { - fieldName: 'STORAGE_TYPE', - label: 'Storage Type', - defaultValue: 'MINIO', - hidden: true, - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'MINIO_REGION', - label: 'Region', - defaultValue: 'us-east-1', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MINIO_ACCESS_KEY', - label: 'Access Key', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MINIO_SECRET_KEY', - label: 'Secret Key', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MINIO_ENDPOINT', - label: 'Endpoint', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'MINIO_BUCKET', - label: 'Root Bucket Path', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - ], - }, - { - name: 'Network File System', - disable: false, - icon: NETWORK_FILE_SYSTEM, - fields: [ - { - fieldName: 'STORAGE_TYPE', - label: 'Storage Type', - defaultValue: 'SMB_CIFS', - hidden: true, - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'NETWORK_DOMAIN', - label: 'Network Domain', - defaultValue: 'US', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'PATH_PREFIX', - label: 'Network Path Prefix', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: false }, - }, - ], - }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, + { + name: "Trino", + disable: false, + icon: TRINO, + fields: [ + { + fieldName: "RDBMS_TYPE", + label: "Driver Name", + defaultValue: "TRINO", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + hidden: true, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "DATABASE_DESCRIPTION", + label: "Database Description", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "DATABASE_TAGS", + label: "Tags", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "hostname", + label: "Host Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "port", + label: "Port", + defaultValue: "1433", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + }, + { + fieldName: "catalog", + label: "Catalog", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "schema", + label: "Schema", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "additional", + label: "Additional Parameters", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "CONNECTION_URL", + label: "JDBC Url", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "FETCH_SIZE", + label: "Fetch Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "CONNECTION_TIMEOUT", + label: "Connection Timeout", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "USE_CONNECTION_POOLING", + label: "Use Connection Pooling", + defaultValue: false, + rules: { required: false }, + options: { + component: "checkbox", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MIN_SIZE", + label: "Pool Min Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + { + fieldName: "POOL_MAX_SIZE", + label: "Pool Max Size", + defaultValue: "", + rules: { required: false, min: 0 }, + options: { + component: "number", + }, + disabled: false, + advanced: true, + }, + ], + }, + ], + }, + STORAGE: { + Storage: [ + { + name: "Amazon S3", + disable: false, + icon: AMAZON_S3, + fields: [ + { + fieldName: "STORAGE_TYPE", + label: "Storage Type", + defaultValue: "AMAZON_S3", + hidden: true, + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "S3_REGION", + label: "Region", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "S3_BUCKET", + label: "Bucket", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "S3_ACCESS_KEY", + label: "Access Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + { + fieldName: "S3_SECRET_KEY", + label: "Secret Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + ], + }, + { + name: "CEPH", + disable: false, + icon: CEPH, + fields: [ + { + fieldName: "STORAGE_TYPE", + label: "Storage Type", + defaultValue: "CEPH", + hidden: true, + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "CEPH_ACCESS_KEY", + label: "Access Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CEPH_SECRET_KEY", + label: "Secret Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CEPH_ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "CEPH_BUCKET", + label: "Root Bucket Path", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + ], + }, + { + name: "Dreamhost", + disable: true, + icon: DREAMHOST, + fields: [ + { + fieldName: "STORAGE_TYPE", + label: "Storage Type", + defaultValue: "", + hidden: true, + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "S3_REGION", + label: "S3 Region", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "S3_ACCESS_KEY", + label: "S3 Access Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "S3_SECRET_KEY", + label: "S3 Secret Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "S3_ENDPOINT", + label: "S3 Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + ], + }, + { + name: "Dropbox", + disable: false, + icon: DROPBOX, + fields: [ + { + fieldName: "STORAGE_TYPE", + label: "Storage Type", + defaultValue: "DROPBOX", + hidden: true, + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "S3_REGION", + label: "S3 Region", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "S3_ACCESS_KEY", + label: "S3 Access Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "S3_SECRET_KEY", + label: "S3 Secret Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "S3_ENDPOINT", + label: "S3 Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + ], + }, + { + name: "Google Cloud", + disable: false, + icon: GOOGLE_CLOUD, + fields: [ + { + fieldName: "STORAGE_TYPE", + label: "Storage Type", + defaultValue: "GOOGLE_CLOUD_STORAGE", + hidden: true, + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "GCS_REGION", + label: "Region", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "GCS_SERVICE_ACCOUNT_FILE", + label: "Service Account File", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "GCS_BUCKET", + label: "Bucket", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + ], + }, + { + name: "Google Drive", + disable: true, + icon: GOOGLE_DRIVE, + fields: [], + }, + { + name: "Local File System", + disable: false, + icon: LOCAL_FILE_SYSTEM, + fields: [ + { + fieldName: "STORAGE_TYPE", + label: "Storage Type", + defaultValue: "LOCAL_FILE_SYSTEM", + hidden: true, + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "PATH_PREFIX", + label: "Local Path Prefix", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + ], + }, + { + name: "Microsoft Azure Blob Storage", + disable: false, + icon: AZURE_BLOB, + fields: [ + { + fieldName: "STORAGE_TYPE", + label: "Storage Type", + defaultValue: "MICROSOFT_AZURE_BLOB_STORAGE", + hidden: true, + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "AZ_ACCOUNT_NAME", + label: "Account Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "AZ_PRIMARY_KEY", + label: "Primary Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "AZ_CONN_STRING", + label: "Connection String", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "AZ_GENERATE_DYNAMIC_SAS", + label: "Generate Dynamic SAS", + defaultValue: "false", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + ], + }, + { + name: "Microsoft OneDrive", + disable: true, + icon: ONEDRIVE, + fields: [ + { + fieldName: "STORAGE_TYPE", + label: "Storage Type", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "S3_REGION", + label: "S3 Region", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "S3_ACCESS_KEY", + label: "S3 Access Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "S3_SECRET_KEY", + label: "S3 Secret Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "S3_ENDPOINT", + label: "S3 Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + ], + }, + { + name: "MinIO", + disable: false, + icon: MINIO, + fields: [ + { + fieldName: "STORAGE_TYPE", + label: "Storage Type", + defaultValue: "MINIO", + hidden: true, + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "MINIO_REGION", + label: "Region", + defaultValue: "us-east-1", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MINIO_ACCESS_KEY", + label: "Access Key", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MINIO_SECRET_KEY", + label: "Secret Key", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MINIO_ENDPOINT", + label: "Endpoint", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "MINIO_BUCKET", + label: "Root Bucket Path", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + ], + }, + { + name: "Network File System", + disable: false, + icon: NETWORK_FILE_SYSTEM, + fields: [ + { + fieldName: "STORAGE_TYPE", + label: "Storage Type", + defaultValue: "SMB_CIFS", + hidden: true, + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "NETWORK_DOMAIN", + label: "Network Domain", + defaultValue: "US", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "PATH_PREFIX", + label: "Network Path Prefix", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: false }, + }, + ], + }, - { - name: 'SFTP', - disable: false, - icon: SFTP, - fields: [ - { - fieldName: 'STORAGE_TYPE', - label: 'Storage Type', - defaultValue: 'SFTP', - hidden: true, - options: { - component: 'text-field', - }, - disabled: true, - rules: { required: true }, - }, - { - fieldName: 'NAME', - label: 'Catalog Name', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { - required: true, - pattern: { - value: /^[\w\-\s]+$/, - message: - 'Catalog names can only contain alphanumeric characters and dashes.', - }, - custom: { - value: 'CheckEngineName ( "[VALUE]") ;', - message: - 'This Catalog name has already been used, please try another.', - }, - }, - }, - { - fieldName: 'HOSTNAME', - label: 'Host', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'PORT', - label: 'Port', - defaultValue: '22', - options: { - component: 'number', - }, - disabled: false, - rules: { required: true, min: 0 }, - }, - { - fieldName: 'USERNAME', - label: 'Username', - defaultValue: '', - options: { - component: 'text-field', - }, - disabled: false, - rules: { required: true }, - }, - { - fieldName: 'PASSWORD', - label: 'Password', - defaultValue: '', - options: { - component: 'password', - }, - disabled: false, - rules: { required: false }, - }, - ], - }, - ], - 'File Uploads': [ - { - name: 'ZIP', - disable: false, - icon: ZIP, - fields: [ - { - fieldName: 'ZIP', - label: 'Zip File', - defaultValue: null, - options: { - component: 'file-upload', - }, - disabled: true, - rules: { required: true }, - }, - ], - }, - ], - }, + { + name: "SFTP", + disable: false, + icon: SFTP, + fields: [ + { + fieldName: "STORAGE_TYPE", + label: "Storage Type", + defaultValue: "SFTP", + hidden: true, + options: { + component: "text-field", + }, + disabled: true, + rules: { required: true }, + }, + { + fieldName: "NAME", + label: "Catalog Name", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { + required: true, + pattern: { + value: /^[\w\-\s]+$/, + message: + "Catalog names can only contain alphanumeric characters and dashes.", + }, + custom: { + value: 'CheckEngineName ( "[VALUE]") ;', + message: + "This Catalog name has already been used, please try another.", + }, + }, + }, + { + fieldName: "HOSTNAME", + label: "Host", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "PORT", + label: "Port", + defaultValue: "22", + options: { + component: "number", + }, + disabled: false, + rules: { required: true, min: 0 }, + }, + { + fieldName: "USERNAME", + label: "Username", + defaultValue: "", + options: { + component: "text-field", + }, + disabled: false, + rules: { required: true }, + }, + { + fieldName: "PASSWORD", + label: "Password", + defaultValue: "", + options: { + component: "password", + }, + disabled: false, + rules: { required: false }, + }, + ], + }, + ], + "File Uploads": [ + { + name: "ZIP", + disable: false, + icon: ZIP, + fields: [ + { + fieldName: "ZIP", + label: "Zip File", + defaultValue: null, + options: { + component: "file-upload", + }, + disabled: true, + rules: { required: true }, + }, + ], + }, + ], + }, }; export const ENGINE_IMAGES = { - MODEL: [ - { - name: 'OPEN_AI', - icon: OPEN_AI, - }, - { - name: 'GPT-3.5', - icon: OPEN_AI, - }, - { - name: 'GPT-4', - icon: OPEN_AI, - }, - { - name: 'Text-Davinci', - icon: OPEN_AI, - }, - { - name: 'DALL E', - icon: OPEN_AI, - }, - { - name: 'Azure Open AI', + MODEL: [ + { + name: "OPEN_AI", + icon: OPEN_AI, + }, + { + name: "GPT-3.5", + icon: OPEN_AI, + }, + { + name: "GPT-4", + icon: OPEN_AI, + }, + { + name: "Text-Davinci", + icon: OPEN_AI, + }, + { + name: "DALL E", + icon: OPEN_AI, + }, + { + name: "Azure Open AI", - icon: AZURE_OPEN_AI, - }, - { - name: 'Claude', - icon: CLAUDE, - }, - { - name: 'Palm Bison', - icon: VERTEX, - }, - { - name: 'Palm Chat Bison', - icon: VERTEX, - }, - { - name: 'Palm Code Bison', - icon: VERTEX, - }, - { - name: 'Wizard 13B', - icon: BRAIN, - }, - { - name: 'Llama2 7B', - icon: META, - }, - { - name: 'Llama2 13B', - icon: META, - }, - { - name: 'Llama2 70B', - icon: META, - }, - { - name: 'Falcon', - icon: FALCON, - }, - { - name: 'StableBeluga2', - icon: BRAIN, - }, - { - name: 'Guanaco', - icon: BRAIN, - }, - { - name: 'Vicuna', - icon: VICUNA, - }, - { - name: 'Mosaic ML', - icon: MOSAIC, - }, - { - name: 'Dolly', - icon: DOLLY, - }, - { - name: 'Replit code model – 3b', - icon: REPLIT, - }, - { - name: 'Flan T5 Large', - icon: FLAN, - }, - { - name: 'Flan T5 XXL', - icon: FLAN, - }, - { - name: 'Bert', - icon: BERT, - }, - { - name: 'Eleuther GPTJ', - icon: ELEUTHER, - }, - { - name: 'Wizard Coder', - icon: BRAIN, - }, - { - name: 'NeMo', - icon: NEMO, - }, - { - name: 'Orca', - icon: ORCA, - }, - { - name: 'AWS_TITAN_TEXT_EMBEDDINGS', - icon: Amazon_Titan, - }, - { - name: 'Stablity AI', - icon: STABILITY_AI, - }, - { - name: 'Replit Code Model', - icon: REPLIT, - }, - { - name: 'NeMo', - icon: NEMO, - }, - { - name: 'ZIP', - icon: ZIP, - }, - ], - FUNCTION: [ - { - name: 'REST', - icon: RESTAPI, - }, - { - name: 'ZIP', - icon: ZIP, - }, - { - name: 'AZUREOCR', - icon: RESTAPI, - }, - { - name: 'AWS - Image Text Extraction', - icon: AWS_TEXTRACT, - }, - { - name: 'AWS POLLY', - icon: AWS_POLLY, - }, - { - name: 'AWS Transcribe', - icon: AWS_TRANSCRIBE, - }, - { - name: 'Google Speech To Text', - icon: GOOGLE_SPEECH_TO_TEXT, - }, - { - name: 'Google OCR', - icon: GOOGLE_OCR, - }, - ], - VECTOR: [ - { - name: 'FAISS', - icon: META, - }, - { - name: 'WEAVIATE', - icon: WEVIATE, - }, - { - name: 'PINECONE', - icon: PINECONE, - }, - { - name: 'PGVECTOR', - icon: POSTGRES, - }, - { - name: 'OPEN_SEARCH', - icon: OPEN_SEARCH, - }, - { - name: 'ZIP', - icon: ZIP, - }, - ], - DATABASE: [ - { - name: 'ZIP', - icon: ZIP, - }, - { - name: 'CSV', - icon: CSV, - }, - { - name: 'EXCEL', - icon: EXCEL, - }, - { - name: 'TSV', - icon: TSV, - }, - { - name: 'SQLITE', - icon: SQLITE, - }, - { - name: 'H2_DB', - icon: H2_DB, - }, - { - name: 'NEO4J', - icon: NEO4J, - }, - { - name: 'TINKER', - icon: TINKER, - }, - { - name: 'ASTER_DB', - icon: ASTER, - }, - { - name: 'ATHENA', - icon: ATHENA, - }, - { - name: 'BIG_QUERY', - icon: BIGQUERY, - }, - { - name: 'CASSANDRA', - icon: CASSANDRA, - }, - { - name: 'CLICKHOUSE', - icon: CLICKHOUSE, - }, - { - name: 'DATABRICKS', - icon: DATABRICKS, - }, - { - name: 'DATASTAX', - icon: DATASTAX, - }, - { - name: 'DB2', - icon: DB2, - }, - { - name: 'DERBY', - icon: DERBY, - }, - { - name: 'ELASTIC_SEARCH', - icon: ELASTIC_SEARCH, - }, - { - name: 'H2', - icon: H2_DB, - }, - { - name: 'HIVE', - icon: HIVE, - }, - { - name: 'IMPALA', - icon: IMPALA, - }, - { - name: 'MARIA_DB', - icon: MARIA_DB, - }, - { - name: 'MYSQL', - icon: MYSQL, - }, - { - name: 'OPEN_SEARCH', - icon: OPEN_SEARCH, - }, - { - name: 'ORACLE', - icon: ORACLE, - }, - { - name: 'PHOENIX', - icon: PHOENIX, - }, - { - name: 'POSTGRES', - icon: POSTGRES, - }, - { - name: 'REDSHIFT', - icon: REDSHIFT, - }, - { - name: 'SAP_HANA', - icon: SAP_HANA, - }, - { - name: 'SEMOSS', - icon: SEMOSS, - }, - { - name: 'SNOWFLAKE', - icon: SNOWFLAKE, - }, - { - name: 'SQL_SERVER', - icon: SQL_SERVER, - }, - { - name: 'SQLITE', - icon: SQLITE, - }, - { - name: 'TERADATA', - icon: TERADATA, - }, - { - name: 'TIBCO', - icon: TIBCO, - }, - { - name: 'TRINO', - icon: TRINO, - }, - ], - STORAGE: [ - { - name: 'AMAZON_S3', - icon: AMAZON_S3, - }, - { - name: 'CEPH', - icon: CEPH, - }, - { - name: 'DREAMHOST', - icon: DREAMHOST, - }, - { - name: 'DROPBOX', - icon: DROPBOX, - }, - { - name: 'GOOGLE_CLOUD_STORAGE', - icon: GOOGLE_CLOUD, - }, - { - name: 'GOOGLE_DRIVE_STORAGE', - icon: GOOGLE_DRIVE, - }, - { - name: 'LOCAL_FILE_SYSTEM', - icon: LOCAL_FILE_SYSTEM, - }, - { - name: 'MICROSOFT_AZURE_BLOB_STORAGE', - icon: AZURE_BLOB, - }, - { - name: 'MICROSOFT_ONEDRIVE', - icon: ONEDRIVE, - }, - { - name: 'NETWORK_FILE_SYSTEM', - icon: NETWORK_FILE_SYSTEM, - }, - { - name: 'MINIO', - icon: MINIO, - }, - { - name: 'SFTP', - icon: SFTP, - }, - { - name: 'ZIP', - icon: ZIP, - }, - ], + icon: AZURE_OPEN_AI, + }, + { + name: "Claude", + icon: CLAUDE, + }, + { + name: "Palm Bison", + icon: VERTEX, + }, + { + name: "Palm Chat Bison", + icon: VERTEX, + }, + { + name: "Palm Code Bison", + icon: VERTEX, + }, + { + name: "Wizard 13B", + icon: BRAIN, + }, + { + name: "Llama2 7B", + icon: META, + }, + { + name: "Llama2 13B", + icon: META, + }, + { + name: "Llama2 70B", + icon: META, + }, + { + name: "Falcon", + icon: FALCON, + }, + { + name: "StableBeluga2", + icon: BRAIN, + }, + { + name: "Guanaco", + icon: BRAIN, + }, + { + name: "Vicuna", + icon: VICUNA, + }, + { + name: "Mosaic ML", + icon: MOSAIC, + }, + { + name: "Dolly", + icon: DOLLY, + }, + { + name: "Replit code model – 3b", + icon: REPLIT, + }, + { + name: "Flan T5 Large", + icon: FLAN, + }, + { + name: "Flan T5 XXL", + icon: FLAN, + }, + { + name: "Bert", + icon: BERT, + }, + { + name: "Eleuther GPTJ", + icon: ELEUTHER, + }, + { + name: "Wizard Coder", + icon: BRAIN, + }, + { + name: "NeMo", + icon: NEMO, + }, + { + name: "Orca", + icon: ORCA, + }, + { + name: "AWS_TITAN_TEXT_EMBEDDINGS", + icon: Amazon_Titan, + }, + { + name: "Stablity AI", + icon: STABILITY_AI, + }, + { + name: "Replit Code Model", + icon: REPLIT, + }, + { + name: "NeMo", + icon: NEMO, + }, + { + name: "ZIP", + icon: ZIP, + }, + ], + FUNCTION: [ + { + name: "REST", + icon: RESTAPI, + }, + { + name: "ZIP", + icon: ZIP, + }, + { + name: "AZUREOCR", + icon: RESTAPI, + }, + { + name: "AWS - Image Text Extraction", + icon: AWS_TEXTRACT, + }, + { + name: "AWS POLLY", + icon: AWS_POLLY, + }, + { + name: "AWS Transcribe", + icon: AWS_TRANSCRIBE, + }, + { + name: "Google Speech To Text", + icon: GOOGLE_SPEECH_TO_TEXT, + }, + { + name: "Google OCR", + icon: GOOGLE_OCR, + }, + ], + VECTOR: [ + { + name: "FAISS", + icon: META, + }, + { + name: "WEAVIATE", + icon: WEVIATE, + }, + { + name: "PINECONE", + icon: PINECONE, + }, + { + name: "PGVECTOR", + icon: POSTGRES, + }, + { + name: "OPEN_SEARCH", + icon: OPEN_SEARCH, + }, + { + name: "ZIP", + icon: ZIP, + }, + ], + DATABASE: [ + { + name: "ZIP", + icon: ZIP, + }, + { + name: "CSV", + icon: CSV, + }, + { + name: "EXCEL", + icon: EXCEL, + }, + { + name: "TSV", + icon: TSV, + }, + { + name: "SQLITE", + icon: SQLITE, + }, + { + name: "H2_DB", + icon: H2_DB, + }, + { + name: "NEO4J", + icon: NEO4J, + }, + { + name: "TINKER", + icon: TINKER, + }, + { + name: "ASTER_DB", + icon: ASTER, + }, + { + name: "ATHENA", + icon: ATHENA, + }, + { + name: "BIG_QUERY", + icon: BIGQUERY, + }, + { + name: "CASSANDRA", + icon: CASSANDRA, + }, + { + name: "CLICKHOUSE", + icon: CLICKHOUSE, + }, + { + name: "DATABRICKS", + icon: DATABRICKS, + }, + { + name: "DATASTAX", + icon: DATASTAX, + }, + { + name: "DB2", + icon: DB2, + }, + { + name: "DERBY", + icon: DERBY, + }, + { + name: "ELASTIC_SEARCH", + icon: ELASTIC_SEARCH, + }, + { + name: "H2", + icon: H2_DB, + }, + { + name: "HIVE", + icon: HIVE, + }, + { + name: "IMPALA", + icon: IMPALA, + }, + { + name: "MARIA_DB", + icon: MARIA_DB, + }, + { + name: "MYSQL", + icon: MYSQL, + }, + { + name: "OPEN_SEARCH", + icon: OPEN_SEARCH, + }, + { + name: "ORACLE", + icon: ORACLE, + }, + { + name: "PHOENIX", + icon: PHOENIX, + }, + { + name: "POSTGRES", + icon: POSTGRES, + }, + { + name: "REDSHIFT", + icon: REDSHIFT, + }, + { + name: "SAP_HANA", + icon: SAP_HANA, + }, + { + name: "SEMOSS", + icon: SEMOSS, + }, + { + name: "SNOWFLAKE", + icon: SNOWFLAKE, + }, + { + name: "SQL_SERVER", + icon: SQL_SERVER, + }, + { + name: "SQLITE", + icon: SQLITE, + }, + { + name: "TERADATA", + icon: TERADATA, + }, + { + name: "TIBCO", + icon: TIBCO, + }, + { + name: "TRINO", + icon: TRINO, + }, + ], + STORAGE: [ + { + name: "AMAZON_S3", + icon: AMAZON_S3, + }, + { + name: "CEPH", + icon: CEPH, + }, + { + name: "DREAMHOST", + icon: DREAMHOST, + }, + { + name: "DROPBOX", + icon: DROPBOX, + }, + { + name: "GOOGLE_CLOUD_STORAGE", + icon: GOOGLE_CLOUD, + }, + { + name: "GOOGLE_DRIVE_STORAGE", + icon: GOOGLE_DRIVE, + }, + { + name: "LOCAL_FILE_SYSTEM", + icon: LOCAL_FILE_SYSTEM, + }, + { + name: "MICROSOFT_AZURE_BLOB_STORAGE", + icon: AZURE_BLOB, + }, + { + name: "MICROSOFT_ONEDRIVE", + icon: ONEDRIVE, + }, + { + name: "NETWORK_FILE_SYSTEM", + icon: NETWORK_FILE_SYSTEM, + }, + { + name: "MINIO", + icon: MINIO, + }, + { + name: "SFTP", + icon: SFTP, + }, + { + name: "ZIP", + icon: ZIP, + }, + ], }; export const SIDEBAR_MENU = { - MENU: [ - { - name: 'Settings', - icon: { default: SETTINGS, active: SETTINGS_SELECTED }, - }, - { - name: 'Notebooks', - icon: { default: NOTEBOOK, active: NOTEBOOK_SELECTED }, - }, - { - name: 'Files', - icon: { default: FILES, active: FILES_SELECTED }, - }, - { - name: 'Variables', - icon: { default: VARIABLES, active: VARIABLES_SELECTED }, - }, - { - name: 'Blocks', - icon: { default: BLOCKS, active: BLOCKS_SELECTED }, - }, - { - name: 'Layers', - icon: { default: LAYERS, active: LAYERS_SELECTED }, - }, - ], + MENU: [ + { + name: "Settings", + icon: { default: SETTINGS, active: SETTINGS_SELECTED }, + }, + { + name: "Notebooks", + icon: { default: NOTEBOOK, active: NOTEBOOK_SELECTED }, + }, + { + name: "Files", + icon: { default: FILES, active: FILES_SELECTED }, + }, + { + name: "Variables", + icon: { default: VARIABLES, active: VARIABLES_SELECTED }, + }, + { + name: "Blocks", + icon: { default: BLOCKS, active: BLOCKS_SELECTED }, + }, + { + name: "Layers", + icon: { default: LAYERS, active: LAYERS_SELECTED }, + }, + ], }; diff --git a/packages/client/src/pages/import/index.ts b/packages/client/src/pages/import/index.ts index 979c043c68..69ac6affbc 100644 --- a/packages/client/src/pages/import/index.ts +++ b/packages/client/src/pages/import/index.ts @@ -1,7 +1,6 @@ -export * from './ImportPage'; -export * from './ImportLayout'; -export * from './ImportConnectionPage'; -export * from './EstablishConnectionPage'; -export * from './ImportPageContent'; - -export * from './import.constants'; +export * from "./EstablishConnectionPage"; +export * from "./ImportConnectionPage"; +export * from "./ImportLayout"; +export * from "./ImportPage"; +export * from "./ImportPageContent"; +export * from "./import.constants"; diff --git a/packages/client/src/pages/index.ts b/packages/client/src/pages/index.ts index 051f0d84cb..a8dfdc5173 100644 --- a/packages/client/src/pages/index.ts +++ b/packages/client/src/pages/index.ts @@ -1,3 +1,3 @@ -import { Router } from './Router'; +import { Router } from "./Router"; export { Router }; diff --git a/packages/client/src/pages/jobs/DeleteJobModal.tsx b/packages/client/src/pages/jobs/DeleteJobModal.tsx index f2f0c68cf8..d6ef32b812 100644 --- a/packages/client/src/pages/jobs/DeleteJobModal.tsx +++ b/packages/client/src/pages/jobs/DeleteJobModal.tsx @@ -1,47 +1,47 @@ -import { Button, Modal, Typography } from '@semoss/ui'; -import { Job } from './job.types'; +import { Button, Modal, Typography } from "@semoss/ui"; +import type { Job } from "./job.types"; export const DeleteJobModal = (props: { - job: Job[]; - isOpen: boolean; - close: () => void; - deleteJob: (id: string[], group: string[]) => void; + job: Job[]; + isOpen: boolean; + close: () => void; + deleteJob: (id: string[], group: string[]) => void; }) => { - const { job, isOpen, close, deleteJob } = props; - return ( - - - Delete Job - - - Are you sure you want to delete - {job.length > 1 ? 'all selected jobs' : job[0]?.name}? - This action is permanent. - - - - - - - - - ); + const { job, isOpen, close, deleteJob } = props; + return ( + + + Delete Job + + + Are you sure you want to delete + {job.length > 1 ? "all selected jobs" : job[0]?.name}? + This action is permanent. + + + + + + + + + ); }; diff --git a/packages/client/src/pages/jobs/HistoryRow.tsx b/packages/client/src/pages/jobs/HistoryRow.tsx index de07a37e34..3e644f2520 100644 --- a/packages/client/src/pages/jobs/HistoryRow.tsx +++ b/packages/client/src/pages/jobs/HistoryRow.tsx @@ -1,74 +1,73 @@ -import { useState } from 'react'; -import { KeyboardArrowDown, ChevronRight } from '@mui/icons-material'; - +import { ChevronRight, KeyboardArrowDown } from "@mui/icons-material"; +import { useState } from "react"; import { - styled, - Table, - IconButton, - Collapse, - ChipTwo, - Box, - Stack, - Typography, -} from '@semoss/ui'; + Box, + ChipTwo, + Collapse, + IconButton, + Stack, + styled, + Table, + Typography, +} from "@semoss/ui"; const StyledExpandTableCell = styled(Table.Cell)(({ theme }) => ({ - padding: 0, + padding: 0, })); const StyledBox = styled(Box)(({ theme }) => ({ - padding: theme.spacing(1), - margin: theme.spacing(1), - borderRadius: theme.spacing(3), - backgroundColor: '#F0F0F0', + padding: theme.spacing(1), + margin: theme.spacing(1), + borderRadius: theme.spacing(3), + backgroundColor: "#F0F0F0", })); export const HistoryRow = (props: { - row: { - jobName: string; - execStart: string; - execDelta: string; - success: boolean; - schedulerOutput: string; - }; + row: { + jobName: string; + execStart: string; + execDelta: string; + success: boolean; + schedulerOutput: string; + }; }) => { - const { row } = props; - const [open, setOpen] = useState(false); + const { row } = props; + const [open, setOpen] = useState(false); - return ( - <> - - - setOpen(!open)} - data-testid={'history-table-toggle-btn'} - > - {open ? : } - - - {row.jobName} - {row.execStart} - {row.execDelta} - - - - - - - - - Output: - {row.schedulerOutput} - - - - - - ); + return ( + <> + + + setOpen(!open)} + data-testid={"history-table-toggle-btn"} + > + {open ? : } + + + {row.jobName} + {row.execStart} + {row.execDelta} + + + + + + + + + Output: + {row.schedulerOutput} + + + + + + ); }; diff --git a/packages/client/src/pages/jobs/JobBuilderModal.tsx b/packages/client/src/pages/jobs/JobBuilderModal.tsx index 877c1c2ff6..0b154d4679 100644 --- a/packages/client/src/pages/jobs/JobBuilderModal.tsx +++ b/packages/client/src/pages/jobs/JobBuilderModal.tsx @@ -1,425 +1,423 @@ -import { useEffect, useMemo, useState } from 'react'; -import { Close } from '@mui/icons-material'; - +import { Close } from "@mui/icons-material"; +import { useEffect, useMemo, useState } from "react"; +import { runPixel } from "@semoss/sdk/react"; import { - AutocompleteTwo, - Button, - IconButton, - Modal, - Stack, - TextField, - ToggleButton, - ToggleButtonGroup, - useNotification, -} from '@semoss/ui'; - -import { runPixel } from '@semoss/sdk/react'; -import { JobBuilder } from './job.types'; -import { getEncodeByJobType } from './job.utils'; -import { JobTypesBuilder } from './JobTypesBuilder'; -import { JobTypeCustomJob, JobTypeSendEmail, timezones } from './job.constants'; -import { JobStandardFrequencyBuilder } from './JobStandardFrequencyBuilder'; -import { JobCustomFrequencyBuilder } from './JobCustomFrequencyBuilder'; + AutocompleteTwo, + Button, + IconButton, + Modal, + Stack, + TextField, + ToggleButton, + ToggleButtonGroup, + useNotification, +} from "@semoss/ui"; +import { JobCustomFrequencyBuilder } from "./JobCustomFrequencyBuilder"; +import { JobStandardFrequencyBuilder } from "./JobStandardFrequencyBuilder"; +import { JobTypesBuilder } from "./JobTypesBuilder"; +import { JobTypeCustomJob, JobTypeSendEmail, timezones } from "./job.constants"; +import type { JobBuilder } from "./job.types"; +import { getEncodeByJobType } from "./job.utils"; const emptyBuilder: JobBuilder = { - id: null, - name: '', - pixel: '', - tags: [], - cronExpression: '0 0 12 * * ?', - cronTz: 'US/Eastern', - smtpHost: '', - smtpPort: '', - subject: '', - jobType: 'Custom Job', - to: [], - cc: [], - bcc: [], - from: '', - message: '', - username: '', - password: '', + id: null, + name: "", + pixel: "", + tags: [], + cronExpression: "0 0 12 * * ?", + cronTz: "US/Eastern", + smtpHost: "", + smtpPort: "", + subject: "", + jobType: "Custom Job", + to: [], + cc: [], + bcc: [], + from: "", + message: "", + username: "", + password: "", }; export const JobBuilderModal = (props: { - isOpen: boolean; - close: () => void; - getJobs: () => void; - initialBuilder?: JobBuilder; + isOpen: boolean; + close: () => void; + getJobs: () => void; + initialBuilder?: JobBuilder; }) => { - const { isOpen, close, getJobs, initialBuilder } = props; - const notification = useNotification(); + const { isOpen, close, getJobs, initialBuilder } = props; + const notification = useNotification(); - const [frequencyType, setFrequencyType] = useState<'custom' | 'standard'>( - 'standard', - ); - const [isLoading, setIsLoading] = useState(false); - const [builder, setBuilder] = useState(emptyBuilder); - const setBuilderField = (field: string, value: string | string[]) => { - setBuilder((previousBuilder) => ({ - ...previousBuilder, - [field]: value, - })); - }; + const [frequencyType, setFrequencyType] = useState<"custom" | "standard">( + "standard", + ); + const [isLoading, setIsLoading] = useState(false); + const [builder, setBuilder] = useState(emptyBuilder); + const setBuilderField = (field: string, value: string | string[]) => { + setBuilder((previousBuilder) => ({ + ...previousBuilder, + [field]: value, + })); + }; - const isEditMode = useMemo(() => { - return !!builder.id; - }, [builder.id]); + const isEditMode = useMemo(() => { + return !!builder.id; + }, [builder.id]); - useEffect(() => { - const builderToSet = initialBuilder ? initialBuilder : emptyBuilder; - setBuilder(builderToSet); - const cronValues = builderToSet.cronExpression.split(' '); - if (cronValues.length < 6) { - // invalid cron syntax, send to standard builder - setFrequencyType('standard'); - return; - } else if (Number.isNaN(cronValues[1]) || Number.isNaN(cronValues[2])) { - // non-integer time values, must be custom - setFrequencyType('custom'); - return; - } + useEffect(() => { + const builderToSet = initialBuilder ? initialBuilder : emptyBuilder; + setBuilder(builderToSet); + const cronValues = builderToSet.cronExpression.split(" "); + if (cronValues.length < 6) { + // invalid cron syntax, send to standard builder + setFrequencyType("standard"); + return; + } else if (Number.isNaN(cronValues[1]) || Number.isNaN(cronValues[2])) { + // non-integer time values, must be custom + setFrequencyType("custom"); + return; + } - if ( - cronValues[3] == '*' && - cronValues[4] == '*' && - cronValues[5] == '*' - ) { - setFrequencyType('standard'); - return; - } else if (cronValues[3] == '*' && cronValues[4] == '*') { - setFrequencyType('standard'); - return; - } else if (cronValues[4] == '*' && cronValues[5] == '*') { - setFrequencyType('standard'); - return; - } else if (cronValues[5] == '*') { - setFrequencyType('standard'); - return; - } else { - setFrequencyType('custom'); - return; - } - }, [initialBuilder ? initialBuilder.id : null]); + if ( + cronValues[3] == "*" && + cronValues[4] == "*" && + cronValues[5] == "*" + ) { + setFrequencyType("standard"); + return; + } else if (cronValues[3] == "*" && cronValues[4] == "*") { + setFrequencyType("standard"); + return; + } else if (cronValues[4] == "*" && cronValues[5] == "*") { + setFrequencyType("standard"); + return; + } else if (cronValues[5] == "*") { + setFrequencyType("standard"); + return; + } else { + setFrequencyType("custom"); + return; + } + }, [initialBuilder ? initialBuilder.id : null]); - const isCronExpressionValid: boolean = useMemo(() => { - const cronValues = builder.cronExpression.split(' '); - if (cronValues.length < 6) { - // make sure it's valid cron syntax - return false; - } - if ( - cronValues[1] !== '*' && - !( - !Number.isNaN(cronValues[1]) && - parseInt(cronValues[1]) <= 59 && - parseInt(cronValues[1]) >= 0 - ) - ) { - return false; - } - if ( - cronValues[2] !== '*' && - !( - !Number.isNaN(cronValues[2]) && - parseInt(cronValues[2]) <= 23 && - parseInt(cronValues[2]) >= 0 - ) - ) { - return false; - } - if ( - cronValues[3] !== '*' && - !( - !Number.isNaN(cronValues[3]) && - parseInt(cronValues[3]) <= 31 && - parseInt(cronValues[3]) >= 0 - ) - ) { - return false; - } - if ( - cronValues[4] !== '*' && - !( - !Number.isNaN(cronValues[4]) && - parseInt(cronValues[4]) <= 12 && - parseInt(cronValues[4]) >= 1 - ) - ) { - return false; - } - if ( - cronValues[5] !== '?' && - !( - !Number.isNaN(cronValues[5]) && - parseInt(cronValues[5]) <= 6 && - parseInt(cronValues[5]) >= 0 - ) - ) { - return false; - } - return true; - }, [builder.cronExpression]); + const isCronExpressionValid: boolean = useMemo(() => { + const cronValues = builder.cronExpression.split(" "); + if (cronValues.length < 6) { + // make sure it's valid cron syntax + return false; + } + if ( + cronValues[1] !== "*" && + !( + !Number.isNaN(cronValues[1]) && + parseInt(cronValues[1]) <= 59 && + parseInt(cronValues[1]) >= 0 + ) + ) { + return false; + } + if ( + cronValues[2] !== "*" && + !( + !Number.isNaN(cronValues[2]) && + parseInt(cronValues[2]) <= 23 && + parseInt(cronValues[2]) >= 0 + ) + ) { + return false; + } + if ( + cronValues[3] !== "*" && + !( + !Number.isNaN(cronValues[3]) && + parseInt(cronValues[3]) <= 31 && + parseInt(cronValues[3]) >= 0 + ) + ) { + return false; + } + if ( + cronValues[4] !== "*" && + !( + !Number.isNaN(cronValues[4]) && + parseInt(cronValues[4]) <= 12 && + parseInt(cronValues[4]) >= 1 + ) + ) { + return false; + } + if ( + cronValues[5] !== "?" && + !( + !Number.isNaN(cronValues[5]) && + parseInt(cronValues[5]) <= 6 && + parseInt(cronValues[5]) >= 0 + ) + ) { + return false; + } + return true; + }, [builder.cronExpression]); - const isBaseFormValid: boolean = useMemo(() => { - switch (builder.jobType) { - case JobTypeSendEmail: - return ( - !!builder.name && - !!builder.smtpHost && - !!builder.smtpPort && - !!builder.subject && - !!builder.jobType && - !!builder.to && - !!builder.from && - !!builder.message && - !!builder.username && - !!builder.password && - !!builder.cronTz - ); - case JobTypeCustomJob: - return !!builder.name && !!builder.pixel && !!builder.cronTz; - } - }, [ - builder.name, - builder.pixel, - builder.cronTz, - builder.smtpHost, - builder.smtpPort, - builder.subject, - builder.jobType, - builder.to, - builder.from, - builder.message, - builder.username, - builder.password, - ]); + const isBaseFormValid: boolean = useMemo(() => { + switch (builder.jobType) { + case JobTypeSendEmail: + return ( + !!builder.name && + !!builder.smtpHost && + !!builder.smtpPort && + !!builder.subject && + !!builder.jobType && + !!builder.to && + !!builder.from && + !!builder.message && + !!builder.username && + !!builder.password && + !!builder.cronTz + ); + case JobTypeCustomJob: + return !!builder.name && !!builder.pixel && !!builder.cronTz; + } + }, [ + builder.name, + builder.pixel, + builder.cronTz, + builder.smtpHost, + builder.smtpPort, + builder.subject, + builder.jobType, + builder.to, + builder.from, + builder.message, + builder.username, + builder.password, + ]); - const hasChanges: boolean = useMemo(() => { - if (builder.id == null) { - return true; - } + const hasChanges: boolean = useMemo(() => { + if (builder.id == null) { + return true; + } - return ( - builder.name !== initialBuilder.name || - builder.pixel !== initialBuilder.pixel || - JSON.stringify(builder.tags) !== - JSON.stringify(initialBuilder.tags) || - builder.cronTz !== initialBuilder.cronTz || - builder.cronExpression !== initialBuilder.cronExpression || - builder.smtpHost !== initialBuilder.smtpHost || - builder.smtpPort !== initialBuilder.smtpPort || - builder.subject !== initialBuilder.subject || - builder.jobType !== initialBuilder.jobType || - JSON.stringify(builder.to) !== JSON.stringify(initialBuilder.to) || - JSON.stringify(builder.cc) !== JSON.stringify(initialBuilder.cc) || - JSON.stringify(builder.bcc) !== - JSON.stringify(initialBuilder.bcc) || - builder.from !== initialBuilder.from || - builder.message !== initialBuilder.message || - builder.username !== initialBuilder.username || - builder.password !== initialBuilder.password - ); - }, [ - builder.name, - builder.pixel, - builder.tags, - builder.cronTz, - builder.cronExpression, - builder.smtpHost, - builder.smtpPort, - builder.subject, - builder.jobType, - builder.to, - builder.from, - builder.message, - builder.username, - builder.password, - ]); + return ( + builder.name !== initialBuilder.name || + builder.pixel !== initialBuilder.pixel || + JSON.stringify(builder.tags) !== + JSON.stringify(initialBuilder.tags) || + builder.cronTz !== initialBuilder.cronTz || + builder.cronExpression !== initialBuilder.cronExpression || + builder.smtpHost !== initialBuilder.smtpHost || + builder.smtpPort !== initialBuilder.smtpPort || + builder.subject !== initialBuilder.subject || + builder.jobType !== initialBuilder.jobType || + JSON.stringify(builder.to) !== JSON.stringify(initialBuilder.to) || + JSON.stringify(builder.cc) !== JSON.stringify(initialBuilder.cc) || + JSON.stringify(builder.bcc) !== + JSON.stringify(initialBuilder.bcc) || + builder.from !== initialBuilder.from || + builder.message !== initialBuilder.message || + builder.username !== initialBuilder.username || + builder.password !== initialBuilder.password + ); + }, [ + builder.name, + builder.pixel, + builder.tags, + builder.cronTz, + builder.cronExpression, + builder.smtpHost, + builder.smtpPort, + builder.subject, + builder.jobType, + builder.to, + builder.from, + builder.message, + builder.username, + builder.password, + ]); - const addJob = async () => { - setIsLoading(true); - try { - const encode = getEncodeByJobType(builder); - const response = await runPixel( - `META|ScheduleJob(jobName=["${builder.name}"],${ - builder.tags.length - ? ` jobTags=${JSON.stringify(builder.tags)},` - : '' - } jobGroup=["defaultGroup"], cronExpression=["${ - builder.cronExpression - }"], cronTz=["${ - builder.cronTz - }"], recipe=["${encode}"], uiState='{"jobType":"${ - builder.jobType - }","jobName":"${builder.name}", "cronExpression":"${ - builder.cronExpression - }","cronTimeZone":"${builder.cronTz}","recipe":"${ - builder.pixel - }","recipeParameters":""}',triggerOnLoad=[false],triggerNow=[false]);`, - ); - if (response.errors.length) { - notification.add({ - color: 'error', - message: response.errors.length[0], - }); - } - } catch (e) { - notification.add({ - color: 'error', - message: 'Unable to add job', - }); - } - getJobs(); - closeModal(); - setIsLoading(false); - }; + const addJob = async () => { + setIsLoading(true); + try { + const encode = getEncodeByJobType(builder); + const response = await runPixel( + `META|ScheduleJob(jobName=["${builder.name}"],${ + builder.tags.length + ? ` jobTags=${JSON.stringify(builder.tags)},` + : "" + } jobGroup=["defaultGroup"], cronExpression=["${ + builder.cronExpression + }"], cronTz=["${ + builder.cronTz + }"], recipe=["${encode}"], uiState='{"jobType":"${ + builder.jobType + }","jobName":"${builder.name}", "cronExpression":"${ + builder.cronExpression + }","cronTimeZone":"${builder.cronTz}","recipe":"${ + builder.pixel + }","recipeParameters":""}',triggerOnLoad=[false],triggerNow=[false]);`, + ); + if (response.errors.length) { + notification.add({ + color: "error", + message: response.errors.length[0], + }); + } + } catch (e) { + notification.add({ + color: "error", + message: "Unable to add job", + }); + } + getJobs(); + closeModal(); + setIsLoading(false); + }; - const updateJob = async () => { - setIsLoading(true); - const encode = getEncodeByJobType(builder); - await runPixel( - `META|EditScheduledJob(jobId="${builder.id}",jobName="${ - builder.name - }",${ - builder.tags.length - ? `jobTags=${JSON.stringify(builder.tags)},` - : '' - }jobGroup=["defaultGroup"],cronExpression="${ - builder.cronExpression - } *",cronTz="${ - builder.cronTz - }",recipe="${encode}",uiState='{"jobType":"${ - builder.jobType - }", "jobName":"${builder.name}", "cronExpression":"${ - builder.cronExpression - }", "cronTimeZone":"${ - builder.cronTz - }"}',triggerOnLoad=[false],triggerNow=[false]);`, - ); - getJobs(); - closeModal(); - setIsLoading(false); - }; + const updateJob = async () => { + setIsLoading(true); + const encode = getEncodeByJobType(builder); + await runPixel( + `META|EditScheduledJob(jobId="${builder.id}",jobName="${ + builder.name + }",${ + builder.tags.length + ? `jobTags=${JSON.stringify(builder.tags)},` + : "" + }jobGroup=["defaultGroup"],cronExpression="${ + builder.cronExpression + } *",cronTz="${ + builder.cronTz + }",recipe="${encode}",uiState='{"jobType":"${ + builder.jobType + }", "jobName":"${builder.name}", "cronExpression":"${ + builder.cronExpression + }", "cronTimeZone":"${ + builder.cronTz + }"}',triggerOnLoad=[false],triggerNow=[false]);`, + ); + getJobs(); + closeModal(); + setIsLoading(false); + }; - const closeModal = () => { - setBuilder(emptyBuilder); - close(); - }; + const closeModal = () => { + setBuilder(emptyBuilder); + close(); + }; - return ( - - - - {isEditMode ? 'Edit' : 'Add'} Job - - - - - - - - - setBuilderField('name', e.target.value) - } - /> - - - setFrequencyType('standard')} - data-testid={'job-builder-standard-btn'} - > - Standard - - setFrequencyType('custom')} - data-testid={'job-builder-custom-btn'} - > - Custom - - - - setBuilderField('cronTz', value) - } - size="small" - getOptionLabel={(option: string) => - option.replaceAll('_', ' ') - } - renderInput={(params) => ( - - )} - /> - {frequencyType === 'standard' ? ( - - ) : ( - - )} - - - - - - - - - - ); + return ( + + + + {isEditMode ? "Edit" : "Add"} Job + + + + + + + + + setBuilderField("name", e.target.value) + } + /> + + + setFrequencyType("standard")} + data-testid={"job-builder-standard-btn"} + > + Standard + + setFrequencyType("custom")} + data-testid={"job-builder-custom-btn"} + > + Custom + + + + setBuilderField("cronTz", value) + } + size="small" + getOptionLabel={(option: string) => + option.replaceAll("_", " ") + } + renderInput={(params) => ( + + )} + /> + {frequencyType === "standard" ? ( + + ) : ( + + )} + + + + + + + + + + ); }; diff --git a/packages/client/src/pages/jobs/JobCard.tsx b/packages/client/src/pages/jobs/JobCard.tsx index 3222eb3b0a..6475ca0825 100644 --- a/packages/client/src/pages/jobs/JobCard.tsx +++ b/packages/client/src/pages/jobs/JobCard.tsx @@ -1,43 +1,43 @@ -import { Avatar, Box, Stack, Typography, styled } from '@semoss/ui'; -import { ReactElement } from 'react'; +import type { ReactElement } from "react"; +import { Avatar, Box, Stack, styled, Typography } from "@semoss/ui"; const StyledBox = styled(Box)(({ theme }) => ({ - borderRadius: theme.spacing(1), - border: `2px ${theme.palette.divider} solid`, - padding: theme.spacing(2), + borderRadius: theme.spacing(1), + border: `2px ${theme.palette.divider} solid`, + padding: theme.spacing(2), })); const StyledAvatar = styled(Avatar, { - shouldForwardProp: (prop) => prop !== 'avatarColor' && prop !== 'iconColor', + shouldForwardProp: (prop) => prop !== "avatarColor" && prop !== "iconColor", })<{ avatarColor: string; iconColor: string }>( - ({ theme, avatarColor, iconColor }) => ({ - borderRadius: theme.spacing(0.5), - backgroundColor: avatarColor, - svg: { - fill: iconColor, - }, - }), + ({ theme, avatarColor, iconColor }) => ({ + borderRadius: theme.spacing(0.5), + backgroundColor: avatarColor, + svg: { + fill: iconColor, + }, + }), ); export const JobCard = (props: { - title: string; - icon: ReactElement; - count: number; - iconColor: string; - avatarColor: string; + title: string; + icon: ReactElement; + count: number; + iconColor: string; + avatarColor: string; }) => { - const { title, icon, count, iconColor, avatarColor } = props; + const { title, icon, count, iconColor, avatarColor } = props; - return ( - - - - {icon} - - - {title} - {count} - - - - ); + return ( + + + + {icon} + + + {title} + {count} + + + + ); }; diff --git a/packages/client/src/pages/jobs/JobCustomFrequencyBuilder.tsx b/packages/client/src/pages/jobs/JobCustomFrequencyBuilder.tsx index a61a853ca5..fda5c42240 100644 --- a/packages/client/src/pages/jobs/JobCustomFrequencyBuilder.tsx +++ b/packages/client/src/pages/jobs/JobCustomFrequencyBuilder.tsx @@ -1,115 +1,115 @@ -import { useEffect, useState } from 'react'; -import { Stack, TextField } from '@semoss/ui'; -import { JobBuilder } from './job.types'; +import { useEffect, useState } from "react"; +import { Stack, TextField } from "@semoss/ui"; +import type { JobBuilder } from "./job.types"; export const JobCustomFrequencyBuilder = (props: { - builder: JobBuilder; - setBuilderField: (field: string, value: string | string[]) => void; + builder: JobBuilder; + setBuilderField: (field: string, value: string | string[]) => void; }) => { - const { builder, setBuilderField } = props; + const { builder, setBuilderField } = props; - const [cronMinute, setCronMinute] = useState('0'); - const [cronHour, setCronHour] = useState('12'); - const [cronDayOfMonth, setCronDayOfMonth] = useState('*'); - const [cronMonth, setCronMonth] = useState('*'); - const [cronDayOfWeek, setCronDayOfWeek] = useState('?'); + const [cronMinute, setCronMinute] = useState("0"); + const [cronHour, setCronHour] = useState("12"); + const [cronDayOfMonth, setCronDayOfMonth] = useState("*"); + const [cronMonth, setCronMonth] = useState("*"); + const [cronDayOfWeek, setCronDayOfWeek] = useState("?"); - useEffect(() => { - const cronValues = builder.cronExpression.split(' '); - if (cronValues.length < 6) { - // make sure it's valid cron syntax - return; - } - if (!Number.isNaN(cronValues[1]) || cronValues[1] == '*') { - setCronMinute(cronValues[1]); - } - if (!Number.isNaN(cronValues[2]) || cronValues[2] == '*') { - setCronHour(cronValues[2]); - } - if (!Number.isNaN(cronValues[3]) || cronValues[3] == '*') { - setCronDayOfMonth(cronValues[3]); - } - if (!Number.isNaN(cronValues[4]) || cronValues[4] == '*') { - setCronMonth(cronValues[4]); - } - if (!Number.isNaN(cronValues[5]) || cronValues[5] == '?') { - setCronDayOfWeek(cronValues[5]); - } - }, []); - useEffect(() => { - setBuilderField( - 'cronExpression', - `0 ${cronMinute} ${cronHour} ${cronDayOfMonth} ${cronMonth} ${cronDayOfWeek} *`, - ); - }, [cronMinute, cronHour, cronDayOfMonth, cronMonth, cronDayOfWeek]); + useEffect(() => { + const cronValues = builder.cronExpression.split(" "); + if (cronValues.length < 6) { + // make sure it's valid cron syntax + return; + } + if (!Number.isNaN(cronValues[1]) || cronValues[1] == "*") { + setCronMinute(cronValues[1]); + } + if (!Number.isNaN(cronValues[2]) || cronValues[2] == "*") { + setCronHour(cronValues[2]); + } + if (!Number.isNaN(cronValues[3]) || cronValues[3] == "*") { + setCronDayOfMonth(cronValues[3]); + } + if (!Number.isNaN(cronValues[4]) || cronValues[4] == "*") { + setCronMonth(cronValues[4]); + } + if (!Number.isNaN(cronValues[5]) || cronValues[5] == "?") { + setCronDayOfWeek(cronValues[5]); + } + }, []); + useEffect(() => { + setBuilderField( + "cronExpression", + `0 ${cronMinute} ${cronHour} ${cronDayOfMonth} ${cronMonth} ${cronDayOfWeek} *`, + ); + }, [cronMinute, cronHour, cronDayOfMonth, cronMonth, cronDayOfWeek]); - return ( - - = 0 - ) - } - onChange={(e) => setCronMinute(e.target.value)} - /> - = 0 - ) - } - onChange={(e) => setCronHour(e.target.value)} - /> - = 0 - ) - } - onChange={(e) => setCronDayOfMonth(e.target.value)} - /> - = 1 - ) - } - onChange={(e) => setCronMonth(e.target.value)} - /> - = 0 - ) - } - onChange={(e) => setCronDayOfWeek(e.target.value)} - /> - - ); + return ( + + = 0 + ) + } + onChange={(e) => setCronMinute(e.target.value)} + /> + = 0 + ) + } + onChange={(e) => setCronHour(e.target.value)} + /> + = 0 + ) + } + onChange={(e) => setCronDayOfMonth(e.target.value)} + /> + = 1 + ) + } + onChange={(e) => setCronMonth(e.target.value)} + /> + = 0 + ) + } + onChange={(e) => setCronDayOfWeek(e.target.value)} + /> + + ); }; diff --git a/packages/client/src/pages/jobs/JobHistory.tsx b/packages/client/src/pages/jobs/JobHistory.tsx index 99fae3529a..cdb01dfc00 100644 --- a/packages/client/src/pages/jobs/JobHistory.tsx +++ b/packages/client/src/pages/jobs/JobHistory.tsx @@ -1,21 +1,21 @@ -import { useEffect, useState } from 'react'; -import { Table, Accordion, Search, styled, LinearProgress } from '@semoss/ui'; -import { ChevronRight } from '@mui/icons-material'; -import { HistoryRow } from './HistoryRow'; -import { HistoryJob } from './job.types'; +import { ChevronRight } from "@mui/icons-material"; +import { useEffect, useState } from "react"; +import { Accordion, LinearProgress, Search, styled, Table } from "@semoss/ui"; +import { HistoryRow } from "./HistoryRow"; +import type { HistoryJob } from "./job.types"; const StyledAccordion = styled(Accordion)(() => ({ - '&:before': { - display: 'none', - }, + "&:before": { + display: "none", + }, })); const StyledAccordionTrigger = styled(Accordion.Trigger)(() => ({ - '& .MuiAccordionSummary-expandIconWrapper.Mui-expanded': { - transform: 'rotate(90deg)', - }, + "& .MuiAccordionSummary-expandIconWrapper.Mui-expanded": { + transform: "rotate(90deg)", + }, })); const LoadingTableCell = styled(Table.Cell)(() => ({ - padding: 0, + padding: 0, })); /** @@ -23,96 +23,96 @@ const LoadingTableCell = styled(Table.Cell)(() => ({ * Would be good to clean this file up and make it more readable in the future */ export const JobHistory = (props: { - history: HistoryJob[]; - historyLoading: boolean; - historyCount: number; - historyPage: number; - historyRowsPerPage: number; - onPageChange?: (page: number) => void; - onRowsPerPageChange?: (rowsPerPage: number) => void; - onSearchChange?: (search: string) => void; + history: HistoryJob[]; + historyLoading: boolean; + historyCount: number; + historyPage: number; + historyRowsPerPage: number; + onPageChange?: (page: number) => void; + onRowsPerPageChange?: (rowsPerPage: number) => void; + onSearchChange?: (search: string) => void; }) => { - const { - history, - historyLoading, - historyCount, - historyPage, - historyRowsPerPage, - onPageChange, - onRowsPerPageChange, - onSearchChange, - } = props; + const { + history, + historyLoading, + historyCount, + historyPage, + historyRowsPerPage, + onPageChange, + onRowsPerPageChange, + onSearchChange, + } = props; - const [historyExpanded, setHistoryExpanded] = useState(false); + const [historyExpanded, setHistoryExpanded] = useState(false); - return ( - { - setHistoryExpanded(!historyExpanded); - }} - > - }> - History - - - onSearchChange(e.target.value)} - /> - - - - - - Name - Run Date - Time - Status - - - - {historyLoading && ( - - - - - - )} - {history.length === 0 && !historyLoading ? ( - - - No job history, please try again. - - - ) : ( - history.map((history, i) => { - return ; - }) - )} - - - - { - onPageChange(v); - }} - page={historyPage} - rowsPerPage={historyRowsPerPage} - onRowsPerPageChange={(e) => { - onRowsPerPageChange( - Number(e.target.value), - ); - }} - count={historyCount} - /> - - -
-
-
-
- ); + return ( + { + setHistoryExpanded(!historyExpanded); + }} + > + }> + History + + + onSearchChange(e.target.value)} + /> + + + + + + Name + Run Date + Time + Status + + + + {historyLoading && ( + + + + + + )} + {history.length === 0 && !historyLoading ? ( + + + No job history, please try again. + + + ) : ( + history.map((history, i) => { + return ; + }) + )} + + + + { + onPageChange(v); + }} + page={historyPage} + rowsPerPage={historyRowsPerPage} + onRowsPerPageChange={(e) => { + onRowsPerPageChange( + Number(e.target.value), + ); + }} + count={historyCount} + /> + + +
+
+
+
+ ); }; diff --git a/packages/client/src/pages/jobs/JobStandardFrequencyBuilder.tsx b/packages/client/src/pages/jobs/JobStandardFrequencyBuilder.tsx index 99dccefae5..e4768cc239 100644 --- a/packages/client/src/pages/jobs/JobStandardFrequencyBuilder.tsx +++ b/packages/client/src/pages/jobs/JobStandardFrequencyBuilder.tsx @@ -1,205 +1,203 @@ -import { useEffect, useMemo, useState } from 'react'; - -import { AutocompleteTwo, Stack, TextField } from '@semoss/ui'; - -import { DaysOfWeek, FrequencyOptions, Months } from './job.constants'; -import { DayOfWeek, Frequencies, JobBuilder, Month } from './job.types'; +import { useEffect, useMemo, useState } from "react"; +import { AutocompleteTwo, Stack, TextField } from "@semoss/ui"; +import { DaysOfWeek, FrequencyOptions, Months } from "./job.constants"; +import type { DayOfWeek, Frequencies, JobBuilder, Month } from "./job.types"; export const JobStandardFrequencyBuilder = (props: { - builder: JobBuilder; - setBuilderField: (field: string, value: string | string[]) => void; + builder: JobBuilder; + setBuilderField: (field: string, value: string | string[]) => void; }) => { - const { builder, setBuilderField } = props; + const { builder, setBuilderField } = props; - const [frequency, setFrequency] = useState('Daily'); - const [time, setTime] = useState('12:00'); - const [dayOfWeek, setDayOfWeek] = useState<{ - day: DayOfWeek; - value: 0 | 1 | 2 | 3 | 4 | 5 | 6; - }>(DaysOfWeek[0]); - const [dayOfMonth, setDayOfMonth] = useState(1); - const [month, setMonth] = useState<{ - month: Month; - value: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; - days: 28 | 29 | 30 | 31; - }>(Months[0]); + const [frequency, setFrequency] = useState("Daily"); + const [time, setTime] = useState("12:00"); + const [dayOfWeek, setDayOfWeek] = useState<{ + day: DayOfWeek; + value: 0 | 1 | 2 | 3 | 4 | 5 | 6; + }>(DaysOfWeek[0]); + const [dayOfMonth, setDayOfMonth] = useState(1); + const [month, setMonth] = useState<{ + month: Month; + value: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; + days: 28 | 29 | 30 | 31; + }>(Months[0]); - useEffect(() => { - const cronValues = builder.cronExpression.split(' '); - if (cronValues.length < 6) { - // make sure it's valid cron syntax - return; - } else if (Number.isNaN(cronValues[1]) || Number.isNaN(cronValues[2])) { - // make sure there's a valid numbered time - return; - } + useEffect(() => { + const cronValues = builder.cronExpression.split(" "); + if (cronValues.length < 6) { + // make sure it's valid cron syntax + return; + } else if (Number.isNaN(cronValues[1]) || Number.isNaN(cronValues[2])) { + // make sure there's a valid numbered time + return; + } - // set time - setTime( - `${cronValues[2] == '0' ? '00' : cronValues[2]}:${ - cronValues[1] == '0' ? '00' : cronValues[1] - }`, - ); + // set time + setTime( + `${cronValues[2] == "0" ? "00" : cronValues[2]}:${ + cronValues[1] == "0" ? "00" : cronValues[1] + }`, + ); - // check frequency type - if ( - cronValues[3] == '*' && - cronValues[4] == '*' && - (cronValues[5] == '*' || cronValues[5] == '?') - ) { - setFrequency('Daily'); - } else if (cronValues[3] == '*' && cronValues[4] == '*') { - setFrequency('Weekly'); - const dayOfWeekValue = parseInt(cronValues[5]); - const dayOfWeekRecord = DaysOfWeek.find( - (record) => record.value == dayOfWeekValue, - ); - if (dayOfWeekRecord) { - setDayOfWeek(dayOfWeekRecord); - } - } else if ( - cronValues[4] == '*' && - (cronValues[5] == '*' || cronValues[5] == '?') - ) { - setFrequency('Monthly'); - const dayOfMonthValue = parseInt(cronValues[3]); - if (dayOfMonthValue <= 31 && dayOfMonthValue >= 1) { - setDayOfMonth(dayOfMonthValue); - } - } else if (cronValues[5] == '*' || cronValues[5] == '?') { - setFrequency('Yearly'); - const dayOfMonthValue = parseInt(cronValues[3]); - if (dayOfMonthValue <= 31 && dayOfMonthValue >= 1) { - setDayOfMonth(dayOfMonthValue); - } - const monthValue = parseInt(cronValues[4]); - const monthRecord = Months.find( - (record) => record.value == monthValue, - ); - if (monthRecord) { - setMonth(monthRecord); - } - } - }, []); - useEffect(() => { - const [hour, minute] = time ? time.split(':') : [0, 0]; - switch (frequency) { - case 'Daily': - setBuilderField( - 'cronExpression', - `0 ${minute == '00' ? '0' : minute} ${hour} * * ? *`, - ); - break; - case 'Weekly': - setBuilderField( - 'cronExpression', - `0 ${minute == '00' ? '0' : minute} ${hour} * * ${ - dayOfWeek.value - }`, - ); - break; - case 'Monthly': - setBuilderField( - 'cronExpression', - `0 ${ - minute == '00' ? '0' : minute - } ${hour} ${dayOfMonth} * ? *`, - ); - break; - case 'Yearly': - setBuilderField( - 'cronExpression', - `0 ${minute == '00' ? '0' : minute} ${hour} ${dayOfMonth} ${ - month.value - } ? *`, - ); - break; - } - }, [time, dayOfWeek.value, dayOfMonth, month.value]); + // check frequency type + if ( + cronValues[3] == "*" && + cronValues[4] == "*" && + (cronValues[5] == "*" || cronValues[5] == "?") + ) { + setFrequency("Daily"); + } else if (cronValues[3] == "*" && cronValues[4] == "*") { + setFrequency("Weekly"); + const dayOfWeekValue = parseInt(cronValues[5]); + const dayOfWeekRecord = DaysOfWeek.find( + (record) => record.value == dayOfWeekValue, + ); + if (dayOfWeekRecord) { + setDayOfWeek(dayOfWeekRecord); + } + } else if ( + cronValues[4] == "*" && + (cronValues[5] == "*" || cronValues[5] == "?") + ) { + setFrequency("Monthly"); + const dayOfMonthValue = parseInt(cronValues[3]); + if (dayOfMonthValue <= 31 && dayOfMonthValue >= 1) { + setDayOfMonth(dayOfMonthValue); + } + } else if (cronValues[5] == "*" || cronValues[5] == "?") { + setFrequency("Yearly"); + const dayOfMonthValue = parseInt(cronValues[3]); + if (dayOfMonthValue <= 31 && dayOfMonthValue >= 1) { + setDayOfMonth(dayOfMonthValue); + } + const monthValue = parseInt(cronValues[4]); + const monthRecord = Months.find( + (record) => record.value == monthValue, + ); + if (monthRecord) { + setMonth(monthRecord); + } + } + }, []); + useEffect(() => { + const [hour, minute] = time ? time.split(":") : [0, 0]; + switch (frequency) { + case "Daily": + setBuilderField( + "cronExpression", + `0 ${minute == "00" ? "0" : minute} ${hour} * * ? *`, + ); + break; + case "Weekly": + setBuilderField( + "cronExpression", + `0 ${minute == "00" ? "0" : minute} ${hour} * * ${ + dayOfWeek.value + }`, + ); + break; + case "Monthly": + setBuilderField( + "cronExpression", + `0 ${ + minute == "00" ? "0" : minute + } ${hour} ${dayOfMonth} * ? *`, + ); + break; + case "Yearly": + setBuilderField( + "cronExpression", + `0 ${minute == "00" ? "0" : minute} ${hour} ${dayOfMonth} ${ + month.value + } ? *`, + ); + break; + } + }, [time, dayOfWeek.value, dayOfMonth, month.value]); - const daysInMonth: number | null = useMemo(() => { - if (month) { - return month.days; - } else { - return 31; - } - }, [month]); + const daysInMonth: number | null = useMemo(() => { + if (month) { + return month.days; + } else { + return 31; + } + }, [month]); - return ( - - { - return ; - }} - fullWidth - onChange={(_, value) => setFrequency(value)} - /> - {frequency == 'Weekly' ? ( - { - return ; - }} - fullWidth - isOptionEqualToValue={(option, value) => - option.value == value.value - } - getOptionLabel={(option) => option.day} - onChange={(_, value) => setDayOfWeek(value)} - /> - ) : ( - <> - )} - {frequency == 'Yearly' ? ( - { - return ; - }} - fullWidth - isOptionEqualToValue={(option, value) => - option.value == value.value - } - getOptionLabel={(option) => option.month} - onChange={(_, value) => setMonth(value)} - /> - ) : ( - <> - )} - {frequency == 'Monthly' || frequency == 'Yearly' ? ( - 0) - : false - } - fullWidth - onChange={(e) => - setDayOfMonth(parseInt(e.target.value) ?? 0) - } - /> - ) : ( - <> - )} - setTime(e.target.value)} - /> - - ); + return ( + + { + return ; + }} + fullWidth + onChange={(_, value) => setFrequency(value)} + /> + {frequency == "Weekly" ? ( + { + return ; + }} + fullWidth + isOptionEqualToValue={(option, value) => + option.value == value.value + } + getOptionLabel={(option) => option.day} + onChange={(_, value) => setDayOfWeek(value)} + /> + ) : ( + <> + )} + {frequency == "Yearly" ? ( + { + return ; + }} + fullWidth + isOptionEqualToValue={(option, value) => + option.value == value.value + } + getOptionLabel={(option) => option.month} + onChange={(_, value) => setMonth(value)} + /> + ) : ( + <> + )} + {frequency == "Monthly" || frequency == "Yearly" ? ( + 0) + : false + } + fullWidth + onChange={(e) => + setDayOfMonth(parseInt(e.target.value) ?? 0) + } + /> + ) : ( + <> + )} + setTime(e.target.value)} + /> + + ); }; diff --git a/packages/client/src/pages/jobs/JobTypesBuilder.tsx b/packages/client/src/pages/jobs/JobTypesBuilder.tsx index 46e6e83bd1..509a744b76 100644 --- a/packages/client/src/pages/jobs/JobTypesBuilder.tsx +++ b/packages/client/src/pages/jobs/JobTypesBuilder.tsx @@ -1,43 +1,42 @@ -import { AutocompleteTwo, Stack, TextField } from '@semoss/ui'; - +import { AutocompleteTwo, Stack, TextField } from "@semoss/ui"; +import { JobTypesCustomJobBuilder } from "./JobTypesCustomJobBuilder"; +import { JobTypesSendEmailBuilder } from "./JobTypesSendEmailBuilder"; import { - JobTypeCustomJob, - JobTypeOptions, - JobTypeSendEmail, -} from './job.constants'; -import { JobBuilder } from './job.types'; -import { JobTypesSendEmailBuilder } from './JobTypesSendEmailBuilder'; -import { JobTypesCustomJobBuilder } from './JobTypesCustomJobBuilder'; + JobTypeCustomJob, + JobTypeOptions, + JobTypeSendEmail, +} from "./job.constants"; +import type { JobBuilder } from "./job.types"; export const JobTypesBuilder = (props: { - builder: JobBuilder; - setBuilderField: (field: string, value: string | string[]) => void; + builder: JobBuilder; + setBuilderField: (field: string, value: string | string[]) => void; }) => { - const { builder, setBuilderField } = props; - return ( - - { - return ; - }} - fullWidth - onChange={(_, value) => setBuilderField('jobType', value)} - /> - {builder.jobType === JobTypeCustomJob && ( - - )} - {builder.jobType === JobTypeSendEmail && ( - - )} - - ); + const { builder, setBuilderField } = props; + return ( + + { + return ; + }} + fullWidth + onChange={(_, value) => setBuilderField("jobType", value)} + /> + {builder.jobType === JobTypeCustomJob && ( + + )} + {builder.jobType === JobTypeSendEmail && ( + + )} + + ); }; diff --git a/packages/client/src/pages/jobs/JobTypesCustomJobBuilder.tsx b/packages/client/src/pages/jobs/JobTypesCustomJobBuilder.tsx index d82ddcb965..6ed59b6a1e 100644 --- a/packages/client/src/pages/jobs/JobTypesCustomJobBuilder.tsx +++ b/packages/client/src/pages/jobs/JobTypesCustomJobBuilder.tsx @@ -1,54 +1,53 @@ import { - createFilterOptions, - AutocompleteTwo, - Stack, - TextField, -} from '@semoss/ui'; - -import { JobBuilder } from './job.types'; + AutocompleteTwo, + createFilterOptions, + Stack, + TextField, +} from "@semoss/ui"; +import type { JobBuilder } from "./job.types"; export const JobTypesCustomJobBuilder = (props: { - builder: JobBuilder; - setBuilderField: (field: string, value: string | string[]) => void; + builder: JobBuilder; + setBuilderField: (field: string, value: string | string[]) => void; }) => { - const { builder, setBuilderField } = props; - const filter = createFilterOptions(); - return ( - - setBuilderField('pixel', e.target.value)} - multiline - rows={3} - /> - { - setBuilderField('tags', newValue); - }} - filterOptions={(options, params) => { - const filtered = filter(options, params); + const { builder, setBuilderField } = props; + const filter = createFilterOptions(); + return ( + + setBuilderField("pixel", e.target.value)} + multiline + rows={3} + /> + { + setBuilderField("tags", newValue); + }} + filterOptions={(options, params) => { + const filtered = filter(options, params); - const { inputValue } = params; - const isExisting = options.some( - (option) => inputValue === option, - ); - if (inputValue !== '' && !isExisting) { - filtered.push(inputValue); - } + const { inputValue } = params; + const isExisting = options.some( + (option) => inputValue === option, + ); + if (inputValue !== "" && !isExisting) { + filtered.push(inputValue); + } - return filtered; - }} - options={[]} - renderOption={(props, option) =>
  • {option}
  • } - freeSolo - renderInput={(params) => } - /> -
    - ); + return filtered; + }} + options={[]} + renderOption={(props, option) =>
  • {option}
  • } + freeSolo + renderInput={(params) => } + /> +
    + ); }; diff --git a/packages/client/src/pages/jobs/JobTypesSendEmailBuilder.tsx b/packages/client/src/pages/jobs/JobTypesSendEmailBuilder.tsx index 12f026f4cf..35f8e39c42 100644 --- a/packages/client/src/pages/jobs/JobTypesSendEmailBuilder.tsx +++ b/packages/client/src/pages/jobs/JobTypesSendEmailBuilder.tsx @@ -1,169 +1,168 @@ import { - createFilterOptions, - AutocompleteTwo, - Stack, - TextField, -} from '@semoss/ui'; - -import { JobBuilder } from './job.types'; + AutocompleteTwo, + createFilterOptions, + Stack, + TextField, +} from "@semoss/ui"; +import type { JobBuilder } from "./job.types"; export const JobTypesSendEmailBuilder = (props: { - builder: JobBuilder; - setBuilderField: (field: string, value: string | string[]) => void; + builder: JobBuilder; + setBuilderField: (field: string, value: string | string[]) => void; }) => { - const { builder, setBuilderField } = props; - const filter = createFilterOptions(); - return ( - - { - setBuilderField('tags', newValue); - }} - filterOptions={(options, params) => { - const filtered = filter(options, params); + const { builder, setBuilderField } = props; + const filter = createFilterOptions(); + return ( + + { + setBuilderField("tags", newValue); + }} + filterOptions={(options, params) => { + const filtered = filter(options, params); - const { inputValue } = params; - const isExisting = options.some( - (option) => inputValue === option, - ); - if (inputValue !== '' && !isExisting) { - filtered.push(inputValue); - } + const { inputValue } = params; + const isExisting = options.some( + (option) => inputValue === option, + ); + if (inputValue !== "" && !isExisting) { + filtered.push(inputValue); + } - return filtered; - }} - options={[]} - renderOption={(props, option) =>
  • {option}
  • } - freeSolo - renderInput={(params) => } - /> - setBuilderField('smtpHost', e.target.value)} - /> - setBuilderField('smtpPort', e.target.value)} - /> - setBuilderField('subject', e.target.value)} - /> - { - setBuilderField('to', newValue); - }} - filterOptions={(options, params) => { - const filtered = filter(options, params); + return filtered; + }} + options={[]} + renderOption={(props, option) =>
  • {option}
  • } + freeSolo + renderInput={(params) => } + /> + setBuilderField("smtpHost", e.target.value)} + /> + setBuilderField("smtpPort", e.target.value)} + /> + setBuilderField("subject", e.target.value)} + /> + { + setBuilderField("to", newValue); + }} + filterOptions={(options, params) => { + const filtered = filter(options, params); - const { inputValue } = params; - const isExisting = options.some( - (option) => inputValue === option, - ); - if (inputValue !== '' && !isExisting) { - filtered.push(inputValue); - } + const { inputValue } = params; + const isExisting = options.some( + (option) => inputValue === option, + ); + if (inputValue !== "" && !isExisting) { + filtered.push(inputValue); + } - return filtered; - }} - options={[]} - renderOption={(props, option) =>
  • {option}
  • } - freeSolo - renderInput={(params) => } - /> - { - setBuilderField('cc', newValue); - }} - filterOptions={(options, params) => { - const filtered = filter(options, params); + return filtered; + }} + options={[]} + renderOption={(props, option) =>
  • {option}
  • } + freeSolo + renderInput={(params) => } + /> + { + setBuilderField("cc", newValue); + }} + filterOptions={(options, params) => { + const filtered = filter(options, params); - const { inputValue } = params; - const isExisting = options.some( - (option) => inputValue === option, - ); - if (inputValue !== '' && !isExisting) { - filtered.push(inputValue); - } + const { inputValue } = params; + const isExisting = options.some( + (option) => inputValue === option, + ); + if (inputValue !== "" && !isExisting) { + filtered.push(inputValue); + } - return filtered; - }} - options={[]} - renderOption={(props, option) =>
  • {option}
  • } - freeSolo - renderInput={(params) => } - /> - { - setBuilderField('bcc', newValue); - }} - filterOptions={(options, params) => { - const filtered = filter(options, params); + return filtered; + }} + options={[]} + renderOption={(props, option) =>
  • {option}
  • } + freeSolo + renderInput={(params) => } + /> + { + setBuilderField("bcc", newValue); + }} + filterOptions={(options, params) => { + const filtered = filter(options, params); - const { inputValue } = params; - const isExisting = options.some( - (option) => inputValue === option, - ); - if (inputValue !== '' && !isExisting) { - filtered.push(inputValue); - } + const { inputValue } = params; + const isExisting = options.some( + (option) => inputValue === option, + ); + if (inputValue !== "" && !isExisting) { + filtered.push(inputValue); + } - return filtered; - }} - options={[]} - renderOption={(props, option) =>
  • {option}
  • } - freeSolo - renderInput={(params) => } - /> - setBuilderField('from', e.target.value)} - /> - setBuilderField('message', e.target.value)} - multiline - rows={3} - /> - setBuilderField('username', e.target.value)} - /> - setBuilderField('password', e.target.value)} - /> -
    - ); + return filtered; + }} + options={[]} + renderOption={(props, option) =>
  • {option}
  • } + freeSolo + renderInput={(params) => } + /> + setBuilderField("from", e.target.value)} + /> + setBuilderField("message", e.target.value)} + multiline + rows={3} + /> + setBuilderField("username", e.target.value)} + /> + setBuilderField("password", e.target.value)} + /> +
    + ); }; diff --git a/packages/client/src/pages/jobs/JobsPage.tsx b/packages/client/src/pages/jobs/JobsPage.tsx index c3ca4f7bae..dfa8cb6b08 100644 --- a/packages/client/src/pages/jobs/JobsPage.tsx +++ b/packages/client/src/pages/jobs/JobsPage.tsx @@ -1,719 +1,691 @@ -import { useEffect, useMemo, useState } from 'react'; -import { GridRowSelectionModel } from '@mui/x-data-grid'; import { - Add, - Bedtime, - ErrorRounded, - NotStartedOutlined, - Pause, - Delete, -} from '@mui/icons-material'; -import { AvTimer } from '@mui/icons-material'; - -import { - Button, - Modal, - Tabs, - Search, - useNotification, - Stack, - Typography, -} from '@semoss/ui'; - -import { runPixel, debounced } from '@semoss/sdk/react'; - -import { useRootStore } from '@/hooks'; -import { JobCard } from './JobCard'; -import { JobHistory } from './JobHistory'; + Add, + AvTimer, + Bedtime, + Delete, + ErrorRounded, + NotStartedOutlined, + Pause, +} from "@mui/icons-material"; +import type { GridRowSelectionModel } from "@mui/x-data-grid"; +import { useEffect, useMemo, useState } from "react"; +import { debounced, runPixel } from "@semoss/sdk/react"; import { - HistoryJob, - HistoryPaginationProps, - Job, - JobBuilder, - JobUIState, - PixelReturnJob, - SendEmailJob, -} from './job.types'; + Button, + Modal, + Search, + Stack, + Tabs, + Typography, + useNotification, +} from "@semoss/ui"; +import { useRootStore } from "@/hooks"; +import { DeleteJobModal } from "./DeleteJobModal"; +import { JobBuilderModal } from "./JobBuilderModal"; +import { JobCard } from "./JobCard"; +import { JobHistory } from "./JobHistory"; +import { JobsTable } from "./JobsTable"; +import type { + HistoryJob, + HistoryPaginationProps, + Job, + JobBuilder, + JobUIState, + PixelReturnJob, + SendEmailJob, +} from "./job.types"; import { - convertDeltaToRuntimeString, - convertSendEmailRecipeToJob, - convertTimetoDate, -} from './job.utils'; -import { JobsTable } from './JobsTable'; -import { JobBuilderModal } from './JobBuilderModal'; -import { DeleteJobModal } from './DeleteJobModal'; + convertDeltaToRuntimeString, + convertSendEmailRecipeToJob, + convertTimetoDate, +} from "./job.utils"; export function JobsPage() { - const { monolithStore } = useRootStore(); - const notification = useNotification(); - - const tabs = ['All', 'Active', 'Inactive']; - - const [searchValue, setSearchValue] = useState(''); - const [selectedTab, setSelectedTab] = useState(tabs[0]); - - const [failedJobCount, setFailedJobCount] = useState(0); - - const [initalBuilderState, setInitialBuilderState] = - useState(null); - - const [jobs, setJobs] = useState([]); - const [jobsLoading, setJobsLoading] = useState(false); - - const [jobToDelete, setJobToDelete] = useState(null); - - const [jobsToDelete, setJobsToDelete] = useState([]); - const [deleteMutliple, setDeleteMultiple] = useState(false); - - const [rowSelectionModel, setRowSelectionModel] = - useState([]); - - const [history, setHistory] = useState([]); - const [historyLoading, setHistoryLoading] = useState(false); - const [historySearch, setHistorySearch] = useState(''); - const [historySearchBuffer, setHistorySearchBuffer] = useState(''); - const [historyPage, setHistoryPage] = useState(0); - const [historyRowsPerPage, setHistoryRowsPerPage] = useState(5); - const [historyCount, setHistoryCount] = useState(-1); - - const getJobs = () => { - setJobsLoading(true); - const pixel = 'META|ListAllJobs()'; - monolithStore - .runQuery<[Record]>(pixel) - .then((response) => { - const type = response.pixelReturn[0].operationType[0]; - - if (type.indexOf('ERROR') > -1) { - notification.add({ - color: 'error', - message: - 'Something went wrong. Jobs could not be retrieved.', - }); - } else { - const pixelJobs: Record = - response.pixelReturn[0].output; - const jobs: Job[] = Object.values(pixelJobs).map((job) => { - // ui state is a legacy construct, this may not exist - let uiState: JobUIState; - try { - if (job.uiState) { - uiState = JSON.parse(job.uiState); - } - } catch (e) { - console.log(e); - } - - let sendEmailJob: SendEmailJob; - if (job.recipe) { - sendEmailJob = convertSendEmailRecipeToJob( - job.recipe, - ); - } - return { - id: job.jobId, - name: job.jobName, - type: 'Custom', - cronExpression: job.cronExpression, - timeZone: job.cronTz, - tags: (job?.jobTags ?? '') - .split(',') - .filter((tag) => !!tag), - lastRun: job.PREV_FIRE_TIME, - nextRun: job.NEXT_FIRE_TIME, - ownerId: job.USER_ID, - isActive: job.NEXT_FIRE_TIME !== 'INACTIVE', - group: job.jobGroup, - pixel: job.recipe, - smtpHost: sendEmailJob?.smtpHost, - smtpPort: sendEmailJob?.smtpPort, - subject: sendEmailJob?.subject, - jobType: uiState?.jobType, - to: (sendEmailJob?.to ?? '') - .split(',') - .filter((to) => !!to), - cc: (sendEmailJob?.cc ?? '') - .split(',') - .filter((cc) => !!cc), - bcc: (sendEmailJob?.bcc ?? '') - .split(',') - .filter((bcc) => !!bcc), - from: sendEmailJob?.from, - message: sendEmailJob?.message, - username: sendEmailJob?.username, - password: sendEmailJob?.password, - }; - }); - - setJobs(jobs); - } - }) - .finally(() => { - setJobsLoading(false); - }); - }; - - const deleteJob = (jobId: string[], jobGroup: string[]) => { - let pixel; - if (jobId.length > 1 && jobGroup.length > 1) { - pixel = `META | RemoveJobFromDB(jobId=${JSON.stringify( - jobId, - )}, jobGroup=${JSON.stringify(jobGroup)}) `; - } else { - pixel = 'META | RemoveJobFromDB('; - pixel += 'jobId=["' + jobId[0] + '"], '; - pixel += 'jobGroup=["' + jobGroup[0] + '"]) '; - } - monolithStore - .runQuery(pixel) - .then((response) => { - const type = response.pixelReturn[0].operationType; - const output = response.pixelReturn[0].output; - // Expecting output to have { success: string[], failed: string[] } - const successIds = output?.success || []; - const failedIds = output?.failed || []; - - if (type.indexOf('ERROR') === -1) { - if (failedIds.length === 0) { - notification.add({ - color: 'success', - message: `Successfully deleted all selected jobs`, - }); - } else { - // Map failed job IDs to job names - const failedJobNames = jobs - .filter((job) => failedIds.includes(job.id)) - .map((job) => job.name) - .join(', '); - notification.add({ - color: 'warning', - message: `Some jobs were deleted successfully, but the following jobs could not be deleted: ${failedJobNames}`, - }); - } - jobId.length > 1 && jobGroup.length > 1 - ? setJobsToDelete([]) - : setJobToDelete(null); - jobId.length > 1 && jobGroup.length > 1 - ? setDeleteMultiple(false) - : ''; - getJobs(); - } else { - throw new Error(response.errors[0]); - } - }) - .catch((error) => { - notification.add({ - color: 'error', - message: error.message, - }); - }); - }; - - const pauseJobs = async () => { - let pixel = ``; - selectedActiveJobs.forEach((job) => { - pixel += `PauseJobTrigger(jobId=["${job.id}"], jobGroup=["${job.group}"]);`; - }); - try { - await runPixel(pixel); - } catch (e) { - notification.add({ - color: 'error', - message: 'Unable to pause jobs.', - }); - } finally { - getJobs(); - } - }; - - const resumeJobs = async () => { - let pixel = ``; - selectedPausedJobs.forEach((job) => { - pixel += `ResumeJobTrigger(jobId=["${job.id}"], jobGroup=["${job.group}"]);`; - }); - try { - await runPixel(pixel); - } catch (e) { - notification.add({ - color: 'error', - message: 'Unable to resume jobs.', - }); - } finally { - getJobs(); - } - }; - - const loadHistory = async ( - page: number, - rowsPerPage: number, - search: string, - ) => { - setHistoryLoading(true); - let pixel = 'META|SchedulerHistory('; - if (search) { - pixel += 'filters=[Filter(SMSS_JOB_RECIPES__JOB_NAME ?like "'; - pixel += search; - pixel += '")],'; - } - pixel += 'limit=' + rowsPerPage + ','; - pixel += 'offset=' + page * rowsPerPage + ' '; - pixel += ')'; - - return monolithStore - .runQuery< - [ - { - data: { - values: string[][]; - headers: string[]; - }; - }, - ] - >(pixel) - .then((response) => { - const type = response.pixelReturn[0].operationType[0]; - if (type.indexOf('ERROR') > -1) { - notification.add({ - color: 'error', - message: - 'Something went wrong. Job history could not be retrieved.', - }); - } else { - // map the headers - const historyData: HistoryJob[] = []; - const output = response.pixelReturn[0].output; - const headers = {}; - for ( - let headerIdx = 0, - headerLen = output['data'].headers.length; - headerIdx < headerLen; - headerIdx++ - ) { - headers[output['data'].headers[headerIdx]] = headerIdx; - } - - for ( - let valueIdx = 0, - valueLen = output['data'].values.length; - valueIdx < valueLen; - valueIdx++ - ) { - // Excluding the jobs that have not ran even once from history - if ( - output['data'].values[valueIdx][ - headers['SUCCESS'] - ] !== null - ) { - const job = { - jobId: Object.prototype.hasOwnProperty.call( - headers, - 'JOB_ID', - ) - ? output['data'].values[valueIdx][ - headers['JOB_ID'] - ] - : '', - jobName: Object.prototype.hasOwnProperty.call( - headers, - 'JOB_NAME', - ) - ? output['data'].values[valueIdx][ - headers['JOB_NAME'] - ] - : '', - jobGroup: Object.prototype.hasOwnProperty.call( - headers, - 'JOB_GROUP', - ) - ? output['data'].values[valueIdx][ - headers['JOB_GROUP'] - ] - : '', - execStart: - Object.prototype.hasOwnProperty.call( - headers, - 'EXECUTION_START', - ) && - output['data'].values[valueIdx][ - headers['EXECUTION_START'] - ] - ? convertTimetoDate( - output['data'].values[valueIdx][ - headers['EXECUTION_START'] - ], - ) - : '', - execEnd: Object.prototype.hasOwnProperty.call( - headers, - 'EXECUTION_END', - ) - ? output['data'].values[valueIdx][ - headers['EXECUTION_END'] - ] - : '', - execDelta: Object.prototype.hasOwnProperty.call( - headers, - 'EXECUTION_DELTA', - ) - ? convertDeltaToRuntimeString( - output['data'].values[valueIdx][ - headers['EXECUTION_DELTA'] - ], - ) - : '', - // TODO: validate return type/value - success: Object.prototype.hasOwnProperty.call( - headers, - 'SUCCESS', - ) - ? JSON.stringify( - output['data'].values[valueIdx][ - headers['SUCCESS'] - ], - ) == 'true' - : false, - // appName: Object.prototype.hasOwnProperty.call(headers, 'APP_NAME') ? output['data'].values[valueIdx][headers.APP_NAME] : '', - jobTags: Object.prototype.hasOwnProperty.call( - headers, - 'JOB_TAG', - ) - ? output['data'].values[valueIdx][ - headers['JOB_TAG'] - ].split(',') - : [], - // capture the latest record based on the IS_LATEST field stored - isLatest: Object.prototype.hasOwnProperty.call( - headers, - 'IS_LATEST', - ) - ? JSON.stringify( - output['data'].values[valueIdx][ - headers['IS_LATEST'] - ], - ) == 'true' - : false, - //capture scheduler output - schedulerOutput: - Object.prototype.hasOwnProperty.call( - headers, - 'SCHEDULER_OUTPUT', - ) - ? output['data'].values[valueIdx][ - headers['SCHEDULER_OUTPUT'] - ] - : 'No Output.', - }; - - historyData.push(job); - } - } - return historyData; - } - }) - .finally(() => { - setHistoryLoading(false); - }); - }; - - const getHistory = async (paginationProps: HistoryPaginationProps = {}) => { - const { page, rowsPerPage, search, reload } = paginationProps; - const oldSearch = historySearch; - const oldNumOfRows = historyRowsPerPage; - const oldPage = historyPage; - const oldHistoryData = history; - - const newSearch = search ?? oldSearch; - const newNumOfRows = rowsPerPage ?? oldNumOfRows; - const newPage = - newSearch !== oldSearch - ? 0 - : Math.floor(((page ?? oldPage) * oldNumOfRows) / newNumOfRows); - - if ( - newPage !== oldPage || - newNumOfRows !== oldNumOfRows || - newSearch !== oldSearch || - reload - ) { - setHistorySearch(newSearch); - - const newHistoryData = await loadHistory( - newPage, - newNumOfRows, - newSearch, - ); - - if (newHistoryData && newHistoryData.length) { - if (newHistoryData.length < newNumOfRows) { - setHistoryCount( - newPage * newNumOfRows + newHistoryData.length, - ); - } else { - setHistoryCount(-1); - } - setHistoryPage(newPage); - setHistoryRowsPerPage(newNumOfRows); - setHistory(newHistoryData); - } else if (newPage > oldPage && newNumOfRows === oldNumOfRows) { - setHistoryCount(oldPage * oldNumOfRows + oldHistoryData.length); - } else if (newPage !== 0) { - setHistoryCount(-1); - getHistory({ - page: 0, - rowsPerPage: newNumOfRows, - search: newSearch, - }); - } else { - setHistoryCount(0); - setHistory([]); - } - } - }; - - const getFailedJobCount = () => { - const pixel = - 'META|SchedulerHistory(filters=[Filter(SMSS_AUDIT_TRAIL__SUCCESS == "false")])'; - monolithStore - .runQuery< - [ - { - data: { - values: string[][]; - headers: string[]; - }; - }, - ] - >(pixel) - .then((response) => { - const type = response.pixelReturn[0].operationType[0]; - if (type.indexOf('ERROR') > -1) { - notification.add({ - color: 'error', - message: - 'Something went wrong. Failed job history could not be retrieved.', - }); - } else { - const output = response.pixelReturn[0].output; - setFailedJobCount(output['data'].values.length); - } - }); - }; - - const filteredJobs = useMemo(() => { - const searchJobs = jobs.filter((job) => job.name.includes(searchValue)); - if (selectedTab === 'Active') { - return searchJobs.filter((job) => job.isActive); - } else if (selectedTab === 'Inactive') { - return searchJobs.filter((job) => !job.isActive); - } - return searchJobs; - }, [jobs, searchValue, selectedTab]); - - const selectedPausedJobs = useMemo(() => { - return jobs.filter((job) => { - return !job.isActive && rowSelectionModel.includes(job.id); - }); - }, [rowSelectionModel]); - - const selectedActiveJobs = useMemo(() => { - return jobs.filter((job) => { - return job.isActive && rowSelectionModel.includes(job.id); - }); - }, [rowSelectionModel]); - - // Create debounced version of getHistory function for search - const debouncedGetHistory = debounced(() => { - getHistory({ search: historySearchBuffer }); - }, 400); - - useEffect(() => { - // initial render - getJobs(); - getHistory({ reload: true }); - getFailedJobCount(); - }, []); - - useEffect(() => { - debouncedGetHistory(); - }, [historySearchBuffer, debouncedGetHistory]); - - const deleteMutlipleJobs = () => { - setDeleteMultiple(true); - const rowsToBeDeleted = jobs.filter((job) => - rowSelectionModel.includes(job.id), - ); - setJobsToDelete(rowsToBeDeleted); - }; - - return ( - - - } - count={ - jobs.filter((job) => { - return job.isActive; - }).length - } - avatarColor="#E2F2FF" - iconColor="#0471F0" - /> - } - count={ - jobs.filter((job) => { - return !job.isActive; - }).length - } - avatarColor="#F1E9FB" - iconColor="#8340DE" - /> - } - count={failedJobCount} - avatarColor="#DEF4F3" - iconColor="#00A593" - /> - - - { - setSelectedTab(value); - }} - color="primary" - > - - - - - - setSearchValue(e.target.value)} - /> - - - - - - - - - - {rowSelectionModel.length > 1 ? ( - - - - ) : ( - '' - )} - - - getHistory({ reload: true })} - setInitialBuilderState={setInitialBuilderState} - showDeleteJobModal={(job: Job) => setJobToDelete(job)} - /> - getHistory({ page })} - onRowsPerPageChange={(rowsPerPage) => - getHistory({ rowsPerPage }) - } - onSearchChange={setHistorySearchBuffer} - /> - { - setJobsToDelete([]); - setDeleteMultiple(false); - } - : () => { - setJobToDelete(null); - } - } - deleteJob={deleteJob} - /> - setInitialBuilderState(null)} - getJobs={getJobs} - /> - - ); + const { monolithStore } = useRootStore(); + const notification = useNotification(); + + const tabs = ["All", "Active", "Inactive"]; + + const [searchValue, setSearchValue] = useState(""); + const [selectedTab, setSelectedTab] = useState(tabs[0]); + + const [failedJobCount, setFailedJobCount] = useState(0); + + const [initalBuilderState, setInitialBuilderState] = + useState(null); + + const [jobs, setJobs] = useState([]); + const [jobsLoading, setJobsLoading] = useState(false); + + const [jobToDelete, setJobToDelete] = useState(null); + + const [jobsToDelete, setJobsToDelete] = useState([]); + const [deleteMutliple, setDeleteMultiple] = useState(false); + + const [rowSelectionModel, setRowSelectionModel] = + useState([]); + + const [history, setHistory] = useState([]); + const [historyLoading, setHistoryLoading] = useState(false); + const [historySearch, setHistorySearch] = useState(""); + const [historySearchBuffer, setHistorySearchBuffer] = useState(""); + const [historyPage, setHistoryPage] = useState(0); + const [historyRowsPerPage, setHistoryRowsPerPage] = useState(5); + const [historyCount, setHistoryCount] = useState(-1); + + const getJobs = () => { + setJobsLoading(true); + const pixel = "META|ListAllJobs()"; + monolithStore + .runQuery<[Record]>(pixel) + .then((response) => { + const type = response.pixelReturn[0].operationType[0]; + + if (type.indexOf("ERROR") > -1) { + notification.add({ + color: "error", + message: + "Something went wrong. Jobs could not be retrieved.", + }); + } else { + const pixelJobs: Record = + response.pixelReturn[0].output; + const jobs: Job[] = Object.values(pixelJobs).map((job) => { + // ui state is a legacy construct, this may not exist + let uiState: JobUIState; + try { + if (job.uiState) { + uiState = JSON.parse(job.uiState); + } + } catch (e) { + console.log(e); + } + + let sendEmailJob: SendEmailJob; + if (job.recipe) { + sendEmailJob = convertSendEmailRecipeToJob( + job.recipe, + ); + } + return { + id: job.jobId, + name: job.jobName, + type: "Custom", + cronExpression: job.cronExpression, + timeZone: job.cronTz, + tags: (job?.jobTags ?? "") + .split(",") + .filter((tag) => !!tag), + lastRun: job.PREV_FIRE_TIME, + nextRun: job.NEXT_FIRE_TIME, + ownerId: job.USER_ID, + isActive: job.NEXT_FIRE_TIME !== "INACTIVE", + group: job.jobGroup, + pixel: job.recipe, + smtpHost: sendEmailJob?.smtpHost, + smtpPort: sendEmailJob?.smtpPort, + subject: sendEmailJob?.subject, + jobType: uiState?.jobType, + to: (sendEmailJob?.to ?? "") + .split(",") + .filter((to) => !!to), + cc: (sendEmailJob?.cc ?? "") + .split(",") + .filter((cc) => !!cc), + bcc: (sendEmailJob?.bcc ?? "") + .split(",") + .filter((bcc) => !!bcc), + from: sendEmailJob?.from, + message: sendEmailJob?.message, + username: sendEmailJob?.username, + password: sendEmailJob?.password, + }; + }); + + setJobs(jobs); + } + }) + .finally(() => { + setJobsLoading(false); + }); + }; + + const deleteJob = (jobId: string[], jobGroup: string[]) => { + let pixel; + if (jobId.length > 1 && jobGroup.length > 1) { + pixel = `META | RemoveJobFromDB(jobId=${JSON.stringify( + jobId, + )}, jobGroup=${JSON.stringify(jobGroup)}) `; + } else { + pixel = "META | RemoveJobFromDB("; + pixel += 'jobId=["' + jobId[0] + '"], '; + pixel += 'jobGroup=["' + jobGroup[0] + '"]) '; + } + monolithStore + .runQuery(pixel) + .then((response) => { + const type = response.pixelReturn[0].operationType; + const output = response.pixelReturn[0].output; + // Expecting output to have { success: string[], failed: string[] } + const successIds = output?.success || []; + const failedIds = output?.failed || []; + + if (type.indexOf("ERROR") === -1) { + if (failedIds.length === 0) { + notification.add({ + color: "success", + message: `Successfully deleted all selected jobs`, + }); + } else { + // Map failed job IDs to job names + const failedJobNames = jobs + .filter((job) => failedIds.includes(job.id)) + .map((job) => job.name) + .join(", "); + notification.add({ + color: "warning", + message: `Some jobs were deleted successfully, but the following jobs could not be deleted: ${failedJobNames}`, + }); + } + jobId.length > 1 && jobGroup.length > 1 + ? setJobsToDelete([]) + : setJobToDelete(null); + jobId.length > 1 && jobGroup.length > 1 + ? setDeleteMultiple(false) + : ""; + getJobs(); + } else { + throw new Error(response.errors[0]); + } + }) + .catch((error) => { + notification.add({ + color: "error", + message: error.message, + }); + }); + }; + + const pauseJobs = async () => { + let pixel = ``; + selectedActiveJobs.forEach((job) => { + pixel += `PauseJobTrigger(jobId=["${job.id}"], jobGroup=["${job.group}"]);`; + }); + try { + await runPixel(pixel); + } catch (e) { + notification.add({ + color: "error", + message: "Unable to pause jobs.", + }); + } finally { + getJobs(); + } + }; + + const resumeJobs = async () => { + let pixel = ``; + selectedPausedJobs.forEach((job) => { + pixel += `ResumeJobTrigger(jobId=["${job.id}"], jobGroup=["${job.group}"]);`; + }); + try { + await runPixel(pixel); + } catch (e) { + notification.add({ + color: "error", + message: "Unable to resume jobs.", + }); + } finally { + getJobs(); + } + }; + + const loadHistory = async ( + page: number, + rowsPerPage: number, + search: string, + ) => { + setHistoryLoading(true); + let pixel = "META|SchedulerHistory("; + if (search) { + pixel += 'filters=[Filter(SMSS_JOB_RECIPES__JOB_NAME ?like "'; + pixel += search; + pixel += '")],'; + } + pixel += "limit=" + rowsPerPage + ","; + pixel += "offset=" + page * rowsPerPage + " "; + pixel += ")"; + + return monolithStore + .runQuery< + [ + { + data: { + values: string[][]; + headers: string[]; + }; + }, + ] + >(pixel) + .then((response) => { + const type = response.pixelReturn[0].operationType[0]; + if (type.indexOf("ERROR") > -1) { + notification.add({ + color: "error", + message: + "Something went wrong. Job history could not be retrieved.", + }); + } else { + // map the headers + const historyData: HistoryJob[] = []; + const output = response.pixelReturn[0].output; + const headers = {}; + for ( + let headerIdx = 0, + headerLen = output["data"].headers.length; + headerIdx < headerLen; + headerIdx++ + ) { + headers[output["data"].headers[headerIdx]] = headerIdx; + } + + for ( + let valueIdx = 0, + valueLen = output["data"].values.length; + valueIdx < valueLen; + valueIdx++ + ) { + // Excluding the jobs that have not ran even once from history + if ( + output["data"].values[valueIdx][ + headers["SUCCESS"] + ] !== null + ) { + const job = { + jobId: Object.hasOwn(headers, "JOB_ID") + ? output["data"].values[valueIdx][ + headers["JOB_ID"] + ] + : "", + jobName: Object.hasOwn(headers, "JOB_NAME") + ? output["data"].values[valueIdx][ + headers["JOB_NAME"] + ] + : "", + jobGroup: Object.hasOwn(headers, "JOB_GROUP") + ? output["data"].values[valueIdx][ + headers["JOB_GROUP"] + ] + : "", + execStart: + Object.hasOwn(headers, "EXECUTION_START") && + output["data"].values[valueIdx][ + headers["EXECUTION_START"] + ] + ? convertTimetoDate( + output["data"].values[valueIdx][ + headers["EXECUTION_START"] + ], + ) + : "", + execEnd: Object.hasOwn(headers, "EXECUTION_END") + ? output["data"].values[valueIdx][ + headers["EXECUTION_END"] + ] + : "", + execDelta: Object.hasOwn( + headers, + "EXECUTION_DELTA", + ) + ? convertDeltaToRuntimeString( + output["data"].values[valueIdx][ + headers["EXECUTION_DELTA"] + ], + ) + : "", + // TODO: validate return type/value + success: Object.hasOwn(headers, "SUCCESS") + ? JSON.stringify( + output["data"].values[valueIdx][ + headers["SUCCESS"] + ], + ) == "true" + : false, + // appName: Object.prototype.hasOwnProperty.call(headers, 'APP_NAME') ? output['data'].values[valueIdx][headers.APP_NAME] : '', + jobTags: Object.hasOwn(headers, "JOB_TAG") + ? output["data"].values[valueIdx][ + headers["JOB_TAG"] + ].split(",") + : [], + // capture the latest record based on the IS_LATEST field stored + isLatest: Object.hasOwn(headers, "IS_LATEST") + ? JSON.stringify( + output["data"].values[valueIdx][ + headers["IS_LATEST"] + ], + ) == "true" + : false, + //capture scheduler output + schedulerOutput: Object.hasOwn( + headers, + "SCHEDULER_OUTPUT", + ) + ? output["data"].values[valueIdx][ + headers["SCHEDULER_OUTPUT"] + ] + : "No Output.", + }; + + historyData.push(job); + } + } + return historyData; + } + }) + .finally(() => { + setHistoryLoading(false); + }); + }; + + const getHistory = async (paginationProps: HistoryPaginationProps = {}) => { + const { page, rowsPerPage, search, reload } = paginationProps; + const oldSearch = historySearch; + const oldNumOfRows = historyRowsPerPage; + const oldPage = historyPage; + const oldHistoryData = history; + + const newSearch = search ?? oldSearch; + const newNumOfRows = rowsPerPage ?? oldNumOfRows; + const newPage = + newSearch !== oldSearch + ? 0 + : Math.floor(((page ?? oldPage) * oldNumOfRows) / newNumOfRows); + + if ( + newPage !== oldPage || + newNumOfRows !== oldNumOfRows || + newSearch !== oldSearch || + reload + ) { + setHistorySearch(newSearch); + + const newHistoryData = await loadHistory( + newPage, + newNumOfRows, + newSearch, + ); + + if (newHistoryData && newHistoryData.length) { + if (newHistoryData.length < newNumOfRows) { + setHistoryCount( + newPage * newNumOfRows + newHistoryData.length, + ); + } else { + setHistoryCount(-1); + } + setHistoryPage(newPage); + setHistoryRowsPerPage(newNumOfRows); + setHistory(newHistoryData); + } else if (newPage > oldPage && newNumOfRows === oldNumOfRows) { + setHistoryCount(oldPage * oldNumOfRows + oldHistoryData.length); + } else if (newPage !== 0) { + setHistoryCount(-1); + getHistory({ + page: 0, + rowsPerPage: newNumOfRows, + search: newSearch, + }); + } else { + setHistoryCount(0); + setHistory([]); + } + } + }; + + const getFailedJobCount = () => { + const pixel = + 'META|SchedulerHistory(filters=[Filter(SMSS_AUDIT_TRAIL__SUCCESS == "false")])'; + monolithStore + .runQuery< + [ + { + data: { + values: string[][]; + headers: string[]; + }; + }, + ] + >(pixel) + .then((response) => { + const type = response.pixelReturn[0].operationType[0]; + if (type.indexOf("ERROR") > -1) { + notification.add({ + color: "error", + message: + "Something went wrong. Failed job history could not be retrieved.", + }); + } else { + const output = response.pixelReturn[0].output; + setFailedJobCount(output["data"].values.length); + } + }); + }; + + const filteredJobs = useMemo(() => { + const searchJobs = jobs.filter((job) => job.name.includes(searchValue)); + if (selectedTab === "Active") { + return searchJobs.filter((job) => job.isActive); + } else if (selectedTab === "Inactive") { + return searchJobs.filter((job) => !job.isActive); + } + return searchJobs; + }, [jobs, searchValue, selectedTab]); + + const selectedPausedJobs = useMemo(() => { + return jobs.filter((job) => { + return !job.isActive && rowSelectionModel.includes(job.id); + }); + }, [rowSelectionModel]); + + const selectedActiveJobs = useMemo(() => { + return jobs.filter((job) => { + return job.isActive && rowSelectionModel.includes(job.id); + }); + }, [rowSelectionModel]); + + // Create debounced version of getHistory function for search + const debouncedGetHistory = debounced(() => { + getHistory({ search: historySearchBuffer }); + }, 400); + + useEffect(() => { + // initial render + getJobs(); + getHistory({ reload: true }); + getFailedJobCount(); + }, []); + + useEffect(() => { + debouncedGetHistory(); + }, [historySearchBuffer, debouncedGetHistory]); + + const deleteMutlipleJobs = () => { + setDeleteMultiple(true); + const rowsToBeDeleted = jobs.filter((job) => + rowSelectionModel.includes(job.id), + ); + setJobsToDelete(rowsToBeDeleted); + }; + + return ( + + + } + count={ + jobs.filter((job) => { + return job.isActive; + }).length + } + avatarColor="#E2F2FF" + iconColor="#0471F0" + /> + } + count={ + jobs.filter((job) => { + return !job.isActive; + }).length + } + avatarColor="#F1E9FB" + iconColor="#8340DE" + /> + } + count={failedJobCount} + avatarColor="#DEF4F3" + iconColor="#00A593" + /> + + + { + setSelectedTab(value); + }} + color="primary" + > + + + + + + setSearchValue(e.target.value)} + /> + + + + + + + + + + {rowSelectionModel.length > 1 ? ( + + + + ) : ( + "" + )} + + + getHistory({ reload: true })} + setInitialBuilderState={setInitialBuilderState} + showDeleteJobModal={(job: Job) => setJobToDelete(job)} + /> + getHistory({ page })} + onRowsPerPageChange={(rowsPerPage) => + getHistory({ rowsPerPage }) + } + onSearchChange={setHistorySearchBuffer} + /> + { + setJobsToDelete([]); + setDeleteMultiple(false); + } + : () => { + setJobToDelete(null); + } + } + deleteJob={deleteJob} + /> + setInitialBuilderState(null)} + getJobs={getJobs} + /> + + ); } diff --git a/packages/client/src/pages/jobs/JobsTable.tsx b/packages/client/src/pages/jobs/JobsTable.tsx index 5d66acdb7e..b4740934ad 100644 --- a/packages/client/src/pages/jobs/JobsTable.tsx +++ b/packages/client/src/pages/jobs/JobsTable.tsx @@ -1,262 +1,264 @@ -import { useEffect, useState } from 'react'; -import dayjs from 'dayjs'; -import { Delete, Edit, PlayArrow } from '@mui/icons-material'; -import { DataGrid, GridColDef, GridRowSelectionModel } from '@mui/x-data-grid'; - +import { Delete, Edit, PlayArrow } from "@mui/icons-material"; import { - Chip, - IconButton, - Stack, - styled, - LinearProgress, - CircularProgress, - useNotification, -} from '@semoss/ui'; - -import { runPixel } from '@semoss/sdk/react'; -import { Job, JobBuilder } from './job.types'; -import { getHumanReadableCronExpression } from './job.utils'; + DataGrid, + type GridColDef, + type GridRowSelectionModel, +} from "@mui/x-data-grid"; +import dayjs from "dayjs"; +import { useEffect, useState } from "react"; +import { runPixel } from "@semoss/sdk/react"; +import { + Chip, + CircularProgress, + IconButton, + LinearProgress, + Stack, + styled, + useNotification, +} from "@semoss/ui"; +import type { Job, JobBuilder } from "./job.types"; +import { getHumanReadableCronExpression } from "./job.utils"; const StyledDataGrid = styled(DataGrid)(() => ({ - '.MuiDataGrid-overlayWrapper': { - height: '48px', - }, - '.MuiDataGrid-overlayWrapperInner': { - height: '48px', - }, - '.MuiDataGrid-cell': { - whiteSpace: 'normal!important', - wordWrap: 'break-word!important', - }, + ".MuiDataGrid-overlayWrapper": { + height: "48px", + }, + ".MuiDataGrid-overlayWrapperInner": { + height: "48px", + }, + ".MuiDataGrid-cell": { + whiteSpace: "normal!important", + wordWrap: "break-word!important", + }, })); export const JobsTable = (props: { - jobs: Job[]; - jobsLoading: boolean; - rowSelectionModel: GridRowSelectionModel; - setRowSelectionModel: (value: GridRowSelectionModel) => void; - getHistory: () => void; - setInitialBuilderState: (builder: JobBuilder) => void; - showDeleteJobModal: (job: Job) => void; + jobs: Job[]; + jobsLoading: boolean; + rowSelectionModel: GridRowSelectionModel; + setRowSelectionModel: (value: GridRowSelectionModel) => void; + getHistory: () => void; + setInitialBuilderState: (builder: JobBuilder) => void; + showDeleteJobModal: (job: Job) => void; }) => { - const { - jobs, - jobsLoading, - rowSelectionModel, - setRowSelectionModel, - getHistory, - setInitialBuilderState, - showDeleteJobModal, - } = props; - const notification = useNotification(); + const { + jobs, + jobsLoading, + rowSelectionModel, + setRowSelectionModel, + getHistory, + setInitialBuilderState, + showDeleteJobModal, + } = props; + const notification = useNotification(); - const [runJobLoading, setRunJobLoading] = useState(false); + const [runJobLoading, setRunJobLoading] = useState(false); - const runJob = async (job: Job) => { - setRunJobLoading(true); - try { - await runPixel( - `META | ExecuteScheduledJob ( jobId = [ "${job.id}" ] , jobGroup = [ "${job.group}" ] ) ;`, - ); - } catch (e) { - notification.add({ - color: 'error', - message: 'Job could not be executed.', - }); - } - try { - await getHistory(); - } catch (e) { - notification.add({ - color: 'error', - message: 'Could not retrieve job history.', - }); - } - setRunJobLoading(false); - }; + const runJob = async (job: Job) => { + setRunJobLoading(true); + try { + await runPixel( + `META | ExecuteScheduledJob ( jobId = [ "${job.id}" ] , jobGroup = [ "${job.group}" ] ) ;`, + ); + } catch (e) { + notification.add({ + color: "error", + message: "Job could not be executed.", + }); + } + try { + await getHistory(); + } catch (e) { + notification.add({ + color: "error", + message: "Could not retrieve job history.", + }); + } + setRunJobLoading(false); + }; - const JobColumns: GridColDef[] = [ - { - headerName: 'Name', - field: 'name', - flex: 1, - }, - { - headerName: 'Frequency', - field: 'cronExpression', - flex: 1, - renderCell: (params) => { - return ( - <> - {getHumanReadableCronExpression( - params.value.replaceAll('?', '*'), - )} - - ); - }, - }, - { - headerName: 'Time Zone', - field: 'timeZone', - flex: 1, - }, - { - headerName: 'Tags', - field: 'tags', - flex: 1, - sortable: false, - disableColumnMenu: true, - renderCell: (params) => { - return ( - - {params.value.map((tag, idx) => { - if (tag) { - return ; - } - })} - - ); - }, - }, - { - headerName: 'Last Run', - field: 'lastRun', - flex: 1, - minWidth: 200, - renderCell: (params) => { - let time = ''; - if ( - !( - !params.value || - params.value === 'N/A' || - params.value === 'INACTIVE' - ) - ) { - time = dayjs(params.value).format('MM/DD/YYYY h:MM A'); - } - return <>{time}; - }, - }, - { - headerName: 'Status', - field: 'isActive', - flex: 1, - renderCell: (params) => { - return params.value ? 'Active' : 'Paused'; - }, - }, - { - headerName: 'Modified By', - field: 'ownerId', - flex: 1, - }, - { - headerName: 'Actions', - field: 'id', - flex: 1, - sortable: false, - disableColumnMenu: true, - renderCell: (params) => { - const job = jobs.find((job) => job.id == params.value); - return ( - <> - { - runJob(job); - }} - data-testid={'jobs-table-play-btn'} - > - {runJobLoading ? ( - - ) : ( - - )} - - { - setInitialBuilderState({ - id: job.id, - name: job.name, - pixel: job.pixel, - tags: job.tags, - cronExpression: - job.cronExpression.replaceAll('?', '*'), - cronTz: job.timeZone, - smtpHost: job.smtpHost, - smtpPort: job.smtpPort, - subject: job.subject, - jobType: job.jobType, - to: job.to, - cc: job.cc, - bcc: job.bcc, - from: job.from, - message: job.message, - username: job.username, - password: job.password, - }); - }} - data-testid={'jobs-table-edit-btn'} - > - - - { - showDeleteJobModal(job); - }} - data-testid={'jobs-table-delete-btn'} - > - - - - ); - }, - }, - ]; + const JobColumns: GridColDef[] = [ + { + headerName: "Name", + field: "name", + flex: 1, + }, + { + headerName: "Frequency", + field: "cronExpression", + flex: 1, + renderCell: (params) => { + return ( + <> + {getHumanReadableCronExpression( + params.value.replaceAll("?", "*"), + )} + + ); + }, + }, + { + headerName: "Time Zone", + field: "timeZone", + flex: 1, + }, + { + headerName: "Tags", + field: "tags", + flex: 1, + sortable: false, + disableColumnMenu: true, + renderCell: (params) => { + return ( + + {params.value.map((tag, idx) => { + if (tag) { + return ; + } + })} + + ); + }, + }, + { + headerName: "Last Run", + field: "lastRun", + flex: 1, + minWidth: 200, + renderCell: (params) => { + let time = ""; + if ( + !( + !params.value || + params.value === "N/A" || + params.value === "INACTIVE" + ) + ) { + time = dayjs(params.value).format("MM/DD/YYYY h:MM A"); + } + return <>{time}; + }, + }, + { + headerName: "Status", + field: "isActive", + flex: 1, + renderCell: (params) => { + return params.value ? "Active" : "Paused"; + }, + }, + { + headerName: "Modified By", + field: "ownerId", + flex: 1, + }, + { + headerName: "Actions", + field: "id", + flex: 1, + sortable: false, + disableColumnMenu: true, + renderCell: (params) => { + const job = jobs.find((job) => job.id == params.value); + return ( + <> + { + runJob(job); + }} + data-testid={"jobs-table-play-btn"} + > + {runJobLoading ? ( + + ) : ( + + )} + + { + setInitialBuilderState({ + id: job.id, + name: job.name, + pixel: job.pixel, + tags: job.tags, + cronExpression: + job.cronExpression.replaceAll("?", "*"), + cronTz: job.timeZone, + smtpHost: job.smtpHost, + smtpPort: job.smtpPort, + subject: job.subject, + jobType: job.jobType, + to: job.to, + cc: job.cc, + bcc: job.bcc, + from: job.from, + message: job.message, + username: job.username, + password: job.password, + }); + }} + data-testid={"jobs-table-edit-btn"} + > + + + { + showDeleteJobModal(job); + }} + data-testid={"jobs-table-delete-btn"} + > + + + + ); + }, + }, + ]; - // reset selections when jobs change - useEffect(() => { - setRowSelectionModel([]); - }, [jobs]); + // reset selections when jobs change + useEffect(() => { + setRowSelectionModel([]); + }, [jobs]); - return ( - setRowSelectionModel(value)} - slots={{ - loadingOverlay: LinearProgress as any, - // loadingOverlay: LinearProgress as GridSlots['loadingOverlay'], - noRowsOverlay: () => ( - - No jobs found - - ), - }} - loading={jobsLoading} - /> - ); + return ( + setRowSelectionModel(value)} + slots={{ + loadingOverlay: LinearProgress as any, + // loadingOverlay: LinearProgress as GridSlots['loadingOverlay'], + noRowsOverlay: () => ( + + No jobs found + + ), + }} + loading={jobsLoading} + /> + ); }; diff --git a/packages/client/src/pages/jobs/job.constants.tsx b/packages/client/src/pages/jobs/job.constants.tsx index 0aa46aca5b..093a0e4f59 100644 --- a/packages/client/src/pages/jobs/job.constants.tsx +++ b/packages/client/src/pages/jobs/job.constants.tsx @@ -1,753 +1,753 @@ -import { DayOfWeek, Frequencies, JobTypes, Month } from './job.types'; +import type { DayOfWeek, Frequencies, JobTypes, Month } from "./job.types"; export const timezones = [ - 'Africa/Abidjan', - 'Africa/Accra', - 'Africa/Addis_Ababa', - 'Africa/Algiers', - 'Africa/Asmara', - 'Africa/Asmera', - 'Africa/Bamako', - 'Africa/Bangui', - 'Africa/Banjul', - 'Africa/Bissau', - 'Africa/Blantyre', - 'Africa/Brazzaville', - 'Africa/Bujumbura', - 'Africa/Cairo', - 'Africa/Casablanca', - 'Africa/Ceuta', - 'Africa/Conakry', - 'Africa/Dakar', - 'Africa/Dar_es_Salaam', - 'Africa/Djibouti', - 'Africa/Douala', - 'Africa/El_Aaiun', - 'Africa/Freetown', - 'Africa/Gaborone', - 'Africa/Harare', - 'Africa/Johannesburg', - 'Africa/Juba', - 'Africa/Kampala', - 'Africa/Khartoum', - 'Africa/Kigali', - 'Africa/Kinshasa', - 'Africa/Lagos', - 'Africa/Libreville', - 'Africa/Lome', - 'Africa/Luanda', - 'Africa/Lubumbashi', - 'Africa/Lusaka', - 'Africa/Malabo', - 'Africa/Maputo', - 'Africa/Maseru', - 'Africa/Mbabane', - 'Africa/Mogadishu', - 'Africa/Monrovia', - 'Africa/Nairobi', - 'Africa/Ndjamena', - 'Africa/Niamey', - 'Africa/Nouakchott', - 'Africa/Ouagadougou', - 'Africa/Porto-Novo', - 'Africa/Sao_Tome', - 'Africa/Timbuktu', - 'Africa/Tripoli', - 'Africa/Tunis', - 'Africa/Windhoek', - 'America/Adak', - 'America/Anchorage', - 'America/Anguilla', - 'America/Antigua', - 'America/Araguaina', - 'America/Argentina/Buenos_Aires', - 'America/Argentina/Catamarca', - 'America/Argentina/ComodRivadavia', - 'America/Argentina/Cordoba', - 'America/Argentina/Jujuy', - 'America/Argentina/La_Rioja', - 'America/Argentina/Mendoza', - 'America/Argentina/Rio_Gallegos', - 'America/Argentina/Salta', - 'America/Argentina/San_Juan', - 'America/Argentina/San_Luis', - 'America/Argentina/Tucuman', - 'America/Argentina/Ushuaia', - 'America/Aruba', - 'America/Asuncion', - 'America/Atikokan', - 'America/Atka', - 'America/Bahia', - 'America/Bahia_Banderas', - 'America/Barbados', - 'America/Belem', - 'America/Belize', - 'America/Blanc-Sablon', - 'America/Boa_Vista', - 'America/Bogota', - 'America/Boise', - 'America/Buenos_Aires', - 'America/Cambridge_Bay', - 'America/Campo_Grande', - 'America/Cancun', - 'America/Caracas', - 'America/Catamarca', - 'America/Cayenne', - 'America/Cayman', - 'America/Chicago', - 'America/Chihuahua', - 'America/Ciudad_Juarez', - 'America/Coral_Harbour', - 'America/Cordoba', - 'America/Costa_Rica', - 'America/Creston', - 'America/Cuiaba', - 'America/Curacao', - 'America/Danmarkshavn', - 'America/Dawson', - 'America/Dawson_Creek', - 'America/Denver', - 'America/Detroit', - 'America/Dominica', - 'America/Edmonton', - 'America/Eirunepe', - 'America/El_Salvador', - 'America/Ensenada', - 'America/Fort_Nelson', - 'America/Fort_Wayne', - 'America/Fortaleza', - 'America/Glace_Bay', - 'America/Godthab', - 'America/Goose_Bay', - 'America/Grand_Turk', - 'America/Grenada', - 'America/Guadeloupe', - 'America/Guatemala', - 'America/Guayaquil', - 'America/Guyana', - 'America/Halifax', - 'America/Havana', - 'America/Hermosillo', - 'America/Indiana/Indianapolis', - 'America/Indiana/Knox', - 'America/Indiana/Marengo', - 'America/Indiana/Petersburg', - 'America/Indiana/Tell_City', - 'America/Indiana/Vevay', - 'America/Indiana/Vincennes', - 'America/Indiana/Winamac', - 'America/Indianapolis', - 'America/Inuvik', - 'America/Iqaluit', - 'America/Jamaica', - 'America/Jujuy', - 'America/Juneau', - 'America/Kentucky/Louisville', - 'America/Kentucky/Monticello', - 'America/Knox_IN', - 'America/Kralendijk', - 'America/La_Paz', - 'America/Lima', - 'America/Los_Angeles', - 'America/Louisville', - 'America/Lower_Princes', - 'America/Maceio', - 'America/Managua', - 'America/Manaus', - 'America/Marigot', - 'America/Martinique', - 'America/Matamoros', - 'America/Mazatlan', - 'America/Mendoza', - 'America/Menominee', - 'America/Merida', - 'America/Metlakatla', - 'America/Mexico_City', - 'America/Miquelon', - 'America/Moncton', - 'America/Monterrey', - 'America/Montevideo', - 'America/Montreal', - 'America/Montserrat', - 'America/Nassau', - 'America/New_York', - 'America/Nipigon', - 'America/Nome', - 'America/Noronha', - 'America/North_Dakota/Beulah', - 'America/North_Dakota/Center', - 'America/North_Dakota/New_Salem', - 'America/Nuuk', - 'America/Ojinaga', - 'America/Panama', - 'America/Pangnirtung', - 'America/Paramaribo', - 'America/Phoenix', - 'America/Port-au-Prince', - 'America/Port_of_Spain', - 'America/Porto_Acre', - 'America/Porto_Velho', - 'America/Puerto_Rico', - 'America/Punta_Arenas', - 'America/Rainy_River', - 'America/Rankin_Inlet', - 'America/Recife', - 'America/Regina', - 'America/Resolute', - 'America/Rio_Branco', - 'America/Rosario', - 'America/Santa_Isabel', - 'America/Santarem', - 'America/Santiago', - 'America/Santo_Domingo', - 'America/Sao_Paulo', - 'America/Scoresbysund', - 'America/Shiprock', - 'America/Sitka', - 'America/St_Barthelemy', - 'America/St_Johns', - 'America/St_Kitts', - 'America/St_Lucia', - 'America/St_Thomas', - 'America/St_Vincent', - 'America/Swift_Current', - 'America/Tegucigalpa', - 'America/Thule', - 'America/Thunder_Bay', - 'America/Tijuana', - 'America/Toronto', - 'America/Tortola', - 'America/Vancouver', - 'America/Virgin', - 'America/Whitehorse', - 'America/Winnipeg', - 'America/Yakutat', - 'America/Yellowknife', - 'Antarctica/Casey', - 'Antarctica/Davis', - 'Antarctica/DumontDUrville', - 'Antarctica/Macquarie', - 'Antarctica/Mawson', - 'Antarctica/McMurdo', - 'Antarctica/Palmer', - 'Antarctica/Rothera', - 'Antarctica/South_Pole', - 'Antarctica/Syowa', - 'Antarctica/Troll', - 'Antarctica/Vostok', - 'Arctic/Longyearbyen', - 'Asia/Aden', - 'Asia/Almaty', - 'Asia/Amman', - 'Asia/Anadyr', - 'Asia/Aqtau', - 'Asia/Aqtobe', - 'Asia/Ashgabat', - 'Asia/Ashkhabad', - 'Asia/Atyrau', - 'Asia/Baghdad', - 'Asia/Bahrain', - 'Asia/Baku', - 'Asia/Bangkok', - 'Asia/Barnaul', - 'Asia/Beirut', - 'Asia/Bishkek', - 'Asia/Brunei', - 'Asia/Calcutta', - 'Asia/Chita', - 'Asia/Choibalsan', - 'Asia/Chongqing', - 'Asia/Chungking', - 'Asia/Colombo', - 'Asia/Dacca', - 'Asia/Damascus', - 'Asia/Dhaka', - 'Asia/Dili', - 'Asia/Dubai', - 'Asia/Dushanbe', - 'Asia/Famagusta', - 'Asia/Gaza', - 'Asia/Harbin', - 'Asia/Hebron', - 'Asia/Ho_Chi_Minh', - 'Asia/Hong_Kong', - 'Asia/Hovd', - 'Asia/Irkutsk', - 'Asia/Istanbul', - 'Asia/Jakarta', - 'Asia/Jayapura', - 'Asia/Jerusalem', - 'Asia/Kabul', - 'Asia/Kamchatka', - 'Asia/Karachi', - 'Asia/Kashgar', - 'Asia/Kathmandu', - 'Asia/Katmandu', - 'Asia/Khandyga', - 'Asia/Kolkata', - 'Asia/Krasnoyarsk', - 'Asia/Kuala_Lumpur', - 'Asia/Kuching', - 'Asia/Kuwait', - 'Asia/Macao', - 'Asia/Macau', - 'Asia/Magadan', - 'Asia/Makassar', - 'Asia/Manila', - 'Asia/Muscat', - 'Asia/Nicosia', - 'Asia/Novokuznetsk', - 'Asia/Novosibirsk', - 'Asia/Omsk', - 'Asia/Oral', - 'Asia/Phnom_Penh', - 'Asia/Pontianak', - 'Asia/Pyongyang', - 'Asia/Qatar', - 'Asia/Qostanay', - 'Asia/Qyzylorda', - 'Asia/Rangoon', - 'Asia/Riyadh', - 'Asia/Saigon', - 'Asia/Sakhalin', - 'Asia/Samarkand', - 'Asia/Seoul', - 'Asia/Shanghai', - 'Asia/Singapore', - 'Asia/Srednekolymsk', - 'Asia/Taipei', - 'Asia/Tashkent', - 'Asia/Tbilisi', - 'Asia/Tehran', - 'Asia/Tel_Aviv', - 'Asia/Thimbu', - 'Asia/Thimphu', - 'Asia/Tokyo', - 'Asia/Tomsk', - 'Asia/Ujung_Pandang', - 'Asia/Ulaanbaatar', - 'Asia/Ulan_Bator', - 'Asia/Urumqi', - 'Asia/Ust-Nera', - 'Asia/Vientiane', - 'Asia/Vladivostok', - 'Asia/Yakutsk', - 'Asia/Yangon', - 'Asia/Yekaterinburg', - 'Asia/Yerevan', - 'Atlantic/Azores', - 'Atlantic/Bermuda', - 'Atlantic/Canary', - 'Atlantic/Cape_Verde', - 'Atlantic/Faeroe', - 'Atlantic/Faroe', - 'Atlantic/Jan_Mayen', - 'Atlantic/Madeira', - 'Atlantic/Reykjavik', - 'Atlantic/South_Georgia', - 'Atlantic/St_Helena', - 'Atlantic/Stanley', - 'Australia/ACT', - 'Australia/Adelaide', - 'Australia/Brisbane', - 'Australia/Broken_Hill', - 'Australia/Canberra', - 'Australia/Currie', - 'Australia/Darwin', - 'Australia/Eucla', - 'Australia/Hobart', - 'Australia/LHI', - 'Australia/Lindeman', - 'Australia/Lord_Howe', - 'Australia/Melbourne', - 'Australia/NSW', - 'Australia/North', - 'Australia/Perth', - 'Australia/Queensland', - 'Australia/South', - 'Australia/Sydney', - 'Australia/Tasmania', - 'Australia/Victoria', - 'Australia/West', - 'Australia/Yancowinna', - 'Brazil/Acre', - 'Brazil/DeNoronha', - 'Brazil/East', - 'Brazil/West', - 'CET', - 'CST6CDT', - 'Canada/Atlantic', - 'Canada/Central', - 'Canada/Eastern', - 'Canada/Mountain', - 'Canada/Newfoundland', - 'Canada/Pacific', - 'Canada/Saskatchewan', - 'Canada/Yukon', - 'Chile/Continental', - 'Chile/EasterIsland', - 'Cuba', - 'EET', - 'EST5EDT', - 'Egypt', - 'Eire', - 'Etc/GMT', - 'Etc/GMT+0', - 'Etc/GMT+1', - 'Etc/GMT+10', - 'Etc/GMT+11', - 'Etc/GMT+12', - 'Etc/GMT+2', - 'Etc/GMT+3', - 'Etc/GMT+4', - 'Etc/GMT+5', - 'Etc/GMT+6', - 'Etc/GMT+7', - 'Etc/GMT+8', - 'Etc/GMT+9', - 'Etc/GMT-0', - 'Etc/GMT-1', - 'Etc/GMT-10', - 'Etc/GMT-11', - 'Etc/GMT-12', - 'Etc/GMT-13', - 'Etc/GMT-14', - 'Etc/GMT-2', - 'Etc/GMT-3', - 'Etc/GMT-4', - 'Etc/GMT-5', - 'Etc/GMT-6', - 'Etc/GMT-7', - 'Etc/GMT-8', - 'Etc/GMT-9', - 'Etc/GMT0', - 'Etc/Greenwich', - 'Etc/UCT', - 'Etc/UTC', - 'Etc/Universal', - 'Etc/Zulu', - 'Europe/Amsterdam', - 'Europe/Andorra', - 'Europe/Astrakhan', - 'Europe/Athens', - 'Europe/Belfast', - 'Europe/Belgrade', - 'Europe/Berlin', - 'Europe/Bratislava', - 'Europe/Brussels', - 'Europe/Bucharest', - 'Europe/Budapest', - 'Europe/Busingen', - 'Europe/Chisinau', - 'Europe/Copenhagen', - 'Europe/Dublin', - 'Europe/Gibraltar', - 'Europe/Guernsey', - 'Europe/Helsinki', - 'Europe/Isle_of_Man', - 'Europe/Istanbul', - 'Europe/Jersey', - 'Europe/Kaliningrad', - 'Europe/Kiev', - 'Europe/Kirov', - 'Europe/Kyiv', - 'Europe/Lisbon', - 'Europe/Ljubljana', - 'Europe/London', - 'Europe/Luxembourg', - 'Europe/Madrid', - 'Europe/Malta', - 'Europe/Mariehamn', - 'Europe/Minsk', - 'Europe/Monaco', - 'Europe/Moscow', - 'Europe/Nicosia', - 'Europe/Oslo', - 'Europe/Paris', - 'Europe/Podgorica', - 'Europe/Prague', - 'Europe/Riga', - 'Europe/Rome', - 'Europe/Samara', - 'Europe/San_Marino', - 'Europe/Sarajevo', - 'Europe/Saratov', - 'Europe/Simferopol', - 'Europe/Skopje', - 'Europe/Sofia', - 'Europe/Stockholm', - 'Europe/Tallinn', - 'Europe/Tirane', - 'Europe/Tiraspol', - 'Europe/Ulyanovsk', - 'Europe/Uzhgorod', - 'Europe/Vaduz', - 'Europe/Vatican', - 'Europe/Vienna', - 'Europe/Vilnius', - 'Europe/Volgograd', - 'Europe/Warsaw', - 'Europe/Zagreb', - 'Europe/Zaporozhye', - 'Europe/Zurich', - 'GB', - 'GB-Eire', - 'GMT', - 'GMT0', - 'Greenwich', - 'Hongkong', - 'Iceland', - 'Indian/Antananarivo', - 'Indian/Chagos', - 'Indian/Christmas', - 'Indian/Cocos', - 'Indian/Comoro', - 'Indian/Kerguelen', - 'Indian/Mahe', - 'Indian/Maldives', - 'Indian/Mauritius', - 'Indian/Mayotte', - 'Indian/Reunion', - 'Iran', - 'Israel', - 'Jamaica', - 'Japan', - 'Kwajalein', - 'Libya', - 'MET', - 'MST7MDT', - 'Mexico/BajaNorte', - 'Mexico/BajaSur', - 'Mexico/General', - 'NZ', - 'NZ-CHAT', - 'Navajo', - 'PRC', - 'PST8PDT', - 'Pacific/Apia', - 'Pacific/Auckland', - 'Pacific/Bougainville', - 'Pacific/Chatham', - 'Pacific/Chuuk', - 'Pacific/Easter', - 'Pacific/Efate', - 'Pacific/Enderbury', - 'Pacific/Fakaofo', - 'Pacific/Fiji', - 'Pacific/Funafuti', - 'Pacific/Galapagos', - 'Pacific/Gambier', - 'Pacific/Guadalcanal', - 'Pacific/Guam', - 'Pacific/Honolulu', - 'Pacific/Johnston', - 'Pacific/Kanton', - 'Pacific/Kiritimati', - 'Pacific/Kosrae', - 'Pacific/Kwajalein', - 'Pacific/Majuro', - 'Pacific/Marquesas', - 'Pacific/Midway', - 'Pacific/Nauru', - 'Pacific/Niue', - 'Pacific/Norfolk', - 'Pacific/Noumea', - 'Pacific/Pago_Pago', - 'Pacific/Palau', - 'Pacific/Pitcairn', - 'Pacific/Pohnpei', - 'Pacific/Ponape', - 'Pacific/Port_Moresby', - 'Pacific/Rarotonga', - 'Pacific/Saipan', - 'Pacific/Samoa', - 'Pacific/Tahiti', - 'Pacific/Tarawa', - 'Pacific/Tongatapu', - 'Pacific/Truk', - 'Pacific/Wake', - 'Pacific/Wallis', - 'Pacific/Yap', - 'Poland', - 'Portugal', - 'ROK', - 'Singapore', - 'SystemV/AST4', - 'SystemV/AST4ADT', - 'SystemV/CST6', - 'SystemV/CST6CDT', - 'SystemV/EST5', - 'SystemV/EST5EDT', - 'SystemV/HST10', - 'SystemV/MST7', - 'SystemV/MST7MDT', - 'SystemV/PST8', - 'SystemV/PST8PDT', - 'SystemV/YST9', - 'SystemV/YST9YDT', - 'Turkey', - 'UCT', - 'US/Alaska', - 'US/Aleutian', - 'US/Arizona', - 'US/Central', - 'US/East-Indiana', - 'US/Eastern', - 'US/Hawaii', - 'US/Indiana-Starke', - 'US/Michigan', - 'US/Mountain', - 'US/Pacific', - 'US/Samoa', - 'UTC', - 'Universal', - 'W-SU', - 'WET', - 'Zulu', - 'EST', - 'HST', - 'MST', - 'ACT', - 'AET', - 'AGT', - 'ART', - 'AST', - 'BET', - 'BST', - 'CAT', - 'CNT', - 'CST', - 'CTT', - 'EAT', - 'ECT', - 'IET', - 'IST', - 'JST', - 'MIT', - 'NET', - 'NST', - 'PLT', - 'PNT', - 'PRT', - 'PST', - 'SST', - 'VST', + "Africa/Abidjan", + "Africa/Accra", + "Africa/Addis_Ababa", + "Africa/Algiers", + "Africa/Asmara", + "Africa/Asmera", + "Africa/Bamako", + "Africa/Bangui", + "Africa/Banjul", + "Africa/Bissau", + "Africa/Blantyre", + "Africa/Brazzaville", + "Africa/Bujumbura", + "Africa/Cairo", + "Africa/Casablanca", + "Africa/Ceuta", + "Africa/Conakry", + "Africa/Dakar", + "Africa/Dar_es_Salaam", + "Africa/Djibouti", + "Africa/Douala", + "Africa/El_Aaiun", + "Africa/Freetown", + "Africa/Gaborone", + "Africa/Harare", + "Africa/Johannesburg", + "Africa/Juba", + "Africa/Kampala", + "Africa/Khartoum", + "Africa/Kigali", + "Africa/Kinshasa", + "Africa/Lagos", + "Africa/Libreville", + "Africa/Lome", + "Africa/Luanda", + "Africa/Lubumbashi", + "Africa/Lusaka", + "Africa/Malabo", + "Africa/Maputo", + "Africa/Maseru", + "Africa/Mbabane", + "Africa/Mogadishu", + "Africa/Monrovia", + "Africa/Nairobi", + "Africa/Ndjamena", + "Africa/Niamey", + "Africa/Nouakchott", + "Africa/Ouagadougou", + "Africa/Porto-Novo", + "Africa/Sao_Tome", + "Africa/Timbuktu", + "Africa/Tripoli", + "Africa/Tunis", + "Africa/Windhoek", + "America/Adak", + "America/Anchorage", + "America/Anguilla", + "America/Antigua", + "America/Araguaina", + "America/Argentina/Buenos_Aires", + "America/Argentina/Catamarca", + "America/Argentina/ComodRivadavia", + "America/Argentina/Cordoba", + "America/Argentina/Jujuy", + "America/Argentina/La_Rioja", + "America/Argentina/Mendoza", + "America/Argentina/Rio_Gallegos", + "America/Argentina/Salta", + "America/Argentina/San_Juan", + "America/Argentina/San_Luis", + "America/Argentina/Tucuman", + "America/Argentina/Ushuaia", + "America/Aruba", + "America/Asuncion", + "America/Atikokan", + "America/Atka", + "America/Bahia", + "America/Bahia_Banderas", + "America/Barbados", + "America/Belem", + "America/Belize", + "America/Blanc-Sablon", + "America/Boa_Vista", + "America/Bogota", + "America/Boise", + "America/Buenos_Aires", + "America/Cambridge_Bay", + "America/Campo_Grande", + "America/Cancun", + "America/Caracas", + "America/Catamarca", + "America/Cayenne", + "America/Cayman", + "America/Chicago", + "America/Chihuahua", + "America/Ciudad_Juarez", + "America/Coral_Harbour", + "America/Cordoba", + "America/Costa_Rica", + "America/Creston", + "America/Cuiaba", + "America/Curacao", + "America/Danmarkshavn", + "America/Dawson", + "America/Dawson_Creek", + "America/Denver", + "America/Detroit", + "America/Dominica", + "America/Edmonton", + "America/Eirunepe", + "America/El_Salvador", + "America/Ensenada", + "America/Fort_Nelson", + "America/Fort_Wayne", + "America/Fortaleza", + "America/Glace_Bay", + "America/Godthab", + "America/Goose_Bay", + "America/Grand_Turk", + "America/Grenada", + "America/Guadeloupe", + "America/Guatemala", + "America/Guayaquil", + "America/Guyana", + "America/Halifax", + "America/Havana", + "America/Hermosillo", + "America/Indiana/Indianapolis", + "America/Indiana/Knox", + "America/Indiana/Marengo", + "America/Indiana/Petersburg", + "America/Indiana/Tell_City", + "America/Indiana/Vevay", + "America/Indiana/Vincennes", + "America/Indiana/Winamac", + "America/Indianapolis", + "America/Inuvik", + "America/Iqaluit", + "America/Jamaica", + "America/Jujuy", + "America/Juneau", + "America/Kentucky/Louisville", + "America/Kentucky/Monticello", + "America/Knox_IN", + "America/Kralendijk", + "America/La_Paz", + "America/Lima", + "America/Los_Angeles", + "America/Louisville", + "America/Lower_Princes", + "America/Maceio", + "America/Managua", + "America/Manaus", + "America/Marigot", + "America/Martinique", + "America/Matamoros", + "America/Mazatlan", + "America/Mendoza", + "America/Menominee", + "America/Merida", + "America/Metlakatla", + "America/Mexico_City", + "America/Miquelon", + "America/Moncton", + "America/Monterrey", + "America/Montevideo", + "America/Montreal", + "America/Montserrat", + "America/Nassau", + "America/New_York", + "America/Nipigon", + "America/Nome", + "America/Noronha", + "America/North_Dakota/Beulah", + "America/North_Dakota/Center", + "America/North_Dakota/New_Salem", + "America/Nuuk", + "America/Ojinaga", + "America/Panama", + "America/Pangnirtung", + "America/Paramaribo", + "America/Phoenix", + "America/Port-au-Prince", + "America/Port_of_Spain", + "America/Porto_Acre", + "America/Porto_Velho", + "America/Puerto_Rico", + "America/Punta_Arenas", + "America/Rainy_River", + "America/Rankin_Inlet", + "America/Recife", + "America/Regina", + "America/Resolute", + "America/Rio_Branco", + "America/Rosario", + "America/Santa_Isabel", + "America/Santarem", + "America/Santiago", + "America/Santo_Domingo", + "America/Sao_Paulo", + "America/Scoresbysund", + "America/Shiprock", + "America/Sitka", + "America/St_Barthelemy", + "America/St_Johns", + "America/St_Kitts", + "America/St_Lucia", + "America/St_Thomas", + "America/St_Vincent", + "America/Swift_Current", + "America/Tegucigalpa", + "America/Thule", + "America/Thunder_Bay", + "America/Tijuana", + "America/Toronto", + "America/Tortola", + "America/Vancouver", + "America/Virgin", + "America/Whitehorse", + "America/Winnipeg", + "America/Yakutat", + "America/Yellowknife", + "Antarctica/Casey", + "Antarctica/Davis", + "Antarctica/DumontDUrville", + "Antarctica/Macquarie", + "Antarctica/Mawson", + "Antarctica/McMurdo", + "Antarctica/Palmer", + "Antarctica/Rothera", + "Antarctica/South_Pole", + "Antarctica/Syowa", + "Antarctica/Troll", + "Antarctica/Vostok", + "Arctic/Longyearbyen", + "Asia/Aden", + "Asia/Almaty", + "Asia/Amman", + "Asia/Anadyr", + "Asia/Aqtau", + "Asia/Aqtobe", + "Asia/Ashgabat", + "Asia/Ashkhabad", + "Asia/Atyrau", + "Asia/Baghdad", + "Asia/Bahrain", + "Asia/Baku", + "Asia/Bangkok", + "Asia/Barnaul", + "Asia/Beirut", + "Asia/Bishkek", + "Asia/Brunei", + "Asia/Calcutta", + "Asia/Chita", + "Asia/Choibalsan", + "Asia/Chongqing", + "Asia/Chungking", + "Asia/Colombo", + "Asia/Dacca", + "Asia/Damascus", + "Asia/Dhaka", + "Asia/Dili", + "Asia/Dubai", + "Asia/Dushanbe", + "Asia/Famagusta", + "Asia/Gaza", + "Asia/Harbin", + "Asia/Hebron", + "Asia/Ho_Chi_Minh", + "Asia/Hong_Kong", + "Asia/Hovd", + "Asia/Irkutsk", + "Asia/Istanbul", + "Asia/Jakarta", + "Asia/Jayapura", + "Asia/Jerusalem", + "Asia/Kabul", + "Asia/Kamchatka", + "Asia/Karachi", + "Asia/Kashgar", + "Asia/Kathmandu", + "Asia/Katmandu", + "Asia/Khandyga", + "Asia/Kolkata", + "Asia/Krasnoyarsk", + "Asia/Kuala_Lumpur", + "Asia/Kuching", + "Asia/Kuwait", + "Asia/Macao", + "Asia/Macau", + "Asia/Magadan", + "Asia/Makassar", + "Asia/Manila", + "Asia/Muscat", + "Asia/Nicosia", + "Asia/Novokuznetsk", + "Asia/Novosibirsk", + "Asia/Omsk", + "Asia/Oral", + "Asia/Phnom_Penh", + "Asia/Pontianak", + "Asia/Pyongyang", + "Asia/Qatar", + "Asia/Qostanay", + "Asia/Qyzylorda", + "Asia/Rangoon", + "Asia/Riyadh", + "Asia/Saigon", + "Asia/Sakhalin", + "Asia/Samarkand", + "Asia/Seoul", + "Asia/Shanghai", + "Asia/Singapore", + "Asia/Srednekolymsk", + "Asia/Taipei", + "Asia/Tashkent", + "Asia/Tbilisi", + "Asia/Tehran", + "Asia/Tel_Aviv", + "Asia/Thimbu", + "Asia/Thimphu", + "Asia/Tokyo", + "Asia/Tomsk", + "Asia/Ujung_Pandang", + "Asia/Ulaanbaatar", + "Asia/Ulan_Bator", + "Asia/Urumqi", + "Asia/Ust-Nera", + "Asia/Vientiane", + "Asia/Vladivostok", + "Asia/Yakutsk", + "Asia/Yangon", + "Asia/Yekaterinburg", + "Asia/Yerevan", + "Atlantic/Azores", + "Atlantic/Bermuda", + "Atlantic/Canary", + "Atlantic/Cape_Verde", + "Atlantic/Faeroe", + "Atlantic/Faroe", + "Atlantic/Jan_Mayen", + "Atlantic/Madeira", + "Atlantic/Reykjavik", + "Atlantic/South_Georgia", + "Atlantic/St_Helena", + "Atlantic/Stanley", + "Australia/ACT", + "Australia/Adelaide", + "Australia/Brisbane", + "Australia/Broken_Hill", + "Australia/Canberra", + "Australia/Currie", + "Australia/Darwin", + "Australia/Eucla", + "Australia/Hobart", + "Australia/LHI", + "Australia/Lindeman", + "Australia/Lord_Howe", + "Australia/Melbourne", + "Australia/NSW", + "Australia/North", + "Australia/Perth", + "Australia/Queensland", + "Australia/South", + "Australia/Sydney", + "Australia/Tasmania", + "Australia/Victoria", + "Australia/West", + "Australia/Yancowinna", + "Brazil/Acre", + "Brazil/DeNoronha", + "Brazil/East", + "Brazil/West", + "CET", + "CST6CDT", + "Canada/Atlantic", + "Canada/Central", + "Canada/Eastern", + "Canada/Mountain", + "Canada/Newfoundland", + "Canada/Pacific", + "Canada/Saskatchewan", + "Canada/Yukon", + "Chile/Continental", + "Chile/EasterIsland", + "Cuba", + "EET", + "EST5EDT", + "Egypt", + "Eire", + "Etc/GMT", + "Etc/GMT+0", + "Etc/GMT+1", + "Etc/GMT+10", + "Etc/GMT+11", + "Etc/GMT+12", + "Etc/GMT+2", + "Etc/GMT+3", + "Etc/GMT+4", + "Etc/GMT+5", + "Etc/GMT+6", + "Etc/GMT+7", + "Etc/GMT+8", + "Etc/GMT+9", + "Etc/GMT-0", + "Etc/GMT-1", + "Etc/GMT-10", + "Etc/GMT-11", + "Etc/GMT-12", + "Etc/GMT-13", + "Etc/GMT-14", + "Etc/GMT-2", + "Etc/GMT-3", + "Etc/GMT-4", + "Etc/GMT-5", + "Etc/GMT-6", + "Etc/GMT-7", + "Etc/GMT-8", + "Etc/GMT-9", + "Etc/GMT0", + "Etc/Greenwich", + "Etc/UCT", + "Etc/UTC", + "Etc/Universal", + "Etc/Zulu", + "Europe/Amsterdam", + "Europe/Andorra", + "Europe/Astrakhan", + "Europe/Athens", + "Europe/Belfast", + "Europe/Belgrade", + "Europe/Berlin", + "Europe/Bratislava", + "Europe/Brussels", + "Europe/Bucharest", + "Europe/Budapest", + "Europe/Busingen", + "Europe/Chisinau", + "Europe/Copenhagen", + "Europe/Dublin", + "Europe/Gibraltar", + "Europe/Guernsey", + "Europe/Helsinki", + "Europe/Isle_of_Man", + "Europe/Istanbul", + "Europe/Jersey", + "Europe/Kaliningrad", + "Europe/Kiev", + "Europe/Kirov", + "Europe/Kyiv", + "Europe/Lisbon", + "Europe/Ljubljana", + "Europe/London", + "Europe/Luxembourg", + "Europe/Madrid", + "Europe/Malta", + "Europe/Mariehamn", + "Europe/Minsk", + "Europe/Monaco", + "Europe/Moscow", + "Europe/Nicosia", + "Europe/Oslo", + "Europe/Paris", + "Europe/Podgorica", + "Europe/Prague", + "Europe/Riga", + "Europe/Rome", + "Europe/Samara", + "Europe/San_Marino", + "Europe/Sarajevo", + "Europe/Saratov", + "Europe/Simferopol", + "Europe/Skopje", + "Europe/Sofia", + "Europe/Stockholm", + "Europe/Tallinn", + "Europe/Tirane", + "Europe/Tiraspol", + "Europe/Ulyanovsk", + "Europe/Uzhgorod", + "Europe/Vaduz", + "Europe/Vatican", + "Europe/Vienna", + "Europe/Vilnius", + "Europe/Volgograd", + "Europe/Warsaw", + "Europe/Zagreb", + "Europe/Zaporozhye", + "Europe/Zurich", + "GB", + "GB-Eire", + "GMT", + "GMT0", + "Greenwich", + "Hongkong", + "Iceland", + "Indian/Antananarivo", + "Indian/Chagos", + "Indian/Christmas", + "Indian/Cocos", + "Indian/Comoro", + "Indian/Kerguelen", + "Indian/Mahe", + "Indian/Maldives", + "Indian/Mauritius", + "Indian/Mayotte", + "Indian/Reunion", + "Iran", + "Israel", + "Jamaica", + "Japan", + "Kwajalein", + "Libya", + "MET", + "MST7MDT", + "Mexico/BajaNorte", + "Mexico/BajaSur", + "Mexico/General", + "NZ", + "NZ-CHAT", + "Navajo", + "PRC", + "PST8PDT", + "Pacific/Apia", + "Pacific/Auckland", + "Pacific/Bougainville", + "Pacific/Chatham", + "Pacific/Chuuk", + "Pacific/Easter", + "Pacific/Efate", + "Pacific/Enderbury", + "Pacific/Fakaofo", + "Pacific/Fiji", + "Pacific/Funafuti", + "Pacific/Galapagos", + "Pacific/Gambier", + "Pacific/Guadalcanal", + "Pacific/Guam", + "Pacific/Honolulu", + "Pacific/Johnston", + "Pacific/Kanton", + "Pacific/Kiritimati", + "Pacific/Kosrae", + "Pacific/Kwajalein", + "Pacific/Majuro", + "Pacific/Marquesas", + "Pacific/Midway", + "Pacific/Nauru", + "Pacific/Niue", + "Pacific/Norfolk", + "Pacific/Noumea", + "Pacific/Pago_Pago", + "Pacific/Palau", + "Pacific/Pitcairn", + "Pacific/Pohnpei", + "Pacific/Ponape", + "Pacific/Port_Moresby", + "Pacific/Rarotonga", + "Pacific/Saipan", + "Pacific/Samoa", + "Pacific/Tahiti", + "Pacific/Tarawa", + "Pacific/Tongatapu", + "Pacific/Truk", + "Pacific/Wake", + "Pacific/Wallis", + "Pacific/Yap", + "Poland", + "Portugal", + "ROK", + "Singapore", + "SystemV/AST4", + "SystemV/AST4ADT", + "SystemV/CST6", + "SystemV/CST6CDT", + "SystemV/EST5", + "SystemV/EST5EDT", + "SystemV/HST10", + "SystemV/MST7", + "SystemV/MST7MDT", + "SystemV/PST8", + "SystemV/PST8PDT", + "SystemV/YST9", + "SystemV/YST9YDT", + "Turkey", + "UCT", + "US/Alaska", + "US/Aleutian", + "US/Arizona", + "US/Central", + "US/East-Indiana", + "US/Eastern", + "US/Hawaii", + "US/Indiana-Starke", + "US/Michigan", + "US/Mountain", + "US/Pacific", + "US/Samoa", + "UTC", + "Universal", + "W-SU", + "WET", + "Zulu", + "EST", + "HST", + "MST", + "ACT", + "AET", + "AGT", + "ART", + "AST", + "BET", + "BST", + "CAT", + "CNT", + "CST", + "CTT", + "EAT", + "ECT", + "IET", + "IST", + "JST", + "MIT", + "NET", + "NST", + "PLT", + "PNT", + "PRT", + "PST", + "SST", + "VST", ]; export const DaysOfWeek: Array<{ - day: DayOfWeek; - value: 0 | 1 | 2 | 3 | 4 | 5 | 6; + day: DayOfWeek; + value: 0 | 1 | 2 | 3 | 4 | 5 | 6; }> = [ - { - day: 'Sunday', - value: 0, - }, - { - day: 'Monday', - value: 1, - }, - { - day: 'Tuesday', - value: 2, - }, - { - day: 'Wednesday', - value: 3, - }, - { - day: 'Thursday', - value: 4, - }, - { - day: 'Friday', - value: 5, - }, - { - day: 'Saturday', - value: 6, - }, + { + day: "Sunday", + value: 0, + }, + { + day: "Monday", + value: 1, + }, + { + day: "Tuesday", + value: 2, + }, + { + day: "Wednesday", + value: 3, + }, + { + day: "Thursday", + value: 4, + }, + { + day: "Friday", + value: 5, + }, + { + day: "Saturday", + value: 6, + }, ]; export const Months: Array<{ - month: Month; - value: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; - days: 28 | 29 | 30 | 31; + month: Month; + value: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; + days: 28 | 29 | 30 | 31; }> = [ - { - month: 'January', - value: 1, - days: 31, - }, - { - month: 'February', - value: 2, - days: 29, - }, - { - month: 'March', - value: 3, - days: 31, - }, - { - month: 'April', - value: 4, - days: 30, - }, - { - month: 'May', - value: 5, - days: 31, - }, - { - month: 'June', - value: 6, - days: 30, - }, - { - month: 'July', - value: 7, - days: 31, - }, - { - month: 'August', - value: 8, - days: 31, - }, - { - month: 'September', - value: 9, - days: 30, - }, - { - month: 'October', - value: 10, - days: 31, - }, - { - month: 'November', - value: 11, - days: 30, - }, - { - month: 'December', - value: 12, - days: 31, - }, + { + month: "January", + value: 1, + days: 31, + }, + { + month: "February", + value: 2, + days: 29, + }, + { + month: "March", + value: 3, + days: 31, + }, + { + month: "April", + value: 4, + days: 30, + }, + { + month: "May", + value: 5, + days: 31, + }, + { + month: "June", + value: 6, + days: 30, + }, + { + month: "July", + value: 7, + days: 31, + }, + { + month: "August", + value: 8, + days: 31, + }, + { + month: "September", + value: 9, + days: 30, + }, + { + month: "October", + value: 10, + days: 31, + }, + { + month: "November", + value: 11, + days: 30, + }, + { + month: "December", + value: 12, + days: 31, + }, ]; -export const FrequencyDaily = 'Daily'; -export const FrequencyWeekly = 'Weekly'; -export const FrequencyMonthly = 'Monthly'; -export const FrequencyYearly = 'Yearly'; +export const FrequencyDaily = "Daily"; +export const FrequencyWeekly = "Weekly"; +export const FrequencyMonthly = "Monthly"; +export const FrequencyYearly = "Yearly"; export const FrequencyOptions: Frequencies[] = [ - FrequencyDaily, - FrequencyWeekly, - FrequencyMonthly, - FrequencyYearly, + FrequencyDaily, + FrequencyWeekly, + FrequencyMonthly, + FrequencyYearly, ]; -export const JobTypeCustomJob = 'Custom Job'; -export const JobTypeSendEmail = 'Send Email'; +export const JobTypeCustomJob = "Custom Job"; +export const JobTypeSendEmail = "Send Email"; export const JobTypeOptions: JobTypes[] = [JobTypeCustomJob, JobTypeSendEmail]; diff --git a/packages/client/src/pages/jobs/job.types.ts b/packages/client/src/pages/jobs/job.types.ts index f7f45c1317..c2dc335d7b 100644 --- a/packages/client/src/pages/jobs/job.types.ts +++ b/packages/client/src/pages/jobs/job.types.ts @@ -1,180 +1,180 @@ export interface JobBuilder { - id: string | null; - name: string; - pixel: string; - tags: string[]; - cronExpression: string; - cronTz: string; - smtpHost: string | null; - smtpPort: string | null; - subject: string | null; - jobType: string | null; - to: string[]; - cc: string[]; - bcc: string[]; - from: string | null; - message: string | null; - username: string | null; - password: string | null; + id: string | null; + name: string; + pixel: string; + tags: string[]; + cronExpression: string; + cronTz: string; + smtpHost: string | null; + smtpPort: string | null; + subject: string | null; + jobType: string | null; + to: string[]; + cc: string[]; + bcc: string[]; + from: string | null; + message: string | null; + username: string | null; + password: string | null; } export interface PixelReturnJob { - jobName: string; - cronExpression: string; - uiState: string; - jobId: string; - PREV_FIRE_TIME: string; - NEXT_FIRE_TIME: string; - recipe: string; - USER_ID: string; - jobGroup: string; - recipeParameters: string; - jobTags: string; - cronTz: string; - smtpHost: string; - smtpPort: string; - subject: string; - jobType: string; - to: string; - cc: string; - bcc: string; - from: string; - message: string; - username: string; - password: string; + jobName: string; + cronExpression: string; + uiState: string; + jobId: string; + PREV_FIRE_TIME: string; + NEXT_FIRE_TIME: string; + recipe: string; + USER_ID: string; + jobGroup: string; + recipeParameters: string; + jobTags: string; + cronTz: string; + smtpHost: string; + smtpPort: string; + subject: string; + jobType: string; + to: string; + cc: string; + bcc: string; + from: string; + message: string; + username: string; + password: string; } export interface JobUIState { - jobType: string; - jobName: string; - cronExpression: string; - cronTimeZone: string; - recipe: string; - recipeParameters: string; - hour: number; - minute: string; - ampm: 'AM' | 'PM'; - frequency: { - computer: number; - human: string; - }; - dayOfWeek: - | 'Sunday' - | 'Monday' - | 'Tuesday' - | 'Wednesday' - | 'Thursday' - | 'Friday' - | 'Saturday'; - dayOfMonth: number; - monthOfyear: - | 'January' - | 'February' - | 'March' - | 'April' - | 'May' - | 'June' - | 'July' - | 'August' - | 'September' - | 'October' - | 'November' - | 'December'; - jobTypeTemplate: object; - onLoad: boolean; - jobTags: string[]; - fileName: string; - filePath: string; - export_template: string; - exportAudit: string; - placeholderData: Array; - selectedApp: string | null; - customCron?: boolean; + jobType: string; + jobName: string; + cronExpression: string; + cronTimeZone: string; + recipe: string; + recipeParameters: string; + hour: number; + minute: string; + ampm: "AM" | "PM"; + frequency: { + computer: number; + human: string; + }; + dayOfWeek: + | "Sunday" + | "Monday" + | "Tuesday" + | "Wednesday" + | "Thursday" + | "Friday" + | "Saturday"; + dayOfMonth: number; + monthOfyear: + | "January" + | "February" + | "March" + | "April" + | "May" + | "June" + | "July" + | "August" + | "September" + | "October" + | "November" + | "December"; + jobTypeTemplate: object; + onLoad: boolean; + jobTags: string[]; + fileName: string; + filePath: string; + export_template: string; + exportAudit: string; + placeholderData: Array; + selectedApp: string | null; + customCron?: boolean; } export interface Job { - id: string; - name: string; - type: string; - cronExpression: string; - timeZone: string; - tags: string[]; - lastRun: string; - nextRun: string; - ownerId: string; - isActive: boolean; - group: string; - pixel: string; - smtpHost: string; - smtpPort: string; - subject: string; - jobType: string; - to: string[]; - cc: string[]; - bcc: string[]; - from: string; - message: string; - username: string; - password: string; + id: string; + name: string; + type: string; + cronExpression: string; + timeZone: string; + tags: string[]; + lastRun: string; + nextRun: string; + ownerId: string; + isActive: boolean; + group: string; + pixel: string; + smtpHost: string; + smtpPort: string; + subject: string; + jobType: string; + to: string[]; + cc: string[]; + bcc: string[]; + from: string; + message: string; + username: string; + password: string; } export interface HistoryJob { - jobId: string; - jobName: string; - jobGroup: string; - execStart: string; - execEnd: string; - execDelta: string; - success: boolean; - jobTags: string[]; - isLatest: boolean; - schedulerOutput: string; + jobId: string; + jobName: string; + jobGroup: string; + execStart: string; + execEnd: string; + execDelta: string; + success: boolean; + jobTags: string[]; + isLatest: boolean; + schedulerOutput: string; } export interface HistoryPaginationProps { - page?: number; - rowsPerPage?: number; - search?: string; - reload?: boolean; + page?: number; + rowsPerPage?: number; + search?: string; + reload?: boolean; } export interface SendEmailJob { - smtpHost: string; - smtpPort: string; - subject: string; - jobType: string; - to: string; - cc: string; - bcc: string; - from: string; - message: string; - username: string; - password: string; + smtpHost: string; + smtpPort: string; + subject: string; + jobType: string; + to: string; + cc: string; + bcc: string; + from: string; + message: string; + username: string; + password: string; } -export type Frequencies = 'Daily' | 'Weekly' | 'Monthly' | 'Yearly'; +export type Frequencies = "Daily" | "Weekly" | "Monthly" | "Yearly"; export type DayOfWeek = - | 'Sunday' - | 'Monday' - | 'Tuesday' - | 'Wednesday' - | 'Thursday' - | 'Friday' - | 'Saturday'; + | "Sunday" + | "Monday" + | "Tuesday" + | "Wednesday" + | "Thursday" + | "Friday" + | "Saturday"; export type Month = - | 'January' - | 'February' - | 'March' - | 'April' - | 'May' - | 'June' - | 'July' - | 'August' - | 'September' - | 'October' - | 'November' - | 'December'; + | "January" + | "February" + | "March" + | "April" + | "May" + | "June" + | "July" + | "August" + | "September" + | "October" + | "November" + | "December"; -export type JobTypes = 'Custom Job' | 'Send Email'; +export type JobTypes = "Custom Job" | "Send Email"; diff --git a/packages/client/src/pages/jobs/job.utils.ts b/packages/client/src/pages/jobs/job.utils.ts index 94d6716d35..74a8855826 100644 --- a/packages/client/src/pages/jobs/job.utils.ts +++ b/packages/client/src/pages/jobs/job.utils.ts @@ -1,172 +1,172 @@ import { - DaysOfWeek, - JobTypeCustomJob, - JobTypeSendEmail, - Months, -} from './job.constants'; -import { JobBuilder, SendEmailJob } from './job.types'; + DaysOfWeek, + JobTypeCustomJob, + JobTypeSendEmail, + Months, +} from "./job.constants"; +import type { JobBuilder, SendEmailJob } from "./job.types"; export function getHumanReadableCronExpression(cronExpression: string) { - const cronValues = cronExpression.split(' '); - if (cronValues.length < 6) { - return 'Invalid cron syntax'; - } else if (Number.isNaN(cronValues[1]) || Number.isNaN(cronValues[2])) { - return cronValues.slice(0, 6).join(' '); - } + const cronValues = cronExpression.split(" "); + if (cronValues.length < 6) { + return "Invalid cron syntax"; + } else if (Number.isNaN(cronValues[1]) || Number.isNaN(cronValues[2])) { + return cronValues.slice(0, 6).join(" "); + } - try { - if ( - cronValues[3] == '*' && - cronValues[4] == '*' && - cronValues[5] == '*' - ) { - // daily frequency - const displayHour = - parseInt(cronValues[2]) === 0 - ? 12 - : parseInt(cronValues[2]) > 12 - ? parseInt(cronValues[2]) - 12 - : parseInt(cronValues[2]); - const displayMinute = parseInt(cronValues[1]); - const amPm = parseInt(cronValues[2]) >= 12 ? 'PM' : 'AM'; - return `Daily at ${displayHour}:${ - displayMinute < 10 ? `0${displayMinute}` : displayMinute - } ${amPm}`; - } else if (cronValues[3] == '*' && cronValues[4] == '*') { - // weekly frequency - const displayHour = - parseInt(cronValues[2]) === 0 - ? 12 - : parseInt(cronValues[2]) > 12 - ? parseInt(cronValues[2]) - 12 - : parseInt(cronValues[2]); - const displayMinute = parseInt(cronValues[1]); - const amPm = parseInt(cronValues[2]) >= 12 ? 'PM' : 'AM'; - const dayOfWeek = DaysOfWeek.find( - (value) => value.value == parseInt(cronValues[5]), - ); - return `Every ${dayOfWeek.day} at ${displayHour}:${ - displayMinute < 10 ? `0${displayMinute}` : displayMinute - } ${amPm}`; - } else if (cronValues[4] == '*' && cronValues[5] == '*') { - // monthly frequency - const displayHour = - parseInt(cronValues[2]) === 0 - ? 12 - : parseInt(cronValues[2]) > 12 - ? parseInt(cronValues[2]) - 12 - : parseInt(cronValues[2]); - const displayMinute = parseInt(cronValues[1]); - const amPm = parseInt(cronValues[2]) >= 12 ? 'PM' : 'AM'; - return `Every month on day ${cronValues[3]} at ${displayHour}:${ - displayMinute < 10 ? `0${displayMinute}` : displayMinute - } ${amPm}`; - } else if (cronValues[5] == '*') { - const displayHour = - parseInt(cronValues[2]) === 0 - ? 12 - : parseInt(cronValues[2]) > 12 - ? parseInt(cronValues[2]) - 12 - : parseInt(cronValues[2]); - const displayMinute = parseInt(cronValues[1]); - const amPm = parseInt(cronValues[2]) >= 12 ? 'PM' : 'AM'; - const month = Months.find( - (value) => value.value == parseInt(cronValues[4]), - ); - return `Yearly on ${month.month} ${ - cronValues[3] - } at ${displayHour}:${ - displayMinute < 10 ? `0${displayMinute}` : displayMinute - } ${amPm}`; - } else { - return cronValues.slice(0, 6).join(' '); - } - } catch (e) { - return cronValues.slice(0, 6).join(' '); - } + try { + if ( + cronValues[3] == "*" && + cronValues[4] == "*" && + cronValues[5] == "*" + ) { + // daily frequency + const displayHour = + parseInt(cronValues[2]) === 0 + ? 12 + : parseInt(cronValues[2]) > 12 + ? parseInt(cronValues[2]) - 12 + : parseInt(cronValues[2]); + const displayMinute = parseInt(cronValues[1]); + const amPm = parseInt(cronValues[2]) >= 12 ? "PM" : "AM"; + return `Daily at ${displayHour}:${ + displayMinute < 10 ? `0${displayMinute}` : displayMinute + } ${amPm}`; + } else if (cronValues[3] == "*" && cronValues[4] == "*") { + // weekly frequency + const displayHour = + parseInt(cronValues[2]) === 0 + ? 12 + : parseInt(cronValues[2]) > 12 + ? parseInt(cronValues[2]) - 12 + : parseInt(cronValues[2]); + const displayMinute = parseInt(cronValues[1]); + const amPm = parseInt(cronValues[2]) >= 12 ? "PM" : "AM"; + const dayOfWeek = DaysOfWeek.find( + (value) => value.value == parseInt(cronValues[5]), + ); + return `Every ${dayOfWeek.day} at ${displayHour}:${ + displayMinute < 10 ? `0${displayMinute}` : displayMinute + } ${amPm}`; + } else if (cronValues[4] == "*" && cronValues[5] == "*") { + // monthly frequency + const displayHour = + parseInt(cronValues[2]) === 0 + ? 12 + : parseInt(cronValues[2]) > 12 + ? parseInt(cronValues[2]) - 12 + : parseInt(cronValues[2]); + const displayMinute = parseInt(cronValues[1]); + const amPm = parseInt(cronValues[2]) >= 12 ? "PM" : "AM"; + return `Every month on day ${cronValues[3]} at ${displayHour}:${ + displayMinute < 10 ? `0${displayMinute}` : displayMinute + } ${amPm}`; + } else if (cronValues[5] == "*") { + const displayHour = + parseInt(cronValues[2]) === 0 + ? 12 + : parseInt(cronValues[2]) > 12 + ? parseInt(cronValues[2]) - 12 + : parseInt(cronValues[2]); + const displayMinute = parseInt(cronValues[1]); + const amPm = parseInt(cronValues[2]) >= 12 ? "PM" : "AM"; + const month = Months.find( + (value) => value.value == parseInt(cronValues[4]), + ); + return `Yearly on ${month.month} ${ + cronValues[3] + } at ${displayHour}:${ + displayMinute < 10 ? `0${displayMinute}` : displayMinute + } ${amPm}`; + } else { + return cronValues.slice(0, 6).join(" "); + } + } catch (e) { + return cronValues.slice(0, 6).join(" "); + } } export function convertTimetoDate(time) { - const today = new Date(), - dd = String(today.getDate()).padStart(2, '0'), - mm = String(today.getMonth() + 1).padStart(2, '0'), - yyyy = today.getFullYear(), - currentDate = yyyy + '-' + mm + '-' + dd, - jobDate = time.split(' ')[0], - jobTime = time.split(' ')[1].split(':'), - jobHour = Number(jobTime[0]), - jobMin = jobTime[1]; + const today = new Date(), + dd = String(today.getDate()).padStart(2, "0"), + mm = String(today.getMonth() + 1).padStart(2, "0"), + yyyy = today.getFullYear(), + currentDate = yyyy + "-" + mm + "-" + dd, + jobDate = time.split(" ")[0], + jobTime = time.split(" ")[1].split(":"), + jobHour = Number(jobTime[0]), + jobMin = jobTime[1]; - let runDateString = ''; + let runDateString = ""; - if (jobDate === currentDate) { - runDateString += 'Today at '; - } else { - runDateString += jobDate + ' at '; - } + if (jobDate === currentDate) { + runDateString += "Today at "; + } else { + runDateString += jobDate + " at "; + } - if (jobHour > 12) - runDateString += - (jobHour - 12).toString() + ':' + jobMin.toString() + 'pm'; - else if (jobHour === 12) runDateString += '12' + ':' + jobMin + 'pm'; - else if (jobHour === 0) runDateString += '12' + ':' + jobMin + 'am'; - else runDateString += jobHour.toString() + ':' + jobMin + 'am'; + if (jobHour > 12) + runDateString += + (jobHour - 12).toString() + ":" + jobMin.toString() + "pm"; + else if (jobHour === 12) runDateString += "12" + ":" + jobMin + "pm"; + else if (jobHour === 0) runDateString += "12" + ":" + jobMin + "am"; + else runDateString += jobHour.toString() + ":" + jobMin + "am"; - return runDateString; + return runDateString; } export function convertDeltaToRuntimeString(duration) { - // padding for leading zeros - function _pad(number: number) { - let tempNumStr = number + ''; + // padding for leading zeros + function _pad(number: number) { + let tempNumStr = number + ""; - for (let i = tempNumStr.length; i < 3; i++) { - tempNumStr = '0' + tempNumStr; - } + for (let i = tempNumStr.length; i < 3; i++) { + tempNumStr = "0" + tempNumStr; + } - return tempNumStr; - } - let milliseconds = _pad(parseFloat(String((duration % 1000) / 100)) * 100); - const seconds = Math.floor((duration / 1000) % 60); - const minutes = Math.floor((duration / (1000 * 60)) % 60); - const hours = Math.floor((duration / (1000 * 60 * 60)) % 24); + return tempNumStr; + } + let milliseconds = _pad(parseFloat(String((duration % 1000) / 100)) * 100); + const seconds = Math.floor((duration / 1000) % 60); + const minutes = Math.floor((duration / (1000 * 60)) % 60); + const hours = Math.floor((duration / (1000 * 60 * 60)) % 24); - const hoursStr = hours < 10 ? '0' + hours : hours; - const minutesStr = minutes < 10 ? '0' + minutes : minutes; - const secondsStr = seconds < 10 ? '0' + seconds : seconds; + const hoursStr = hours < 10 ? "0" + hours : hours; + const minutesStr = minutes < 10 ? "0" + minutes : minutes; + const secondsStr = seconds < 10 ? "0" + seconds : seconds; - // always have milliseconds a let size - while (milliseconds.length < 3) { - milliseconds = milliseconds + '0'; - } - milliseconds = milliseconds.substring(0, 3); - return hoursStr + ':' + minutesStr + ':' + secondsStr + '.' + milliseconds; + // always have milliseconds a let size + while (milliseconds.length < 3) { + milliseconds = milliseconds + "0"; + } + milliseconds = milliseconds.substring(0, 3); + return hoursStr + ":" + minutesStr + ":" + secondsStr + "." + milliseconds; } export function convertSendEmailRecipeToJob(recipe: string): SendEmailJob { - if (!recipe.includes('SendEmail')) { - return; - } - const recipeMatches: RegExpMatchArray = recipe.match(/(?<=\().*/g); - if (recipeMatches.length === 0) { - return; - } - let cleanedRecipe: string = recipeMatches[0]; - cleanedRecipe = cleanedRecipe.replaceAll(/[\(\[\]\;\)]/g, ''); - cleanedRecipe = cleanedRecipe.replaceAll(',,', ','); - cleanedRecipe = cleanedRecipe.replaceAll('=', "':"); - cleanedRecipe = cleanedRecipe.replaceAll("', ", "', '"); - cleanedRecipe = cleanedRecipe.replaceAll("'", '"'); - cleanedRecipe = `{"${cleanedRecipe}}`; - const job: SendEmailJob = JSON.parse(cleanedRecipe); - return job; + if (!recipe.includes("SendEmail")) { + return; + } + const recipeMatches: RegExpMatchArray = recipe.match(/(?<=\().*/g); + if (recipeMatches.length === 0) { + return; + } + let cleanedRecipe: string = recipeMatches[0]; + cleanedRecipe = cleanedRecipe.replaceAll(/[([\];)]/g, ""); + cleanedRecipe = cleanedRecipe.replaceAll(",,", ","); + cleanedRecipe = cleanedRecipe.replaceAll("=", "':"); + cleanedRecipe = cleanedRecipe.replaceAll("', ", "', '"); + cleanedRecipe = cleanedRecipe.replaceAll("'", '"'); + cleanedRecipe = `{"${cleanedRecipe}}`; + const job: SendEmailJob = JSON.parse(cleanedRecipe); + return job; } export function getEncodeByJobType(builder: JobBuilder) { - switch (builder.jobType) { - case JobTypeCustomJob: - return builder.pixel; - case JobTypeSendEmail: - return `SendEmail(smtpHost=['${builder.smtpHost}'], smtpPort=['${builder.smtpPort}'], subject=['${builder.subject}'], to=['${builder.to}'], cc=['${builder.cc}'], bcc=['${builder.bcc}'], from=['${builder.from}'], message=['${builder.message}'], username=['${builder.username}'], password=['${builder.password}']);`; - } + switch (builder.jobType) { + case JobTypeCustomJob: + return builder.pixel; + case JobTypeSendEmail: + return `SendEmail(smtpHost=['${builder.smtpHost}'], smtpPort=['${builder.smtpPort}'], subject=['${builder.subject}'], to=['${builder.to}'], cc=['${builder.cc}'], bcc=['${builder.bcc}'], from=['${builder.from}'], message=['${builder.message}'], username=['${builder.username}'], password=['${builder.password}']);`; + } } diff --git a/packages/client/src/pages/legal/CookieNotice.tsx b/packages/client/src/pages/legal/CookieNotice.tsx index fdfa023d79..c785e305f1 100644 --- a/packages/client/src/pages/legal/CookieNotice.tsx +++ b/packages/client/src/pages/legal/CookieNotice.tsx @@ -1,15 +1,15 @@ -import { useRootStore } from '@/hooks'; -import { observer } from 'mobx-react-lite'; -import { LegalPage } from './components/legalPage'; +import { observer } from "mobx-react-lite"; +import { useRootStore } from "@/hooks"; +import { LegalPage } from "./components/legalPage"; export const CookieNotice = observer(() => { - const { configStore } = useRootStore(); + const { configStore } = useRootStore(); - const html = configStore.theme.cookiePolicyNoticePage; + const html = configStore.theme.cookiePolicyNoticePage; - return ( - -
    - - ); + return ( + +
    + + ); }); diff --git a/packages/client/src/pages/legal/PrivacyNotice.tsx b/packages/client/src/pages/legal/PrivacyNotice.tsx index 4b42d93ac9..e417e7d6ae 100644 --- a/packages/client/src/pages/legal/PrivacyNotice.tsx +++ b/packages/client/src/pages/legal/PrivacyNotice.tsx @@ -1,15 +1,15 @@ -import { useRootStore } from '@/hooks'; -import { observer } from 'mobx-react-lite'; -import { LegalPage } from './components/legalPage'; +import { observer } from "mobx-react-lite"; +import { useRootStore } from "@/hooks"; +import { LegalPage } from "./components/legalPage"; export const PrivacyNotice = observer(() => { - const { configStore } = useRootStore(); + const { configStore } = useRootStore(); - const html = configStore.theme.privacyNoticePage; + const html = configStore.theme.privacyNoticePage; - return ( - -
    - - ); + return ( + +
    + + ); }); diff --git a/packages/client/src/pages/legal/components/legalPage.tsx b/packages/client/src/pages/legal/components/legalPage.tsx index 7c8c45e8ad..789a242793 100644 --- a/packages/client/src/pages/legal/components/legalPage.tsx +++ b/packages/client/src/pages/legal/components/legalPage.tsx @@ -1,23 +1,23 @@ -import { styled } from '@semoss/ui'; +import { styled } from "@semoss/ui"; -const StyledPage = styled('div')(({ theme }) => ({ - width: '100%', - display: 'flex', - justifyContent: 'center', - padding: `${theme.spacing(7)} ${theme.spacing(5)}`, +const StyledPage = styled("div")(({ theme }) => ({ + width: "100%", + display: "flex", + justifyContent: "center", + padding: `${theme.spacing(7)} ${theme.spacing(5)}`, })); -const StyledBody = styled('div')(({ theme }) => ({ - width: '100%', - maxWidth: '1800px', - backgroundColor: theme.palette.background.paper, - padding: theme.spacing(3), +const StyledBody = styled("div")(({ theme }) => ({ + width: "100%", + maxWidth: "1800px", + backgroundColor: theme.palette.background.paper, + padding: theme.spacing(3), })); export const LegalPage = ({ children }) => { - return ( - - {children} - - ); + return ( + + {children} + + ); }; diff --git a/packages/client/src/pages/prompt/PromptModal.tsx b/packages/client/src/pages/prompt/PromptModal.tsx index 9ed959b072..f7b978b803 100644 --- a/packages/client/src/pages/prompt/PromptModal.tsx +++ b/packages/client/src/pages/prompt/PromptModal.tsx @@ -1,254 +1,254 @@ -import { useEffect, useState } from 'react'; +import { ModeCommentOutlined } from "@mui/icons-material"; +import { validateHeaderName } from "http"; +import { useEffect, useState } from "react"; import { - Button, - Stack, - Typography, - TextField, - styled, - Modal, - FormControl, - Autocomplete, -} from '@semoss/ui'; -import { usePixel, useRootStore } from '@/hooks'; -import { ModeCommentOutlined } from '@mui/icons-material'; -import { validateHeaderName } from 'http'; + Autocomplete, + Button, + FormControl, + Modal, + Stack, + styled, + TextField, + Typography, +} from "@semoss/ui"; +import { usePixel, useRootStore } from "@/hooks"; interface PromptModalProps { - isOpen: boolean; - onClose(reload: boolean): void; - mode: string; - inputContext?: any; - inputTitle?: any; - inputIntent?: any; - inputTags?: any; - prompt?: any; + isOpen: boolean; + onClose(reload: boolean): void; + mode: string; + inputContext?: any; + inputTitle?: any; + inputIntent?: any; + inputTags?: any; + prompt?: any; } const StyledStack = styled(Stack)(() => ({ - margin: '24px 16px', + margin: "24px 16px", })); const StyledTypographyLabel = styled(Typography)(() => ({ - color: 'var(--Text-Primary, #212121)', - fontFeatureSettings: "'liga' off, 'clig' off", - /* Typography/Body 1 */ - fontFamily: 'Inter', - fontSize: '16px', - fontStyle: 'normal', - fontWeight: 400, - lineHeight: '150%' /* 24px */, - letterSpacing: '0.15px', + color: "var(--Text-Primary, #212121)", + fontFeatureSettings: "'liga' off, 'clig' off", + /* Typography/Body 1 */ + fontFamily: "Inter", + fontSize: "16px", + fontStyle: "normal", + fontWeight: 400, + lineHeight: "150%" /* 24px */, + letterSpacing: "0.15px", })); const StyledTypographyTitle = styled(Typography)(() => ({ - color: 'var(--Text-Primary, #212121)', - fontFeatureSettings: "'liga' off, 'clig' off", - /* Typography/Body 1 */ - fontFamily: 'Inter', - fontSize: '20px', - fontStyle: 'normal', - fontWeight: 500, - lineHeight: '160%' /* 24px */, - letterSpacing: '0.15px', + color: "var(--Text-Primary, #212121)", + fontFeatureSettings: "'liga' off, 'clig' off", + /* Typography/Body 1 */ + fontFamily: "Inter", + fontSize: "20px", + fontStyle: "normal", + fontWeight: 500, + lineHeight: "160%" /* 24px */, + letterSpacing: "0.15px", })); export const PromptModal = (props: PromptModalProps) => { - const { configStore, monolithStore } = useRootStore(); - const { isOpen, onClose, mode, prompt } = props; - const [context, setContext] = useState(''); - const [title, setTitle] = useState(''); - const [intent, setIntent] = useState(''); - const [tags, setTags] = useState([]); + const { configStore, monolithStore } = useRootStore(); + const { isOpen, onClose, mode, prompt } = props; + const [context, setContext] = useState(""); + const [title, setTitle] = useState(""); + const [intent, setIntent] = useState(""); + const [tags, setTags] = useState([]); - const addPrompt = () => { - const promptMap = { - context: context, - title: title, - intent: intent, - tags: tags, - }; - const stringified = - 'AddPrompt ( map = [' + JSON.stringify(promptMap) + ' ])'; - monolithStore.runQuery(stringified).then((response) => { - const { pixelReturn } = response; - onClose(true); - }); - }; + const addPrompt = () => { + const promptMap = { + context: context, + title: title, + intent: intent, + tags: tags, + }; + const stringified = + "AddPrompt ( map = [" + JSON.stringify(promptMap) + " ])"; + monolithStore.runQuery(stringified).then((response) => { + const { pixelReturn } = response; + onClose(true); + }); + }; - const updatePrompt = () => { - console.log(prompt); - const promptMap = { - context: context, - title: title, - intent: intent, - tags: tags, - id: prompt['id'], - }; - const stringified = - 'UpdatePrompt ( map = [' + JSON.stringify(promptMap) + ' ])'; - monolithStore.runQuery(stringified).then((response) => { - const { pixelReturn } = response; - onClose(true); - }); - }; + const updatePrompt = () => { + console.log(prompt); + const promptMap = { + context: context, + title: title, + intent: intent, + tags: tags, + id: prompt["id"], + }; + const stringified = + "UpdatePrompt ( map = [" + JSON.stringify(promptMap) + " ])"; + monolithStore.runQuery(stringified).then((response) => { + const { pixelReturn } = response; + onClose(true); + }); + }; - const disableCreate = () => { - return title == '' || title == null || context == '' || context == null; - }; + const disableCreate = () => { + return title == "" || title == null || context == "" || context == null; + }; - const createContextString = () => { - const stringArr = []; - if (prompt?.['inputs']) { - prompt['inputs'].forEach((input) => { - let currInput = ''; - if (input.type != 'text') { - currInput = '{{' + input.key + '}}'; - stringArr.push(currInput); - } else { - stringArr.push(input.key); - } - }); + const createContextString = () => { + const stringArr = []; + if (prompt?.["inputs"]) { + prompt["inputs"].forEach((input) => { + let currInput = ""; + if (input.type != "text") { + currInput = "{{" + input.key + "}}"; + stringArr.push(currInput); + } else { + stringArr.push(input.key); + } + }); - return stringArr.join(' '); - } else if (prompt?.['context']) { - return prompt?.['context']; - } + return stringArr.join(" "); + } else if (prompt?.["context"]) { + return prompt?.["context"]; + } - return ''; - }; + return ""; + }; - useEffect(() => { - if (mode == 'Edit' || prompt != null) { - console.log(createContextString()); - setContext(createContextString()); - setTitle(prompt['title']); - setIntent(prompt['intent']); - setTags(prompt['tags']); - } - }, [mode, prompt]); - return ( - - {mode} Prompt - - - - Prompt Title - - - { - setTitle(e.target.value); - }} - > - - - - - Prompt Context - - - { - setContext(e.target.value); - }} - > - - - - - Intent - - - { - setIntent(e.target.value); - }} - > - - - - - Tags - - - { - setTags(newValue); - }} - options={[]} - freeSolo - renderInput={(params) => ( - - )} - /> - - - - - - - - - ); + useEffect(() => { + if (mode == "Edit" || prompt != null) { + console.log(createContextString()); + setContext(createContextString()); + setTitle(prompt["title"]); + setIntent(prompt["intent"]); + setTags(prompt["tags"]); + } + }, [mode, prompt]); + return ( + + {mode} Prompt + + + + Prompt Title + + + { + setTitle(e.target.value); + }} + > + + + + + Prompt Context + + + { + setContext(e.target.value); + }} + > + + + + + Intent + + + { + setIntent(e.target.value); + }} + > + + + + + Tags + + + { + setTags(newValue); + }} + options={[]} + freeSolo + renderInput={(params) => ( + + )} + /> + + + + + + + + + ); }; diff --git a/packages/client/src/pages/prompt/PromptPage.tsx b/packages/client/src/pages/prompt/PromptPage.tsx index b7f0725189..46975420dc 100644 --- a/packages/client/src/pages/prompt/PromptPage.tsx +++ b/packages/client/src/pages/prompt/PromptPage.tsx @@ -1,177 +1,177 @@ -import { useEffect, useState } from 'react'; -import { observer } from 'mobx-react-lite'; -import { Button, Stack, Typography, useNotification, Grid } from '@semoss/ui'; -import { useRootStore } from '@/hooks'; -import { PromptModal } from './PromptModal'; -import { PromptLibraryCards } from '../../components/prompt/library/PromptLibraryCards'; -import { Prompt } from '../../components/prompt/prompt.types'; -import { PromptLibraryList } from '@/components/prompt/library/PromptLibraryList'; +import { observer } from "mobx-react-lite"; +import { useEffect, useState } from "react"; +import { Button, Grid, Stack, Typography, useNotification } from "@semoss/ui"; +import { PromptLibraryList } from "@/components/prompt/library/PromptLibraryList"; +import { useRootStore } from "@/hooks"; +import { PromptLibraryCards } from "../../components/prompt/library/PromptLibraryCards"; +import type { Prompt } from "../../components/prompt/prompt.types"; +import { PromptModal } from "./PromptModal"; export const PromptPage = observer(() => { - const { monolithStore } = useRootStore(); - const [isPromptModalOpen, setIsPromptModalOpen] = useState(false); - const [promptMode, setPromptMode] = useState(''); - const [promptToEdit, setPromptToEdit] = useState({}); - const [pageReload, setPageReload] = useState(false); + const { monolithStore } = useRootStore(); + const [isPromptModalOpen, setIsPromptModalOpen] = useState(false); + const [promptMode, setPromptMode] = useState(""); + const [promptToEdit, setPromptToEdit] = useState({}); + const [pageReload, setPageReload] = useState(false); - const [filter, setFilter] = useState('all'); - const [allPrompts, setAllPrompts] = useState([]); + const [filter, setFilter] = useState("all"); + const [allPrompts, setAllPrompts] = useState([]); - /** - * @desc Load prompts - */ - useEffect(() => { - init(); - }, [pageReload]); + /** + * @desc Load prompts + */ + useEffect(() => { + init(); + }, [pageReload]); - /** - * @desc Gets All prompts - */ - const init = () => { - monolithStore.runQuery('ListPrompt()').then((response) => { - const { output } = response.pixelReturn[0]; - if (output.length > 0) { - const promptArr = []; - output.map((prompt) => { - promptArr.push({ - context: prompt.CONTEXT ? prompt.CONTEXT : '', - created_by: prompt.CREATED_BY ? prompt.CREATED_BY : '', - date_created: prompt.DATE_CREATED - ? prompt.DATE_CREATED - : '', - id: prompt.ID ? prompt.ID : '', - intent: prompt.INTENT ? prompt.INTENT : '', - title: prompt.TITLE ? prompt.TITLE : '', - tags: prompt.tags ? prompt.tags : [], - }); - }); - setAllPrompts(promptArr); - } - }); - }; + /** + * @desc Gets All prompts + */ + const init = () => { + monolithStore.runQuery("ListPrompt()").then((response) => { + const { output } = response.pixelReturn[0]; + if (output.length > 0) { + const promptArr = []; + output.map((prompt) => { + promptArr.push({ + context: prompt.CONTEXT ? prompt.CONTEXT : "", + created_by: prompt.CREATED_BY ? prompt.CREATED_BY : "", + date_created: prompt.DATE_CREATED + ? prompt.DATE_CREATED + : "", + id: prompt.ID ? prompt.ID : "", + intent: prompt.INTENT ? prompt.INTENT : "", + title: prompt.TITLE ? prompt.TITLE : "", + tags: prompt.tags ? prompt.tags : [], + }); + }); + setAllPrompts(promptArr); + } + }); + }; - /** - * @desc Filters our prompts based on filter specified - * TODO: Have backend handle filtering on ListPrompt() - */ - const filteredPrompts = () => { - return allPrompts.length > 0 - ? allPrompts - .filter((prompt) => { - if (filter == 'all') { - return true; - } else { - return prompt.tags - ? prompt.tags.includes(filter) - : false; - } - }) - .sort(function (a, b) { - const firstTitle = a.title.toLowerCase(); - const secondTitle = b.title.toLowerCase(); - if (firstTitle < secondTitle) { - return -1; - } - if (firstTitle > secondTitle) { - return 1; - } - return 0; - }) - : []; - }; + /** + * @desc Filters our prompts based on filter specified + * TODO: Have backend handle filtering on ListPrompt() + */ + const filteredPrompts = () => { + return allPrompts.length > 0 + ? allPrompts + .filter((prompt) => { + if (filter == "all") { + return true; + } else { + return prompt.tags + ? prompt.tags.includes(filter) + : false; + } + }) + .sort((a, b) => { + const firstTitle = a.title.toLowerCase(); + const secondTitle = b.title.toLowerCase(); + if (firstTitle < secondTitle) { + return -1; + } + if (firstTitle > secondTitle) { + return 1; + } + return 0; + }) + : []; + }; - /** - * @desc Used on click of prompt card - */ - async function handlePromptEditClick(p: Prompt) { - const tempPrompt = { - title: p.title, - tags: p.tags, - context: p.context, - id: p.id, - intent: p.intent ? p.intent : '', - }; - setPromptToEdit(tempPrompt); - setPromptMode('Edit'); - setIsPromptModalOpen(true); - } + /** + * @desc Used on click of prompt card + */ + async function handlePromptEditClick(p: Prompt) { + const tempPrompt = { + title: p.title, + tags: p.tags, + context: p.context, + id: p.id, + intent: p.intent ? p.intent : "", + }; + setPromptToEdit(tempPrompt); + setPromptMode("Edit"); + setIsPromptModalOpen(true); + } - return ( - - - - - - Prompt Catalog - - - - - - - Our prompt catalog is a versatile library of prompts - designed for various use cases. It offers an abstracted - interface, allowing developers and data scientists to - easily select and integrate the right prompts into their - applications. This flexibility ensures optimized - workflows and improved outcomes. - - - - - - - - - { - handlePromptEditClick(p); - }} - /> - - - { - setIsPromptModalOpen(false); - if (reload) { - setPageReload(!pageReload); - } - }} - mode={promptMode} - > - - ); + return ( + + + + + + Prompt Catalog + + + + + + + Our prompt catalog is a versatile library of prompts + designed for various use cases. It offers an abstracted + interface, allowing developers and data scientists to + easily select and integrate the right prompts into their + applications. This flexibility ensures optimized + workflows and improved outcomes. + + + + + + + + + { + handlePromptEditClick(p); + }} + /> + + + { + setIsPromptModalOpen(false); + if (reload) { + setPageReload(!pageReload); + } + }} + mode={promptMode} + > + + ); }); diff --git a/packages/client/src/pages/prompt/PromptRouter.tsx b/packages/client/src/pages/prompt/PromptRouter.tsx index f8c09d0654..229f7ab3c5 100644 --- a/packages/client/src/pages/prompt/PromptRouter.tsx +++ b/packages/client/src/pages/prompt/PromptRouter.tsx @@ -1,12 +1,12 @@ -import { observer } from 'mobx-react-lite'; -import { Routes, Route } from 'react-router-dom'; -import { PromptPage } from './PromptPage'; -import { PromptBuilder } from '@/components/prompt'; +import { observer } from "mobx-react-lite"; +import { Route, Routes } from "react-router-dom"; +import { PromptBuilder } from "@/components/prompt"; +import { PromptPage } from "./PromptPage"; export const PromptRouter = observer(() => { - return ( - - } /> - - ); + return ( + + } /> + + ); }); diff --git a/packages/client/src/pages/prompt/index.ts b/packages/client/src/pages/prompt/index.ts index 2769581356..b744954090 100644 --- a/packages/client/src/pages/prompt/index.ts +++ b/packages/client/src/pages/prompt/index.ts @@ -1,3 +1,3 @@ -import { PromptRouter } from './PromptRouter'; +import { PromptRouter } from "./PromptRouter"; export { PromptRouter }; diff --git a/packages/client/src/pages/settings/AdminQueryPage.tsx b/packages/client/src/pages/settings/AdminQueryPage.tsx index 3bd9ddc0bf..7e30a7f327 100644 --- a/packages/client/src/pages/settings/AdminQueryPage.tsx +++ b/packages/client/src/pages/settings/AdminQueryPage.tsx @@ -1,317 +1,315 @@ -import { useEffect, useState } from 'react'; -import { Controller, useForm } from 'react-hook-form'; -import { Navigate } from 'react-router-dom'; - +import { useEffect, useState } from "react"; +import { Controller, useForm } from "react-hook-form"; +import { Navigate } from "react-router-dom"; import { - styled, - useNotification, - Alert, - Button, - TextField, - Select, - Table, - TextArea, -} from '@semoss/ui'; - -import { useRootStore, useSettings } from '@/hooks'; + Alert, + Button, + Select, + styled, + Table, + TextArea, + TextField, + useNotification, +} from "@semoss/ui"; +import { useRootStore, useSettings } from "@/hooks"; -const StyledContainer = styled('div')(() => ({ - display: 'flex', - width: '100%', - gap: '24px', +const StyledContainer = styled("div")(() => ({ + display: "flex", + width: "100%", + gap: "24px", })); -const StyledLeft = styled('div')(() => ({ - display: 'flex', - flexDirection: 'column', - width: '100%', +const StyledLeft = styled("div")(() => ({ + display: "flex", + flexDirection: "column", + width: "100%", })); -const StyledRight = styled('div')(() => ({ - overflow: 'scroll', - width: '100%', - marginTop: '20px', +const StyledRight = styled("div")(() => ({ + overflow: "scroll", + width: "100%", + marginTop: "20px", })); -const Styledform = styled('div')(() => ({ - width: '100%', +const Styledform = styled("div")(() => ({ + width: "100%", })); -const StyledStack = styled('div')(() => ({ - width: '100%', - gap: '20px', - display: 'flex', - marginBottom: '20px', +const StyledStack = styled("div")(() => ({ + width: "100%", + gap: "20px", + display: "flex", + marginBottom: "20px", })); const DATABASE_OPTIONS = [ - 'LocalMasterDatabase', - 'security', - 'scheduler', - 'themes', - 'UserTrackingDatabase', + "LocalMasterDatabase", + "security", + "scheduler", + "themes", + "UserTrackingDatabase", ]; interface TypeDbQuery { - SELECTED_DATABASE: string; - QUERY: string; - ROWS: number; + SELECTED_DATABASE: string; + QUERY: string; + ROWS: number; } export const AdminQueryPage = () => { - const { monolithStore } = useRootStore(); - const { adminMode } = useSettings(); - const notification = useNotification(); + const { monolithStore } = useRootStore(); + const { adminMode } = useSettings(); + const notification = useNotification(); - if (!adminMode) { - return ; - } - const [output, setOutput] = useState<{ - type: string; - value: any; - }>({ - type: '', - value: '', - }); + if (!adminMode) { + return ; + } + const [output, setOutput] = useState<{ + type: string; + value: any; + }>({ + type: "", + value: "", + }); - const [showRowsField, setShowRowsField] = useState(false); + const [showRowsField, setShowRowsField] = useState(false); - const { control, watch, setValue, handleSubmit } = useForm<{ - SELECTED_DATABASE: string; - QUERY: string; - ROWS: number; - }>({ - defaultValues: { - SELECTED_DATABASE: '', - QUERY: '', - ROWS: 100, - }, - }); + const { control, watch, setValue, handleSubmit } = useForm<{ + SELECTED_DATABASE: string; + QUERY: string; + ROWS: number; + }>({ + defaultValues: { + SELECTED_DATABASE: "", + QUERY: "", + ROWS: 100, + }, + }); - const query = watch('QUERY'); - const selectedDatabase = watch('SELECTED_DATABASE'); + const query = watch("QUERY"); + const selectedDatabase = watch("SELECTED_DATABASE"); - const disableButton = query && selectedDatabase ? true : false; + const disableButton = query && selectedDatabase ? true : false; - useEffect(() => { - verifySelectQuery(); - }, [query]); + useEffect(() => { + verifySelectQuery(); + }, [query]); - /** - * @name verifySelectQuery - * @desc check whether the query contains SELECT, - * and if so update the ROWS field and show or hide field - */ - function verifySelectQuery() { - if (query.toUpperCase().startsWith('SELECT')) { - // show rows field - setShowRowsField(true); - } else { - if (showRowsField) { - // don't show rows field - setShowRowsField(false); - setValue('ROWS', 0); - } - } - } + /** + * @name verifySelectQuery + * @desc check whether the query contains SELECT, + * and if so update the ROWS field and show or hide field + */ + function verifySelectQuery() { + if (query.toUpperCase().startsWith("SELECT")) { + // show rows field + setShowRowsField(true); + } else { + if (showRowsField) { + // don't show rows field + setShowRowsField(false); + setValue("ROWS", 0); + } + } + } - /** - * @name submitQuery - * @desc make runQuery API call based on submitted fields - */ - const submitQuery = handleSubmit((data: TypeDbQuery) => { - let pixelString = `META | AdminDatabase("${data.SELECTED_DATABASE}") | Query("${data.QUERY}")`; + /** + * @name submitQuery + * @desc make runQuery API call based on submitted fields + */ + const submitQuery = handleSubmit((data: TypeDbQuery) => { + let pixelString = `META | AdminDatabase("${data.SELECTED_DATABASE}") | Query("${data.QUERY}")`; - if (showRowsField) { - pixelString += `| Collect(${data.ROWS});`; - } else { - // No collect - pixelString += '| AdminExecQuery();'; - } - monolithStore - .runQuery(pixelString) - .then((response) => { - let output = undefined; - let type = undefined; + if (showRowsField) { + pixelString += `| Collect(${data.ROWS});`; + } else { + // No collect + pixelString += "| AdminExecQuery();"; + } + monolithStore + .runQuery(pixelString) + .then((response) => { + let output; + let type; - output = response.pixelReturn[0].output; - type = response.pixelReturn[0].operationType[0]; + output = response.pixelReturn[0].output; + type = response.pixelReturn[0].operationType[0]; - if (type.indexOf('ERROR') > -1) { - setOutput({ - type: 'error', - value: output, - }); - notification.add({ - color: 'error', - message: output, - }); + if (type.indexOf("ERROR") > -1) { + setOutput({ + type: "error", + value: output, + }); + notification.add({ + color: "error", + message: output, + }); - return; - } + return; + } - // if we have a select query returning data - else if (output instanceof Object) { - setOutput({ - type: 'table', - value: { - headers: output.data.headers, - values: output.data.values, - }, - }); - } + // if we have a select query returning data + else if (output instanceof Object) { + setOutput({ + type: "table", + value: { + headers: output.data.headers, + values: output.data.values, + }, + }); + } - // if we have a non-select query - else { - setOutput({ - type: 'success', - value: '', - }); - } + // if we have a non-select query + else { + setOutput({ + type: "success", + value: "", + }); + } - notification.add({ - color: 'success', - message: 'Successfully submitted query', - }); - }) - .catch((error) => { - notification.add({ - color: 'error', - message: error, - }); - }); - }); + notification.add({ + color: "success", + message: "Successfully submitted query", + }); + }) + .catch((error) => { + notification.add({ + color: "error", + message: error, + }); + }); + }); - /** - * @name displayQueryOutput - * @desc return alert or table based on the queryOutputType - * @returns JSX.Element - */ - const displayQueryOutput = (): JSX.Element => { - if (output.type === 'success') { - return Successful query!; - } else if (output.type === 'error') { - return {output.value}; - } else if (output.type === 'table') { - return ( - - - - {output.value.headers.map((header, index) => ( - - {header} - - ))} - - - - {output.value.values.map((row, index) => ( - - {row.map((column, i) => ( - - {column} - - ))} - - ))} - -
    - ); - } - }; + /** + * @name displayQueryOutput + * @desc return alert or table based on the queryOutputType + * @returns JSX.Element + */ + const displayQueryOutput = (): JSX.Element => { + if (output.type === "success") { + return Successful query!; + } else if (output.type === "error") { + return {output.value}; + } else if (output.type === "table") { + return ( + + + + {output.value.headers.map((header, index) => ( + + {header} + + ))} + + + + {output.value.values.map((row, index) => ( + + {row.map((column, i) => ( + + {column} + + ))} + + ))} + +
    + ); + } + }; - return ( - - - - - { - return ( - - ); - }} - /> - { - return ( - - field.onChange(e.target.value) - } - type={'number'} - > - ); - }} - /> - - - { - return ( - - ); - }} - /> - - {!output.type - ? 'Execute a query to display the results here.' - : displayQueryOutput()} - - - - - ); + return ( + + + + + { + return ( + + ); + }} + /> + { + return ( + + field.onChange(e.target.value) + } + type={"number"} + > + ); + }} + /> + + + { + return ( + + ); + }} + /> + + {!output.type + ? "Execute a query to display the results here." + : displayQueryOutput()} + + + + + ); }; diff --git a/packages/client/src/pages/settings/AppSettingsDetailPage.tsx b/packages/client/src/pages/settings/AppSettingsDetailPage.tsx index 6cf33da88e..ca53b661dd 100644 --- a/packages/client/src/pages/settings/AppSettingsDetailPage.tsx +++ b/packages/client/src/pages/settings/AppSettingsDetailPage.tsx @@ -1,166 +1,165 @@ -import { useState, useEffect } from 'react'; -import { useParams, useNavigate } from 'react-router-dom'; -import { styled, ToggleTabsGroup } from '@semoss/ui'; - -import { Role } from '@/types'; -import { useSettings, useAPI } from '@/hooks'; +import { useEffect, useState } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { styled, ToggleTabsGroup } from "@semoss/ui"; +import { AppSettings } from "@/components/app"; import { - PendingMembersTable, - MembersTable, - SettingsTiles, -} from '@/components/settings'; -import { AppSettings } from '@/components/app'; - -const StyledContainer = styled('div')(({ theme }) => ({ - width: '100%', - display: 'flex', - alignSelf: 'stretch', - flexDirection: 'column', - alignItems: 'flex-start', - gap: theme.spacing(2), + MembersTable, + PendingMembersTable, + SettingsTiles, +} from "@/components/settings"; +import { useAPI, useSettings } from "@/hooks"; +import type { Role } from "@/types"; + +const StyledContainer = styled("div")(({ theme }) => ({ + width: "100%", + display: "flex", + alignSelf: "stretch", + flexDirection: "column", + alignItems: "flex-start", + gap: theme.spacing(2), })); -const StyledContent = styled('div')(({ theme }) => ({ - display: 'flex', - width: '100%', - flexDirection: 'column', - alignItems: 'flex-start', - gap: theme.spacing(2), - flexShrink: '0', +const StyledContent = styled("div")(({ theme }) => ({ + display: "flex", + width: "100%", + flexDirection: "column", + alignItems: "flex-start", + gap: theme.spacing(2), + flexShrink: "0", })); -type VIEW = 'CURRENT' | 'PENDING' | 'APP'; +type VIEW = "CURRENT" | "PENDING" | "APP"; export const AppSettingsUserDetailPage = () => { - const { id } = useParams(); - const navigate = useNavigate(); - - const [view, setView] = useState('CURRENT'); - const [permission, setPermission] = useState(null); - - const getUserEnginePermission = useAPI(['getUserProjectPermission', id]); - - /** - * @name useEffect - * @desc - Set Permission to see Pending Requests - */ - useEffect(() => { - if (getUserEnginePermission.status !== 'SUCCESS') { - return; - } - - if ( - !getUserEnginePermission.data || - !getUserEnginePermission.data.permission - ) { - setPermission(null); - return; - } - - // set the permission - setPermission(getUserEnginePermission.data.permission); - }, [getUserEnginePermission.status, getUserEnginePermission.data]); - - // if there is no permission, ignore - if (!permission) { - return null; - } - - return ( - - {permission === 'OWNER' ? ( - { - navigate('/settings/app'); - }} - /> - ) : null} - - setView(v as VIEW)} - > - - - - - {view === 'CURRENT' && ( - getUserEnginePermission.refresh()} - /> - )} - {view === 'PENDING' && ( - - )} - {view === 'APP' && } - - - ); + const { id } = useParams(); + const navigate = useNavigate(); + + const [view, setView] = useState("CURRENT"); + const [permission, setPermission] = useState(null); + + const getUserEnginePermission = useAPI(["getUserProjectPermission", id]); + + /** + * @name useEffect + * @desc - Set Permission to see Pending Requests + */ + useEffect(() => { + if (getUserEnginePermission.status !== "SUCCESS") { + return; + } + + if ( + !getUserEnginePermission.data || + !getUserEnginePermission.data.permission + ) { + setPermission(null); + return; + } + + // set the permission + setPermission(getUserEnginePermission.data.permission); + }, [getUserEnginePermission.status, getUserEnginePermission.data]); + + // if there is no permission, ignore + if (!permission) { + return null; + } + + return ( + + {permission === "OWNER" ? ( + { + navigate("/settings/app"); + }} + /> + ) : null} + + setView(v as VIEW)} + > + + + + + {view === "CURRENT" && ( + getUserEnginePermission.refresh()} + /> + )} + {view === "PENDING" && ( + + )} + {view === "APP" && } + + + ); }; export const AppSettingsAdminDetailPage = () => { - const { id } = useParams(); - const navigate = useNavigate(); - - const [view, setView] = useState('CURRENT'); - - return ( - - { - navigate('/settings/app'); - }} - /> - - setView(v as VIEW)} - > - - - - - {view === 'CURRENT' && } - {view === 'PENDING' && ( - - )} - {view === 'APP' && } - - - ); + const { id } = useParams(); + const navigate = useNavigate(); + + const [view, setView] = useState("CURRENT"); + + return ( + + { + navigate("/settings/app"); + }} + /> + + setView(v as VIEW)} + > + + + + + {view === "CURRENT" && } + {view === "PENDING" && ( + + )} + {view === "APP" && } + + + ); }; export const AppSettingsDetailPage = () => { - const { adminMode } = useSettings(); - - return ( - <> - {adminMode ? ( - - ) : ( - - )} - - ); + const { adminMode } = useSettings(); + + return ( + <> + {adminMode ? ( + + ) : ( + + )} + + ); }; diff --git a/packages/client/src/pages/settings/ConfigurationsPage.tsx b/packages/client/src/pages/settings/ConfigurationsPage.tsx index 656b7b324f..03f7b7cd0e 100644 --- a/packages/client/src/pages/settings/ConfigurationsPage.tsx +++ b/packages/client/src/pages/settings/ConfigurationsPage.tsx @@ -1,406 +1,405 @@ -import React, { - useEffect, - useState, - useReducer, - useRef, - SyntheticEvent, - Suspense, - lazy, -} from 'react'; - -import { useAPI, useRootStore, useSettings } from '@/hooks'; -import { LoadingScreen } from '@/components/ui'; +import { KeyboardArrowDown } from "@mui/icons-material"; +import type React from "react"; import { - Divider, - Accordion, - Button, - Search, - styled, - TextField, - ToggleTabsGroup, - Typography, - useNotification, - Box, -} from '@semoss/ui'; -import google from '../../assets/img/google.png'; -import ms from '../../assets/img/ms.png'; -import dropbox from '../../assets/img/dropbox.png'; -import github from '../../assets/img/github.png'; -import other from '../../assets/img/other.png'; - -import { useNavigate } from 'react-router-dom'; -import { KeyboardArrowDown } from '@mui/icons-material'; - -const Editor = lazy(() => import('@monaco-editor/react')); + lazy, + Suspense, + type SyntheticEvent, + useEffect, + useReducer, + useRef, + useState, +} from "react"; +import { useNavigate } from "react-router-dom"; +import { + Accordion, + Box, + Button, + Divider, + Search, + styled, + TextField, + ToggleTabsGroup, + Typography, + useNotification, +} from "@semoss/ui"; +import { LoadingScreen } from "@/components/ui"; +import { useAPI, useRootStore, useSettings } from "@/hooks"; +import dropbox from "../../assets/img/dropbox.png"; +import github from "../../assets/img/github.png"; +import google from "../../assets/img/google.png"; +import ms from "../../assets/img/ms.png"; +import other from "../../assets/img/other.png"; + +const Editor = lazy(() => import("@monaco-editor/react")); const SOCIAL = { - google: { - name: 'Google', - image: google, - }, - ms: { - name: 'Microsoft', - image: ms, - }, - dropbox: { - name: 'Dropbox', - image: dropbox, - }, - github: { - name: 'Github', - image: github, - }, - native: { - name: 'Native', - image: other, - }, + google: { + name: "Google", + image: google, + }, + ms: { + name: "Microsoft", + image: ms, + }, + dropbox: { + name: "Dropbox", + image: dropbox, + }, + github: { + name: "Github", + image: github, + }, + native: { + name: "Native", + image: other, + }, }; -const StyledConfigurationsOptionsAccordion = styled('div')({ - display: 'flex', +const StyledConfigurationsOptionsAccordion = styled("div")({ + display: "flex", }); const StyledAccordion = styled(Accordion)({ - width: '291px', + width: "291px", }); const StyledBox = styled(Box)({ - padding: '0px 12px 12px 12px', + padding: "0px 12px 12px 12px", }); const StyledAccordionContent = styled(Accordion.Content)({ - fontSize: '14px', - margin: 0, - padding: '12px 16px 16px 16px', + fontSize: "14px", + margin: 0, + padding: "12px 16px 16px 16px", }); const StyledListButton = styled(Button)(({ theme }) => ({ - textTransform: 'none', - width: '100%', - justifyContent: 'left', + textTransform: "none", + width: "100%", + justifyContent: "left", })); const StyledDivider = styled(Divider)({ - marginBottom: '8px', + marginBottom: "8px", }); -const StyledImage = styled('img')({ - objectFit: 'cover', - maxHeight: '28px', - maxWidth: '28px', - verticalAlign: 'middle', - padding: '4px', +const StyledImage = styled("img")({ + objectFit: "cover", + maxHeight: "28px", + maxWidth: "28px", + verticalAlign: "middle", + padding: "4px", }); -const StyledTitle = styled('div')(({ theme }) => ({ - marginBottom: theme.spacing(2), - display: 'flex', - justifyContent: 'space-between', +const StyledTitle = styled("div")(({ theme }) => ({ + marginBottom: theme.spacing(2), + display: "flex", + justifyContent: "space-between", })); -const StyledActionButtonsDiv = styled('div')(() => ({ - display: 'flex', - justifyContent: 'center', - gap: '.5rem', +const StyledActionButtonsDiv = styled("div")(() => ({ + display: "flex", + justifyContent: "center", + gap: ".5rem", })); const StyledButton = styled(Button)({ - textTransform: 'none', - fontWeight: 'bold', + textTransform: "none", + fontWeight: "bold", }); -const StyledForm = styled('form')(({ theme }) => ({ - marginLeft: theme.spacing(8), - width: '100%', +const StyledForm = styled("form")(({ theme }) => ({ + marginLeft: theme.spacing(8), + width: "100%", })); -const StyledKeyValue = styled('div')(({ theme }) => ({ - display: 'flex', - marginBottom: theme.spacing(2), +const StyledKeyValue = styled("div")(({ theme }) => ({ + display: "flex", + marginBottom: theme.spacing(2), })); -const StyledPropContainer = styled('div')(({ theme }) => ({ - display: 'flex', - flexDirection: 'column', - marginBottom: theme.spacing(2), - padding: '24px', - borderRadius: '15px', - backgroundColor: 'rgba(255, 255, 255, 1)', - boxShadow: '0px 5px 22px 0px rgba(0, 0, 0, 0.06)', +const StyledPropContainer = styled("div")(({ theme }) => ({ + display: "flex", + flexDirection: "column", + marginBottom: theme.spacing(2), + padding: "24px", + borderRadius: "15px", + backgroundColor: "rgba(255, 255, 255, 1)", + boxShadow: "0px 5px 22px 0px rgba(0, 0, 0, 0.06)", })); const StyledToggleTabsGroup = styled(ToggleTabsGroup)({ - marginBottom: '16px', + marginBottom: "16px", }); const StyledTextField = styled(TextField)({ - marginRight: '12px', + marginRight: "12px", }); const initialState = { - socialProps: {}, + socialProps: {}, }; const reducer = (state, action) => { - switch (action.type) { - case 'field': { - return { - ...state, - [action.field]: action.value, - }; - } - } - return state; + switch (action.type) { + case "field": { + return { + ...state, + [action.field]: action.value, + }; + } + } + return state; }; export const ConfigurationsPage = () => { - const { adminMode } = useSettings(); - - const navigate = useNavigate(); - - if (!adminMode) { - navigate('/settings'); - } - - const [state, dispatch] = useReducer(reducer, initialState); - const { socialProps } = state; - - const [accordionValue, setAccordionValue] = useState(); - - const [authentication, setAuthentication] = useState( - Object.keys(socialProps), - ); - - const [tabValue, setTabValue] = useState(0); - - const [authSearch, setAuthSearch] = useState(''); - const authSearchBarRef = useRef(null); - - const loginProperties = useAPI(['getLoginProperties']); - - useEffect(() => { - // pixel call to get pending members - if (loginProperties.status !== 'SUCCESS' || !loginProperties.data) { - return; - } - - // Key is the label for each accordion, the value is an array of fields - const formattedProperties = {}; - Object.entries(loginProperties.data).map((pr) => { - if (pr[0] === 'cac') return; // angular js ui doesn't paint cac - const fields = []; - Object.entries(pr[1]).map((prop) => { - const fieldMap = { - label: prop[0], - value: prop[1], - }; - - fields.push(fieldMap); - }); - - if (!formattedProperties[pr[0]]) { - formattedProperties[pr[0]] = fields; - } - }); - - dispatch({ - type: 'field', - field: 'socialProps', - value: formattedProperties, - }); - - if (!accordionValue) { - setAccordionValue(Object.keys(formattedProperties)[0]); - } - setAuthentication(Object.keys(formattedProperties)); - authSearchBarRef.current?.focus(); - }, [loginProperties.status, loginProperties.data]); - - useEffect(() => { - // reset the options if there is no search value - if (!authSearch) { - setAuthentication(Object.keys(socialProps)); - return; - } - - const cleanedSearch = authSearch.toLowerCase(); - - const filtered = authentication.filter((c) => { - return c.toLowerCase().includes(cleanedSearch); - }); - - setAuthentication(filtered); - }, [authSearch]); - - // show a loading screen when loginProperties is pending - if (loginProperties.status !== 'SUCCESS' || !Object.keys(socialProps)) { - return ( - - ); - } - - const onTabChange = (event: SyntheticEvent, newValue: number) => { - setTabValue(newValue); - }; - - const updateSocialProps = ( - fieldName: string, - value: string, - label: string, - index, - ) => { - const socialPropsCopy = socialProps; - socialPropsCopy[fieldName][index]['value'] = value; - - dispatch({ - type: 'field', - field: 'socialProps', - value: socialPropsCopy, - }); - // setSocialProps(socialPropsCopy); - }; - - /** - * @name resetLoginProperties - * @desc refreshes getLoginProperties - */ - const resetLoginProperties = () => { - loginProperties.refresh(); - }; - - const settingsPage = () => { - return Object.keys(socialProps) ? ( - -
    - - }> - - Authentication - - - - { - setAuthSearch(e.target.value); - }} - /> - - {authentication.map((value, i) => { - return ( - - { - setAccordionValue(value); - }} - data-testid={`configuration-page-auth-${value}-btn`} - > - - {SOCIAL[value]?.name || - value[0].toUpperCase() + - value.slice(1)} - - - ); - })} - -
    - {accordionValue && ( - - )} -
    - ) : ( -
    No socials props
    - ); - }; - - const fileContentsPage = () => { - const defaultTyping = ``; - return ( - - - social.properties - - - - Reset - - - Save - - - - - ...}> - - - - ); - }; - - const customTogglePanel = ( - children: React.ReactNode, - index: number, - value: number, - ) => { - return ( - - ); - }; - - return ( - <> - - - - - - {customTogglePanel(settingsPage(), 0, tabValue)} - {customTogglePanel(fileContentsPage(), 1, tabValue)} - - - ); + const { adminMode } = useSettings(); + + const navigate = useNavigate(); + + if (!adminMode) { + navigate("/settings"); + } + + const [state, dispatch] = useReducer(reducer, initialState); + const { socialProps } = state; + + const [accordionValue, setAccordionValue] = useState(); + + const [authentication, setAuthentication] = useState( + Object.keys(socialProps), + ); + + const [tabValue, setTabValue] = useState(0); + + const [authSearch, setAuthSearch] = useState(""); + const authSearchBarRef = useRef(null); + + const loginProperties = useAPI(["getLoginProperties"]); + + useEffect(() => { + // pixel call to get pending members + if (loginProperties.status !== "SUCCESS" || !loginProperties.data) { + return; + } + + // Key is the label for each accordion, the value is an array of fields + const formattedProperties = {}; + Object.entries(loginProperties.data).map((pr) => { + if (pr[0] === "cac") return; // angular js ui doesn't paint cac + const fields = []; + Object.entries(pr[1]).map((prop) => { + const fieldMap = { + label: prop[0], + value: prop[1], + }; + + fields.push(fieldMap); + }); + + if (!formattedProperties[pr[0]]) { + formattedProperties[pr[0]] = fields; + } + }); + + dispatch({ + type: "field", + field: "socialProps", + value: formattedProperties, + }); + + if (!accordionValue) { + setAccordionValue(Object.keys(formattedProperties)[0]); + } + setAuthentication(Object.keys(formattedProperties)); + authSearchBarRef.current?.focus(); + }, [loginProperties.status, loginProperties.data]); + + useEffect(() => { + // reset the options if there is no search value + if (!authSearch) { + setAuthentication(Object.keys(socialProps)); + return; + } + + const cleanedSearch = authSearch.toLowerCase(); + + const filtered = authentication.filter((c) => { + return c.toLowerCase().includes(cleanedSearch); + }); + + setAuthentication(filtered); + }, [authSearch]); + + // show a loading screen when loginProperties is pending + if (loginProperties.status !== "SUCCESS" || !Object.keys(socialProps)) { + return ( + + ); + } + + const onTabChange = (event: SyntheticEvent, newValue: number) => { + setTabValue(newValue); + }; + + const updateSocialProps = ( + fieldName: string, + value: string, + label: string, + index, + ) => { + const socialPropsCopy = socialProps; + socialPropsCopy[fieldName][index]["value"] = value; + + dispatch({ + type: "field", + field: "socialProps", + value: socialPropsCopy, + }); + // setSocialProps(socialPropsCopy); + }; + + /** + * @name resetLoginProperties + * @desc refreshes getLoginProperties + */ + const resetLoginProperties = () => { + loginProperties.refresh(); + }; + + const settingsPage = () => { + return Object.keys(socialProps) ? ( + +
    + + }> + + Authentication + + + + { + setAuthSearch(e.target.value); + }} + /> + + {authentication.map((value, i) => { + return ( + + { + setAccordionValue(value); + }} + data-testid={`configuration-page-auth-${value}-btn`} + > + + {SOCIAL[value]?.name || + value[0].toUpperCase() + + value.slice(1)} + + + ); + })} + +
    + {accordionValue && ( + + )} +
    + ) : ( +
    No socials props
    + ); + }; + + const fileContentsPage = () => { + const defaultTyping = ``; + return ( + + + social.properties + + + + Reset + + + Save + + + + + ...}> + + + + ); + }; + + const customTogglePanel = ( + children: React.ReactNode, + index: number, + value: number, + ) => { + return ( + + ); + }; + + return ( + <> + + + + + + {customTogglePanel(settingsPage(), 0, tabValue)} + {customTogglePanel(fileContentsPage(), 1, tabValue)} + + + ); }; const mapDefaultValues = (vals: FieldProps[]) => { - const value = {}; + const value = {}; - vals.forEach((f: FieldProps) => { - value[f.label] = f.value || ''; - }); + vals.forEach((f: FieldProps) => { + value[f.label] = f.value || ""; + }); - return value; + return value; }; interface FieldProps { - label: string; - value: string; + label: string; + value: string; } // interface PropertyProps { @@ -410,88 +409,88 @@ interface FieldProps { // } const SocialProperty = (props) => { - const { fieldName, fields, resetLoginProperties, updateSocialProps } = - props; - - const { monolithStore } = useRootStore(); - const notification = useNotification(); - - /** - * @name onSubmit - * @desc changes properties based on updates to social props - * @param data - form data - */ - const onSubmit = () => { - const values = mapDefaultValues(fields); - monolithStore.modifyLoginProperties(fieldName, values).then(() => { - notification.add({ - color: 'success', - message: `Succesfully modified ${fieldName} properties`, - }); - }); - }; - - return ( - - - - {fieldName.charAt(0).toUpperCase() + fieldName.slice(1)} - - - - { - resetLoginProperties(fieldName); - }} - data-testid={'configuration-page-reset-btn'} - > - Reset - - onSubmit()} - data-testid={'configuration-page-save-btn'} - > - Save - - - - - {fields.map((f, i) => { - return ( - - - - { - updateSocialProps( - fieldName, - e.target.value, - f.label, - i, - ); - }} - /> - - - ); - })} - - ); + const { fieldName, fields, resetLoginProperties, updateSocialProps } = + props; + + const { monolithStore } = useRootStore(); + const notification = useNotification(); + + /** + * @name onSubmit + * @desc changes properties based on updates to social props + * @param data - form data + */ + const onSubmit = () => { + const values = mapDefaultValues(fields); + monolithStore.modifyLoginProperties(fieldName, values).then(() => { + notification.add({ + color: "success", + message: `Succesfully modified ${fieldName} properties`, + }); + }); + }; + + return ( + + + + {fieldName.charAt(0).toUpperCase() + fieldName.slice(1)} + + + + { + resetLoginProperties(fieldName); + }} + data-testid={"configuration-page-reset-btn"} + > + Reset + + onSubmit()} + data-testid={"configuration-page-save-btn"} + > + Save + + + + + {fields.map((f, i) => { + return ( + + + + { + updateSocialProps( + fieldName, + e.target.value, + f.label, + i, + ); + }} + /> + + + ); + })} + + ); }; { - /* + /*
    Property diff --git a/packages/client/src/pages/settings/DatabaseSettingsPage.tsx b/packages/client/src/pages/settings/DatabaseSettingsPage.tsx index 9d90e83ff6..b426df23e0 100644 --- a/packages/client/src/pages/settings/DatabaseSettingsPage.tsx +++ b/packages/client/src/pages/settings/DatabaseSettingsPage.tsx @@ -1,531 +1,527 @@ -import { useEffect, useState, useRef, useReducer } from 'react'; -import { useRootStore, usePixel, useAPI } from '@/hooks'; -import { useSettings } from '@/hooks/useSettings'; -import { useNavigate } from 'react-router-dom'; - import { - Grid, - Search, - Select, - MenuItem, - ToggleButton, - ToggleButtonGroup, - styled, - Backdrop, - CircularProgress, - Stack, - Typography, -} from '@semoss/ui'; - + FormatListBulletedOutlined, + SpaceDashboardOutlined, +} from "@mui/icons-material"; +import { useEffect, useReducer, useRef, useState } from "react"; +import { useNavigate } from "react-router-dom"; import { - SpaceDashboardOutlined, - FormatListBulletedOutlined, -} from '@mui/icons-material'; - -import { EngineLandscapeCard, EngineTileCard } from '@/components/engine'; - -import { removeUnderscores } from '@/utility'; + Backdrop, + CircularProgress, + Grid, + MenuItem, + Search, + Select, + Stack, + styled, + ToggleButton, + ToggleButtonGroup, + Typography, +} from "@semoss/ui"; +import { EngineLandscapeCard, EngineTileCard } from "@/components/engine"; +import { useAPI, usePixel, useRootStore } from "@/hooks"; +import { useSettings } from "@/hooks/useSettings"; +import { removeUnderscores } from "@/utility"; export interface DBMember { - ID: string; - NAME: string; - PERMISSION: string; - EMAIL: string; - SELECTED: boolean; + ID: string; + NAME: string; + PERMISSION: string; + EMAIL: string; + SELECTED: boolean; } export interface Database { - app_cost: string; - app_favorite: number; - app_id: string; - app_name: string; - app_type: string; - database_cost: string; - database_id: string; - database_name: string; - database_type: string; - low_database_name: string; - database_global: true; - database_favorite?: number; - permission?: number; - user_permission?: number; + app_cost: string; + app_favorite: number; + app_id: string; + app_name: string; + app_type: string; + database_cost: string; + database_id: string; + database_name: string; + database_type: string; + low_database_name: string; + database_global: true; + database_favorite?: number; + permission?: number; + user_permission?: number; } -const StyledContainer = styled('div')({ - display: 'flex', - width: 'auto', - flexDirection: 'column', - alignItems: 'flex-start', - gap: '24px', +const StyledContainer = styled("div")({ + display: "flex", + width: "auto", + flexDirection: "column", + alignItems: "flex-start", + gap: "24px", }); -const StyledSearchbarContainer = styled('div')({ - display: 'flex', - width: '100%', - alignItems: 'flex-start', - gap: '24px', +const StyledSearchbarContainer = styled("div")({ + display: "flex", + width: "100%", + alignItems: "flex-start", + gap: "24px", }); const StyledSearchbar = styled(Search)({ - width: '80%', + width: "80%", }); const StyledSort = styled(Select)({ - width: '20%', + width: "20%", }); const StyledBackdrop = styled(Backdrop)({ - backgroundColor: 'rgba(255, 255, 255, 0.5)', - zIndex: 1501, + backgroundColor: "rgba(255, 255, 255, 0.5)", + zIndex: 1501, }); const initialState = { - favoritedDbs: [], - databases: [], + favoritedDbs: [], + databases: [], }; const reducer = (state, action) => { - switch (action.type) { - case 'field': { - return { - ...state, - [action.field]: action.value, - }; - } - } - return state; + switch (action.type) { + case "field": { + return { + ...state, + [action.field]: action.value, + }; + } + } + return state; }; export const DatabaseSettingsPage = () => { - const { adminMode } = useSettings(); - const { configStore, monolithStore } = useRootStore(); - const navigate = useNavigate(); - - const [state, dispatch] = useReducer(reducer, initialState); - const { favoritedDbs, databases } = state; - - const [view, setView] = useState('tile'); - const [search, setSearch] = useState(''); - const [sort, setSort] = useState('Name'); - const [canCollect, setCanCollect] = useState(true); - const [offset, setOffset] = useState(0); - - //** amount of items to be loaded */ - const limit = 15; - - // To focus when getting new results - const searchbarRef = useRef(null); - - // get a list of the keys - const databaseMetaKeys = configStore.store.config.databaseMetaKeys.filter( - (k) => { - return ( - k.display_options === 'single-checklist' || - k.display_options === 'multi-checklist' || - k.display_options === 'single-select' || - k.display_options === 'multi-select' || - k.display_options === 'single-typeahead' || - k.display_options === 'multi-typeahead' || - k.display_options === 'textarea' - ); - }, - ); - - // get metakeys to the ones we want - const metaKeys = databaseMetaKeys.map((k) => { - return k.metakey; - }); - - // Favorites ---------------------------------- - const getFavoritedDatabases = usePixel(` + const { adminMode } = useSettings(); + const { configStore, monolithStore } = useRootStore(); + const navigate = useNavigate(); + + const [state, dispatch] = useReducer(reducer, initialState); + const { favoritedDbs, databases } = state; + + const [view, setView] = useState("tile"); + const [search, setSearch] = useState(""); + const [sort, setSort] = useState("Name"); + const [canCollect, setCanCollect] = useState(true); + const [offset, setOffset] = useState(0); + + //** amount of items to be loaded */ + const limit = 15; + + // To focus when getting new results + const searchbarRef = useRef(null); + + // get a list of the keys + const databaseMetaKeys = configStore.store.config.databaseMetaKeys.filter( + (k) => { + return ( + k.display_options === "single-checklist" || + k.display_options === "multi-checklist" || + k.display_options === "single-select" || + k.display_options === "multi-select" || + k.display_options === "single-typeahead" || + k.display_options === "multi-typeahead" || + k.display_options === "textarea" + ); + }, + ); + + // get metakeys to the ones we want + const metaKeys = databaseMetaKeys.map((k) => { + return k.metakey; + }); + + // Favorites ---------------------------------- + const getFavoritedDatabases = usePixel(` MyEngines(metaKeys = ${JSON.stringify( - metaKeys, - )}, filterWord=["${search}"], onlyFavorites=[true], engineTypes=['DATABASE']); + metaKeys, + )}, filterWord=["${search}"], onlyFavorites=[true], engineTypes=['DATABASE']); `); - useEffect(() => { - if (getFavoritedDatabases.status !== 'SUCCESS') { - return; - } - - dispatch({ - type: 'field', - field: 'favoritedDbs', - value: getFavoritedDatabases.data, - }); - - searchbarRef.current?.focus(); - }, [getFavoritedDatabases.status, getFavoritedDatabases.data]); - - // All Engines ------------------------------------- - const getEngines = useAPI([ - 'getEngines', - adminMode, - search, - 'DATABASE', - offset, - limit, - ]); - - //** reset dataMode if adminMode is toggled */ - useEffect(() => { - setOffset(0); - dispatch({ - type: 'field', - field: 'databases', - value: [], - }); - }, [adminMode, search]); - - //** append data through infinite scroll */ - useEffect(() => { - if (getEngines.status !== 'SUCCESS') { - return; - } - - if (getEngines.data.length < limit) { - setCanCollect(false); - } else { - if (!canCollectRef.current) { - setCanCollect(true); - } - } - - const mutateListWithVotes = databases; - - getEngines.data.forEach((db) => { - mutateListWithVotes.push({ - ...db, - upvotes: db.upvotes ? db.upvotes : 0, - views: 'N/A', - trending: 'N/A', - }); - }); - - dispatch({ - type: 'field', - field: 'databases', - value: mutateListWithVotes, - }); - - searchbarRef.current?.focus(); - }, [getEngines.status, getEngines.data]); - - /** - * @name favoriteDb - * @param db - */ - const favoriteDb = (db) => { - const favorite = !isFavorited(db.database_id); - monolithStore - .setEngineFavorite(db.database_id, favorite) - .then(() => { - if (!favorite) { - const newFavorites = favoritedDbs; - for (let i = newFavorites.length - 1; i >= 0; i--) { - if (newFavorites[i].database_id === db.database_id) { - newFavorites.splice(i, 1); - } - } - - dispatch({ - type: 'field', - field: 'favoritedDbs', - value: newFavorites, - }); - } else { - dispatch({ - type: 'field', - field: 'favoritedDbs', - value: [...favoritedDbs, db], - }); - } - }) - .catch((err) => { - // throw error if promise doesn't fulfill - throw Error(err); - }); - }; - - /** - * @name isFavorited - * @param id - */ - const isFavorited = (id) => { - const favorites = favoritedDbs; - - if (!favorites) return false; - return favorites.some((el) => el.database_id === id); - }; - - /** - * @name upvoteDb - * @param db - */ - const upvoteDb = (db) => { - let pixelString = ''; - - if (!db.hasUpvoted) { - pixelString += `VoteEngine(engine="${db.database_id}", vote=1)`; - } else { - pixelString += `UnvoteEngine(engine="${db.database_id}")`; - } - - monolithStore.runQuery(pixelString).then((response) => { - const type = response.pixelReturn[0].operationType; - - if (type.indexOf('ERROR') === -1) { - const newDatabases = []; - - databases.forEach((database) => { - if (database.database_id === db.database_id) { - const newCopy = database; - newCopy.upvotes = !db.hasUpvoted - ? newCopy.upvotes + 1 - : newCopy.upvotes - 1; - newCopy.hasUpvoted = !db.hasUpvoted ? true : false; - - newDatabases.push(newCopy); - } else { - newDatabases.push(database); - } - }); - - dispatch({ - type: 'field', - field: 'database', - value: newDatabases, - }); - } else { - console.error('Error voting for DB'); - } - }); - }; - - /** - * @name setDbGlobal - * @param db - */ - const setDbGlobal = (db) => { - monolithStore - .setEngineGlobal(adminMode, db.database_id, !db.database_global) - .then((response) => { - if (response.data.success) { - const newDatabases = []; - databases.forEach((database) => { - if (database.database_id === db.database_id) { - const newCopy = database; - newCopy.database_global = !db.database_global; - - newDatabases.push(newCopy); - } else { - newDatabases.push(database); - } - }); - - dispatch({ - type: 'field', - field: 'database', - value: newDatabases, - }); - } - }) - .catch((error) => { - console.error(error); - }); - }; - - //** infinite sroll variables */ - let scrollEle, scrollTimeout, currentScroll, previousScroll; - const offsetRef = useRef(0); - offsetRef.current = offset; - const canCollectRef = useRef(true); - canCollectRef.current = canCollect; - - const scrollAll = () => { - currentScroll = scrollEle.scrollTop + scrollEle.offsetHeight; - if ( - currentScroll > scrollEle.scrollHeight * 0.75 && - currentScroll > previousScroll - ) { - if (scrollTimeout) { - clearTimeout(scrollTimeout); - } - - scrollTimeout = setTimeout(() => { - if (!canCollectRef.current) { - return; - } - - setOffset(offsetRef.current + limit); - }, 500); - } - - previousScroll = currentScroll; - }; - - /** - * @desc infinite scroll - */ - useEffect(() => { - scrollEle = document.querySelector('#home__content'); - scrollEle.addEventListener('scroll', scrollAll); - return () => { - scrollEle.removeEventListener('scroll', scrollAll); - }; - }, [scrollEle]); - - return ( - <> - - - - Loading - Databases - - - - - { - setSearch(e.target.value); - }} - size="small" - onClear={() => setSearch('')} - ref={searchbarRef} - /> - setSort(e.target.value)} - > - Name - Date Created - Views - Trending - Upvotes - - - - setView(v)} - value={'tile'} - > - - - setView(v)} - value={'list'} - > - - - - - - {databases.length - ? databases.map((db, i) => { - return ( - - {view === 'list' ? ( - { - favoriteDb(db); - }} - onClick={() => { - navigate( - `${db.database_id}`, - { - state: { - name: removeUnderscores( - db.database_name, - ), - global: db.database_global, - permission: - db.permission, - }, - }, - ); - }} - upvote={() => { - upvoteDb(db); - }} - global={() => { - setDbGlobal(db); - }} - /> - ) : ( - { - favoriteDb(db); - }} - onClick={() => { - navigate( - `${db.database_id}`, - { - state: { - name: removeUnderscores( - db.database_name, - ), - global: db.database_global, - permission: - db.permission, - }, - }, - ); - }} - upvote={() => { - upvoteDb(db); - }} - global={() => { - setDbGlobal(db); - }} - /> - )} - - ); - }) - : null} - - - - ); + useEffect(() => { + if (getFavoritedDatabases.status !== "SUCCESS") { + return; + } + + dispatch({ + type: "field", + field: "favoritedDbs", + value: getFavoritedDatabases.data, + }); + + searchbarRef.current?.focus(); + }, [getFavoritedDatabases.status, getFavoritedDatabases.data]); + + // All Engines ------------------------------------- + const getEngines = useAPI([ + "getEngines", + adminMode, + search, + "DATABASE", + offset, + limit, + ]); + + //** reset dataMode if adminMode is toggled */ + useEffect(() => { + setOffset(0); + dispatch({ + type: "field", + field: "databases", + value: [], + }); + }, [adminMode, search]); + + //** append data through infinite scroll */ + useEffect(() => { + if (getEngines.status !== "SUCCESS") { + return; + } + + if (getEngines.data.length < limit) { + setCanCollect(false); + } else { + if (!canCollectRef.current) { + setCanCollect(true); + } + } + + const mutateListWithVotes = databases; + + getEngines.data.forEach((db) => { + mutateListWithVotes.push({ + ...db, + upvotes: db.upvotes ? db.upvotes : 0, + views: "N/A", + trending: "N/A", + }); + }); + + dispatch({ + type: "field", + field: "databases", + value: mutateListWithVotes, + }); + + searchbarRef.current?.focus(); + }, [getEngines.status, getEngines.data]); + + /** + * @name favoriteDb + * @param db + */ + const favoriteDb = (db) => { + const favorite = !isFavorited(db.database_id); + monolithStore + .setEngineFavorite(db.database_id, favorite) + .then(() => { + if (!favorite) { + const newFavorites = favoritedDbs; + for (let i = newFavorites.length - 1; i >= 0; i--) { + if (newFavorites[i].database_id === db.database_id) { + newFavorites.splice(i, 1); + } + } + + dispatch({ + type: "field", + field: "favoritedDbs", + value: newFavorites, + }); + } else { + dispatch({ + type: "field", + field: "favoritedDbs", + value: [...favoritedDbs, db], + }); + } + }) + .catch((err) => { + // throw error if promise doesn't fulfill + throw Error(err); + }); + }; + + /** + * @name isFavorited + * @param id + */ + const isFavorited = (id) => { + const favorites = favoritedDbs; + + if (!favorites) return false; + return favorites.some((el) => el.database_id === id); + }; + + /** + * @name upvoteDb + * @param db + */ + const upvoteDb = (db) => { + let pixelString = ""; + + if (!db.hasUpvoted) { + pixelString += `VoteEngine(engine="${db.database_id}", vote=1)`; + } else { + pixelString += `UnvoteEngine(engine="${db.database_id}")`; + } + + monolithStore.runQuery(pixelString).then((response) => { + const type = response.pixelReturn[0].operationType; + + if (type.indexOf("ERROR") === -1) { + const newDatabases = []; + + databases.forEach((database) => { + if (database.database_id === db.database_id) { + const newCopy = database; + newCopy.upvotes = !db.hasUpvoted + ? newCopy.upvotes + 1 + : newCopy.upvotes - 1; + newCopy.hasUpvoted = !db.hasUpvoted ? true : false; + + newDatabases.push(newCopy); + } else { + newDatabases.push(database); + } + }); + + dispatch({ + type: "field", + field: "database", + value: newDatabases, + }); + } else { + console.error("Error voting for DB"); + } + }); + }; + + /** + * @name setDbGlobal + * @param db + */ + const setDbGlobal = (db) => { + monolithStore + .setEngineGlobal(adminMode, db.database_id, !db.database_global) + .then((response) => { + if (response.data.success) { + const newDatabases = []; + databases.forEach((database) => { + if (database.database_id === db.database_id) { + const newCopy = database; + newCopy.database_global = !db.database_global; + + newDatabases.push(newCopy); + } else { + newDatabases.push(database); + } + }); + + dispatch({ + type: "field", + field: "database", + value: newDatabases, + }); + } + }) + .catch((error) => { + console.error(error); + }); + }; + + //** infinite sroll variables */ + let scrollEle, scrollTimeout, currentScroll, previousScroll; + const offsetRef = useRef(0); + offsetRef.current = offset; + const canCollectRef = useRef(true); + canCollectRef.current = canCollect; + + const scrollAll = () => { + currentScroll = scrollEle.scrollTop + scrollEle.offsetHeight; + if ( + currentScroll > scrollEle.scrollHeight * 0.75 && + currentScroll > previousScroll + ) { + if (scrollTimeout) { + clearTimeout(scrollTimeout); + } + + scrollTimeout = setTimeout(() => { + if (!canCollectRef.current) { + return; + } + + setOffset(offsetRef.current + limit); + }, 500); + } + + previousScroll = currentScroll; + }; + + /** + * @desc infinite scroll + */ + useEffect(() => { + scrollEle = document.querySelector("#home__content"); + scrollEle.addEventListener("scroll", scrollAll); + return () => { + scrollEle.removeEventListener("scroll", scrollAll); + }; + }, [scrollEle]); + + return ( + <> + + + + Loading + Databases + + + + + { + setSearch(e.target.value); + }} + size="small" + onClear={() => setSearch("")} + ref={searchbarRef} + /> + setSort(e.target.value)} + > + Name + Date Created + Views + Trending + Upvotes + + + + setView(v)} + value={"tile"} + > + + + setView(v)} + value={"list"} + > + + + + + + {databases.length + ? databases.map((db, i) => { + return ( + + {view === "list" ? ( + { + favoriteDb(db); + }} + onClick={() => { + navigate( + `${db.database_id}`, + { + state: { + name: removeUnderscores( + db.database_name, + ), + global: db.database_global, + permission: + db.permission, + }, + }, + ); + }} + upvote={() => { + upvoteDb(db); + }} + global={() => { + setDbGlobal(db); + }} + /> + ) : ( + { + favoriteDb(db); + }} + onClick={() => { + navigate( + `${db.database_id}`, + { + state: { + name: removeUnderscores( + db.database_name, + ), + global: db.database_global, + permission: + db.permission, + }, + }, + ); + }} + upvote={() => { + upvoteDb(db); + }} + global={() => { + setDbGlobal(db); + }} + /> + )} + + ); + }) + : null} + + + + ); }; diff --git a/packages/client/src/pages/settings/EngineSettingsDetailPage.tsx b/packages/client/src/pages/settings/EngineSettingsDetailPage.tsx index 64b90afb86..61bf3ba740 100644 --- a/packages/client/src/pages/settings/EngineSettingsDetailPage.tsx +++ b/packages/client/src/pages/settings/EngineSettingsDetailPage.tsx @@ -1,177 +1,176 @@ -import { useState, useEffect } from 'react'; -import { useParams, useNavigate } from 'react-router-dom'; -import { styled, ToggleTabsGroup } from '@semoss/ui'; - -import { Role, ALL_TYPES } from '@/types'; -import { useSettings, useAPI } from '@/hooks'; +import { useEffect, useState } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { styled, ToggleTabsGroup } from "@semoss/ui"; import { - SettingsTiles, - PendingMembersTable, - MembersTable, - UpdateSMSS, -} from '@/components/settings'; - -const StyledContainer = styled('div')(({ theme }) => ({ - width: '100%', - display: 'flex', - alignSelf: 'stretch', - flexDirection: 'column', - alignItems: 'flex-start', - gap: theme.spacing(2), + MembersTable, + PendingMembersTable, + SettingsTiles, + UpdateSMSS, +} from "@/components/settings"; +import { useAPI, useSettings } from "@/hooks"; +import type { ALL_TYPES, Role } from "@/types"; + +const StyledContainer = styled("div")(({ theme }) => ({ + width: "100%", + display: "flex", + alignSelf: "stretch", + flexDirection: "column", + alignItems: "flex-start", + gap: theme.spacing(2), })); -const StyledContent = styled('div')(({ theme }) => ({ - display: 'flex', - width: '100%', - flexDirection: 'column', - alignItems: 'flex-start', - gap: theme.spacing(2), - flexShrink: '0', +const StyledContent = styled("div")(({ theme }) => ({ + display: "flex", + width: "100%", + flexDirection: "column", + alignItems: "flex-start", + gap: theme.spacing(2), + flexShrink: "0", })); -type VIEW = 'CURRENT' | 'PENDING'; +type VIEW = "CURRENT" | "PENDING"; /** * Show detailed settings for an engine */ interface EngineSettingsDetailPageProps { - /** Type of the page to render */ - type: ALL_TYPES; + /** Type of the page to render */ + type: ALL_TYPES; } export const EngineSettingsUserDetailPage = ( - props: EngineSettingsDetailPageProps, + props: EngineSettingsDetailPageProps, ) => { - const { type } = props; - - const { id } = useParams(); - const navigate = useNavigate(); - - const [view, setView] = useState('CURRENT'); - const [permission, setPermission] = useState(null); - - const getUserEnginePermission = useAPI(['getUserEnginePermission', id]); - - /** - * @name useEffect - * @desc - Set Permission to see Pending Requests - */ - useEffect(() => { - if (getUserEnginePermission.status !== 'SUCCESS') { - return; - } - - if ( - !getUserEnginePermission.data || - !getUserEnginePermission.data.permission - ) { - setPermission(null); - return; - } - - // set the permission - setPermission(getUserEnginePermission.data.permission); - }, [getUserEnginePermission.status, getUserEnginePermission.data]); - - // if there is no permission, ignore - if (!permission) { - return null; - } - - return ( - - {permission === 'OWNER' ? ( - { - navigate('..', { relative: 'path' }); - }} - /> - ) : null} - - setView(v as VIEW)} - > - - - - {view === 'CURRENT' && ( - getUserEnginePermission.refresh()} - /> - )} - {view === 'PENDING' && ( - - )} - - {permission === 'OWNER' ? : null} - - ); + const { type } = props; + + const { id } = useParams(); + const navigate = useNavigate(); + + const [view, setView] = useState("CURRENT"); + const [permission, setPermission] = useState(null); + + const getUserEnginePermission = useAPI(["getUserEnginePermission", id]); + + /** + * @name useEffect + * @desc - Set Permission to see Pending Requests + */ + useEffect(() => { + if (getUserEnginePermission.status !== "SUCCESS") { + return; + } + + if ( + !getUserEnginePermission.data || + !getUserEnginePermission.data.permission + ) { + setPermission(null); + return; + } + + // set the permission + setPermission(getUserEnginePermission.data.permission); + }, [getUserEnginePermission.status, getUserEnginePermission.data]); + + // if there is no permission, ignore + if (!permission) { + return null; + } + + return ( + + {permission === "OWNER" ? ( + { + navigate("..", { relative: "path" }); + }} + /> + ) : null} + + setView(v as VIEW)} + > + + + + {view === "CURRENT" && ( + getUserEnginePermission.refresh()} + /> + )} + {view === "PENDING" && ( + + )} + + {permission === "OWNER" ? : null} + + ); }; export const EngineSettingsAdminDetailPage = ( - props: EngineSettingsDetailPageProps, + props: EngineSettingsDetailPageProps, ) => { - const { type } = props; - - const { id } = useParams(); - const navigate = useNavigate(); - - const [view, setView] = useState('CURRENT'); - - return ( - - { - navigate('..', { relative: 'path' }); - }} - /> - - setView(v as VIEW)} - > - - - - {view === 'CURRENT' && } - {view === 'PENDING' && ( - - )} - - - - ); + const { type } = props; + + const { id } = useParams(); + const navigate = useNavigate(); + + const [view, setView] = useState("CURRENT"); + + return ( + + { + navigate("..", { relative: "path" }); + }} + /> + + setView(v as VIEW)} + > + + + + {view === "CURRENT" && } + {view === "PENDING" && ( + + )} + + + + ); }; export const EngineSettingsDetailPage = ( - props: EngineSettingsDetailPageProps, + props: EngineSettingsDetailPageProps, ) => { - const { adminMode } = useSettings(); - const { type } = props; - - return ( - <> - {adminMode ? ( - - ) : ( - - )} - - ); + const { adminMode } = useSettings(); + const { type } = props; + + return ( + <> + {adminMode ? ( + + ) : ( + + )} + + ); }; diff --git a/packages/client/src/pages/settings/EngineSettingsIndexPage.tsx b/packages/client/src/pages/settings/EngineSettingsIndexPage.tsx index 9f20fa8f2c..2bc3d31926 100644 --- a/packages/client/src/pages/settings/EngineSettingsIndexPage.tsx +++ b/packages/client/src/pages/settings/EngineSettingsIndexPage.tsx @@ -1,583 +1,580 @@ -import { useNavigate } from 'react-router-dom'; -import { useEffect, useState, useRef, useReducer } from 'react'; - import { - Grid, - Search, - Select, - MenuItem, - ToggleButton, - ToggleButtonGroup, - styled, - Backdrop, - CircularProgress, - Stack, - Typography, - Tooltip, -} from '@semoss/ui'; - + ArrowDownward, + ArrowUpward, + FormatListBulletedOutlined, + SpaceDashboardOutlined, +} from "@mui/icons-material"; +import { useEffect, useReducer, useRef, useState } from "react"; +import { useNavigate } from "react-router-dom"; import { - SpaceDashboardOutlined, - FormatListBulletedOutlined, - ArrowUpward, - ArrowDownward, -} from '@mui/icons-material'; - -import { ALL_TYPES } from '@/types'; -import { useRootStore, usePixel, useAPI, useSettings } from '@/hooks'; -import { EngineLandscapeCard, EngineTileCard } from '@/components/engine'; -import { removeUnderscores } from '@/utility'; + Backdrop, + CircularProgress, + Grid, + MenuItem, + Search, + Select, + Stack, + styled, + ToggleButton, + ToggleButtonGroup, + Tooltip, + Typography, +} from "@semoss/ui"; +import { EngineLandscapeCard, EngineTileCard } from "@/components/engine"; +import { useAPI, usePixel, useRootStore, useSettings } from "@/hooks"; +import type { ALL_TYPES } from "@/types"; +import { removeUnderscores } from "@/utility"; export interface DBMember { - ID: string; - NAME: string; - PERMISSION: string; - EMAIL: string; - SELECTED: boolean; + ID: string; + NAME: string; + PERMISSION: string; + EMAIL: string; + SELECTED: boolean; } export interface Database { - app_cost: string; - app_favorite: number; - app_id: string; - app_name: string; - app_type: string; - database_cost: string; - database_id: string; - database_name: string; - database_type: string; - low_database_name: string; - database_global: true; - database_favorite?: number; - permission?: number; - user_permission?: number; + app_cost: string; + app_favorite: number; + app_id: string; + app_name: string; + app_type: string; + database_cost: string; + database_id: string; + database_name: string; + database_type: string; + low_database_name: string; + database_global: true; + database_favorite?: number; + permission?: number; + user_permission?: number; } -const StyledContainer = styled('div')({ - display: 'flex', - width: 'auto', - flexDirection: 'column', - alignItems: 'flex-start', - gap: '24px', +const StyledContainer = styled("div")({ + display: "flex", + width: "auto", + flexDirection: "column", + alignItems: "flex-start", + gap: "24px", }); -const StyledSearchbarContainer = styled('div')({ - display: 'flex', - width: '100%', - alignItems: 'flex-start', - gap: '24px', +const StyledSearchbarContainer = styled("div")({ + display: "flex", + width: "100%", + alignItems: "flex-start", + gap: "24px", }); const StyledSearchbar = styled(Search)({ - width: '80%', + width: "80%", }); const StyledSort = styled(Select)({ - width: '20%', + width: "20%", }); const initialState = { - favoritedDbs: [], - databases: [], + favoritedDbs: [], + databases: [], }; const reducer = (state, action) => { - switch (action.type) { - case 'field': { - return { - ...state, - [action.field]: action.value, - }; - } - } - return state; + switch (action.type) { + case "field": { + return { + ...state, + [action.field]: action.value, + }; + } + } + return state; }; /** * Show detailed settings for an engine */ interface EngineSettingsIndexPageProps { - /** Type of the page to render */ - type: ALL_TYPES; + /** Type of the page to render */ + type: ALL_TYPES; } export const EngineSettingsIndexPage = ( - props: EngineSettingsIndexPageProps, + props: EngineSettingsIndexPageProps, ) => { - const { type } = props; - - const { adminMode } = useSettings(); - const { configStore, monolithStore } = useRootStore(); - const navigate = useNavigate(); - - const [state, dispatch] = useReducer(reducer, initialState); - const { favoritedDbs, databases } = state; - - const [view, setView] = useState('tile'); - const [search, setSearch] = useState(''); - const [sort, setSort] = useState('ENGINENAME'); - const [sortOrder, setSortOrder] = useState('ASC'); - const [canCollect, setCanCollect] = useState(true); - const [offset, setOffset] = useState(0); - - //** amount of items to be loaded */ - const limit = 8; - - // To focus when getting new results - const searchbarRef = useRef(null); - - // get a list of the keys - const databaseMetaKeys = configStore.store.config.databaseMetaKeys.filter( - (k) => { - return ( - k.display_options === 'single-checklist' || - k.display_options === 'multi-checklist' || - k.display_options === 'single-select' || - k.display_options === 'multi-select' || - k.display_options === 'single-typeahead' || - k.display_options === 'multi-typeahead' || - k.display_options === 'textarea' - ); - }, - ); - - // get metakeys to the ones we want - const metaKeys = databaseMetaKeys.map((k) => { - return k.metakey; - }); - - // Favorites ---------------------------------- - const getFavoritedDatabases = usePixel(` + const { type } = props; + + const { adminMode } = useSettings(); + const { configStore, monolithStore } = useRootStore(); + const navigate = useNavigate(); + + const [state, dispatch] = useReducer(reducer, initialState); + const { favoritedDbs, databases } = state; + + const [view, setView] = useState("tile"); + const [search, setSearch] = useState(""); + const [sort, setSort] = useState("ENGINENAME"); + const [sortOrder, setSortOrder] = useState("ASC"); + const [canCollect, setCanCollect] = useState(true); + const [offset, setOffset] = useState(0); + + //** amount of items to be loaded */ + const limit = 8; + + // To focus when getting new results + const searchbarRef = useRef(null); + + // get a list of the keys + const databaseMetaKeys = configStore.store.config.databaseMetaKeys.filter( + (k) => { + return ( + k.display_options === "single-checklist" || + k.display_options === "multi-checklist" || + k.display_options === "single-select" || + k.display_options === "multi-select" || + k.display_options === "single-typeahead" || + k.display_options === "multi-typeahead" || + k.display_options === "textarea" + ); + }, + ); + + // get metakeys to the ones we want + const metaKeys = databaseMetaKeys.map((k) => { + return k.metakey; + }); + + // Favorites ---------------------------------- + const getFavoritedDatabases = usePixel(` MyEngines(metaKeys = ${JSON.stringify( - metaKeys, - )}, filterWord=["${search}"], sort=[{"${sort}" : "${sortOrder}"}], onlyFavorites=[true], engineTypes=["${type}"]); + metaKeys, + )}, filterWord=["${search}"], sort=[{"${sort}" : "${sortOrder}"}], onlyFavorites=[true], engineTypes=["${type}"]); `); - useEffect(() => { - if (getFavoritedDatabases.status !== 'SUCCESS') { - return; - } - - dispatch({ - type: 'field', - field: 'favoritedDbs', - value: getFavoritedDatabases.data, - }); - - searchbarRef.current?.focus(); - }, [getFavoritedDatabases.status, getFavoritedDatabases.data]); - - // All Engines ------------------------------------- - const getEngines = useAPI([ - 'getEngines', - adminMode, - search, - type, - offset, - limit, - ]); - - //** reset dataMode if adminMode is toggled */ - useEffect(() => { - setOffset(0); - dispatch({ - type: 'field', - field: 'databases', - value: [], - }); - }, [adminMode, search, sort]); - - //** append data through infinite scroll */ - useEffect(() => { - if (getEngines.status !== 'SUCCESS') { - return; - } - - if (getEngines.data.length < limit) { - setCanCollect(false); - } else { - if (!canCollectRef.current) { - setCanCollect(true); - } - } - - const mutateListWithVotes = databases; - - getEngines.data.forEach((db, i) => { - mutateListWithVotes.push({ - ...db, - upvotes: db.upvotes ? db.upvotes : 0, - // hasUpvoted: false, - views: 'N/A', - trending: 'N/A', - }); - }); - - dispatch({ - type: 'field', - field: 'databases', - value: mutateListWithVotes, - }); - - searchbarRef.current?.focus(); - }, [getEngines.status, getEngines.data]); - - /** - * @name favoriteDb - * @param db - */ - const favoriteDb = (db) => { - const favorite = !isFavorited(db.database_id); - monolithStore - .setEngineFavorite(db.database_id, favorite) - .then((response) => { - if (!favorite) { - const newFavorites = favoritedDbs; - for (let i = newFavorites.length - 1; i >= 0; i--) { - if (newFavorites[i].database_id === db.database_id) { - newFavorites.splice(i, 1); - } - } - - dispatch({ - type: 'field', - field: 'favoritedDbs', - value: newFavorites, - }); - } else { - dispatch({ - type: 'field', - field: 'favoritedDbs', - value: [...favoritedDbs, db], - }); - } - }) - .catch((err) => { - // throw error if promise doesn't fulfill - throw Error(err); - }); - }; - - /** - * @name isFavorited - * @param id - */ - const isFavorited = (id) => { - const favorites = favoritedDbs; - - if (!favorites) return false; - return favorites.some((el) => el.database_id === id); - }; - - /** - * @name upvoteDb - * @param db - */ - const upvoteDb = (db) => { - let pixelString = ''; - - if (!db.hasUpvoted) { - pixelString += `VoteEngine(engine="${db.database_id}", vote=1)`; - } else { - pixelString += `UnvoteEngine(engine="${db.database_id}")`; - } - - monolithStore.runQuery(pixelString).then((response) => { - const type = response.pixelReturn[0].operationType; - const pixelResponse = response.pixelReturn[0].output; - - if (type.indexOf('ERROR') === -1) { - const newDatabases = []; - - databases.forEach((database) => { - if (database.database_id === db.database_id) { - const newCopy = database; - newCopy.upvotes = !db.hasUpvoted - ? newCopy.upvotes + 1 - : newCopy.upvotes - 1; - newCopy.hasUpvoted = !db.hasUpvoted ? true : false; - - newDatabases.push(newCopy); - } else { - newDatabases.push(database); - } - }); - - dispatch({ - type: 'field', - field: 'database', - value: newDatabases, - }); - } else { - console.error('Error voting for DB'); - } - }); - }; - - /** - * @name setDbGlobal - * @param db - */ - const setDbGlobal = (db) => { - monolithStore - .setEngineGlobal(adminMode, db.database_id, !db.database_global) - .then((response) => { - if (response.data.success) { - const newDatabases = []; - databases.forEach((database) => { - if (database.database_id === db.database_id) { - const newCopy = database; - newCopy.database_global = !db.database_global; - - newDatabases.push(newCopy); - } else { - newDatabases.push(database); - } - }); - - dispatch({ - type: 'field', - field: 'database', - value: newDatabases, - }); - } - }) - .catch((error) => { - console.error(error); - }); - }; - - //** infinite sroll variables */ - let scrollEle, scrollTimeout, currentScroll, previousScroll; - const offsetRef = useRef(0); - offsetRef.current = offset; - const canCollectRef = useRef(true); - canCollectRef.current = canCollect; - - const scrollAll = () => { - currentScroll = scrollEle.scrollTop + scrollEle.offsetHeight; - if ( - currentScroll > scrollEle.scrollHeight * 0.75 && - currentScroll > previousScroll - ) { - if (scrollTimeout) { - clearTimeout(scrollTimeout); - } - - scrollTimeout = setTimeout(() => { - if (!canCollectRef.current) { - return; - } - - setOffset(offsetRef.current + limit); - }, 500); - } - - previousScroll = currentScroll; - }; - - /** - * @desc infinite scroll - */ - useEffect(() => { - scrollEle = document.querySelector('#home__content'); - scrollEle.addEventListener('scroll', scrollAll); - return () => { - scrollEle.removeEventListener('scroll', scrollAll); - }; - }, [scrollEle]); - - return ( - <> - - - - Loading - Databases - - - - - { - setSearch(e.target.value); - }} - size="small" - onClear={() => setSearch('')} - ref={searchbarRef} - /> - setSort(e.target.value)} - label={'Sort By'} - > - Name - Date Created - {/* Views + useEffect(() => { + if (getFavoritedDatabases.status !== "SUCCESS") { + return; + } + + dispatch({ + type: "field", + field: "favoritedDbs", + value: getFavoritedDatabases.data, + }); + + searchbarRef.current?.focus(); + }, [getFavoritedDatabases.status, getFavoritedDatabases.data]); + + // All Engines ------------------------------------- + const getEngines = useAPI([ + "getEngines", + adminMode, + search, + type, + offset, + limit, + ]); + + //** reset dataMode if adminMode is toggled */ + useEffect(() => { + setOffset(0); + dispatch({ + type: "field", + field: "databases", + value: [], + }); + }, [adminMode, search, sort]); + + //** append data through infinite scroll */ + useEffect(() => { + if (getEngines.status !== "SUCCESS") { + return; + } + + if (getEngines.data.length < limit) { + setCanCollect(false); + } else { + if (!canCollectRef.current) { + setCanCollect(true); + } + } + + const mutateListWithVotes = databases; + + getEngines.data.forEach((db, i) => { + mutateListWithVotes.push({ + ...db, + upvotes: db.upvotes ? db.upvotes : 0, + // hasUpvoted: false, + views: "N/A", + trending: "N/A", + }); + }); + + dispatch({ + type: "field", + field: "databases", + value: mutateListWithVotes, + }); + + searchbarRef.current?.focus(); + }, [getEngines.status, getEngines.data]); + + /** + * @name favoriteDb + * @param db + */ + const favoriteDb = (db) => { + const favorite = !isFavorited(db.database_id); + monolithStore + .setEngineFavorite(db.database_id, favorite) + .then((response) => { + if (!favorite) { + const newFavorites = favoritedDbs; + for (let i = newFavorites.length - 1; i >= 0; i--) { + if (newFavorites[i].database_id === db.database_id) { + newFavorites.splice(i, 1); + } + } + + dispatch({ + type: "field", + field: "favoritedDbs", + value: newFavorites, + }); + } else { + dispatch({ + type: "field", + field: "favoritedDbs", + value: [...favoritedDbs, db], + }); + } + }) + .catch((err) => { + // throw error if promise doesn't fulfill + throw Error(err); + }); + }; + + /** + * @name isFavorited + * @param id + */ + const isFavorited = (id) => { + const favorites = favoritedDbs; + + if (!favorites) return false; + return favorites.some((el) => el.database_id === id); + }; + + /** + * @name upvoteDb + * @param db + */ + const upvoteDb = (db) => { + let pixelString = ""; + + if (!db.hasUpvoted) { + pixelString += `VoteEngine(engine="${db.database_id}", vote=1)`; + } else { + pixelString += `UnvoteEngine(engine="${db.database_id}")`; + } + + monolithStore.runQuery(pixelString).then((response) => { + const type = response.pixelReturn[0].operationType; + const pixelResponse = response.pixelReturn[0].output; + + if (type.indexOf("ERROR") === -1) { + const newDatabases = []; + + databases.forEach((database) => { + if (database.database_id === db.database_id) { + const newCopy = database; + newCopy.upvotes = !db.hasUpvoted + ? newCopy.upvotes + 1 + : newCopy.upvotes - 1; + newCopy.hasUpvoted = !db.hasUpvoted ? true : false; + + newDatabases.push(newCopy); + } else { + newDatabases.push(database); + } + }); + + dispatch({ + type: "field", + field: "database", + value: newDatabases, + }); + } else { + console.error("Error voting for DB"); + } + }); + }; + + /** + * @name setDbGlobal + * @param db + */ + const setDbGlobal = (db) => { + monolithStore + .setEngineGlobal(adminMode, db.database_id, !db.database_global) + .then((response) => { + if (response.data.success) { + const newDatabases = []; + databases.forEach((database) => { + if (database.database_id === db.database_id) { + const newCopy = database; + newCopy.database_global = !db.database_global; + + newDatabases.push(newCopy); + } else { + newDatabases.push(database); + } + }); + + dispatch({ + type: "field", + field: "database", + value: newDatabases, + }); + } + }) + .catch((error) => { + console.error(error); + }); + }; + + //** infinite sroll variables */ + let scrollEle, scrollTimeout, currentScroll, previousScroll; + const offsetRef = useRef(0); + offsetRef.current = offset; + const canCollectRef = useRef(true); + canCollectRef.current = canCollect; + + const scrollAll = () => { + currentScroll = scrollEle.scrollTop + scrollEle.offsetHeight; + if ( + currentScroll > scrollEle.scrollHeight * 0.75 && + currentScroll > previousScroll + ) { + if (scrollTimeout) { + clearTimeout(scrollTimeout); + } + + scrollTimeout = setTimeout(() => { + if (!canCollectRef.current) { + return; + } + + setOffset(offsetRef.current + limit); + }, 500); + } + + previousScroll = currentScroll; + }; + + /** + * @desc infinite scroll + */ + useEffect(() => { + scrollEle = document.querySelector("#home__content"); + scrollEle.addEventListener("scroll", scrollAll); + return () => { + scrollEle.removeEventListener("scroll", scrollAll); + }; + }, [scrollEle]); + + return ( + <> + + + + Loading + Databases + + + + + { + setSearch(e.target.value); + }} + size="small" + onClear={() => setSearch("")} + ref={searchbarRef} + /> + setSort(e.target.value)} + label={"Sort By"} + > + Name + Date Created + {/* Views Trending Upvotes */} - - - - setSortOrder(v)} - value={'DESC'} - aria-label={'Descending Order'} - > - - - - - setSortOrder(v)} - value={'ASC'} - aria-label={'Ascending Order'} - > - - - - - - - - setView(v)} - value={'tile'} - > - - - - - setView(v)} - value={'list'} - > - - - - - - - - {databases.length - ? databases.map((db, i) => { - return ( - - {view === 'list' ? ( - { - favoriteDb(db); - }} - onClick={(id) => { - navigate( - `${db.database_id}`, - { - state: { - name: removeUnderscores( - db.database_name, - ), - global: db.database_global, - permission: - db.permission, - }, - }, - ); - }} - upvote={(val) => { - upvoteDb(db); - }} - global={(val) => { - setDbGlobal(db); - }} - /> - ) : ( - { - favoriteDb(db); - }} - onClick={() => { - navigate( - `${db.database_id}`, - { - state: { - name: removeUnderscores( - db.database_name, - ), - global: db.database_global, - permission: - db.permission, - }, - }, - ); - }} - upvote={() => { - upvoteDb(db); - }} - global={() => { - setDbGlobal(db); - }} - /> - )} - - ); - }) - : null} - - - - ); + + + + setSortOrder(v)} + value={"DESC"} + aria-label={"Descending Order"} + > + + + + + setSortOrder(v)} + value={"ASC"} + aria-label={"Ascending Order"} + > + + + + + + + + setView(v)} + value={"tile"} + > + + + + + setView(v)} + value={"list"} + > + + + + + + + + {databases.length + ? databases.map((db, i) => { + return ( + + {view === "list" ? ( + { + favoriteDb(db); + }} + onClick={(id) => { + navigate( + `${db.database_id}`, + { + state: { + name: removeUnderscores( + db.database_name, + ), + global: db.database_global, + permission: + db.permission, + }, + }, + ); + }} + upvote={(val) => { + upvoteDb(db); + }} + global={(val) => { + setDbGlobal(db); + }} + /> + ) : ( + { + favoriteDb(db); + }} + onClick={() => { + navigate( + `${db.database_id}`, + { + state: { + name: removeUnderscores( + db.database_name, + ), + global: db.database_global, + permission: + db.permission, + }, + }, + ); + }} + upvote={() => { + upvoteDb(db); + }} + global={() => { + setDbGlobal(db); + }} + /> + )} + + ); + }) + : null} + + + + ); }; diff --git a/packages/client/src/pages/settings/InsightSettingsDetailPage.tsx b/packages/client/src/pages/settings/InsightSettingsDetailPage.tsx index 91143d9cd7..aca5fbe47c 100644 --- a/packages/client/src/pages/settings/InsightSettingsDetailPage.tsx +++ b/packages/client/src/pages/settings/InsightSettingsDetailPage.tsx @@ -1,3 +1,3 @@ export const InsightSettingsDetailPage = () => { - return null; + return null; }; diff --git a/packages/client/src/pages/settings/InsightSettingsPage.tsx b/packages/client/src/pages/settings/InsightSettingsPage.tsx index 571b588f7b..6f7d2a0b5e 100644 --- a/packages/client/src/pages/settings/InsightSettingsPage.tsx +++ b/packages/client/src/pages/settings/InsightSettingsPage.tsx @@ -1,225 +1,226 @@ -import React, { useEffect, useState, useRef, useReducer } from 'react'; -import { useRootStore, useSettings, usePixel } from '@/hooks'; -import { LoadingScreen } from '@/components/ui'; -import { useNavigate } from 'react-router-dom'; - import { - Grid, - Search, - Select, - MenuItem, - ToggleButton, - ToggleButtonGroup, - Typography, - styled, -} from '@semoss/ui'; - + FormatListBulletedOutlined, + SpaceDashboardOutlined, +} from "@mui/icons-material"; +import React, { useEffect, useReducer, useRef, useState } from "react"; +import { useNavigate } from "react-router-dom"; import { - SpaceDashboardOutlined, - FormatListBulletedOutlined, -} from '@mui/icons-material'; - -import { InsightLandscapeCard, InsightTileCard } from '@/components/insight'; + Grid, + MenuItem, + Search, + Select, + styled, + ToggleButton, + ToggleButtonGroup, + Typography, +} from "@semoss/ui"; +import { InsightLandscapeCard, InsightTileCard } from "@/components/insight"; +import { LoadingScreen } from "@/components/ui"; +import { usePixel, useRootStore, useSettings } from "@/hooks"; export interface InsightInterface { - app_id: string; - app_insight_id: string; - app_name: string; - cacheMinutes: number; - cacheable: boolean; - cachedOn: string; - created_on: string; - description: string; - last_modified_on: string; - layout: string; - low_name: string; - name: string; - permission: number; - insight_global: boolean; - insight_id: string; - insight_insight_id: string; - insight_name: string; - insight_permission: number; - tags: string[]; - view_count: number; + app_id: string; + app_insight_id: string; + app_name: string; + cacheMinutes: number; + cacheable: boolean; + cachedOn: string; + created_on: string; + description: string; + last_modified_on: string; + layout: string; + low_name: string; + name: string; + permission: number; + insight_global: boolean; + insight_id: string; + insight_insight_id: string; + insight_name: string; + insight_permission: number; + tags: string[]; + view_count: number; } -const StyledContainer = styled('div')(({ theme }) => ({ - display: 'flex', - width: 'auto', - flexDirection: 'column', - alignItems: 'flex-start', - gap: theme.spacing(3), +const StyledContainer = styled("div")(({ theme }) => ({ + display: "flex", + width: "auto", + flexDirection: "column", + alignItems: "flex-start", + gap: theme.spacing(3), })); -const StyledSearchbarContainer = styled('div')(({ theme }) => ({ - display: 'flex', - width: '100%', - alignItems: 'flex-start', - gap: '24px', +const StyledSearchbarContainer = styled("div")(({ theme }) => ({ + display: "flex", + width: "100%", + alignItems: "flex-start", + gap: "24px", })); const StyledSearchbar = styled(Search)({ - width: '80%', + width: "80%", }); const StyledSort = styled(Select)({ - width: '20%', + width: "20%", }); const initialState = { - insights: [], + insights: [], }; const reducer = (state, action) => { - switch (action.type) { - case 'field': { - return { - ...state, - [action.field]: action.value, - }; - } - } - return state; + switch (action.type) { + case "field": { + return { + ...state, + [action.field]: action.value, + }; + } + } + return state; }; export const InsightSettingsPage = () => { - const { adminMode } = useSettings(); - const navigate = useNavigate(); - - const [state, dispatch] = useReducer(reducer, initialState); - const { insights } = state; - - const [view, setView] = useState('tile'); - const [search, setSearch] = useState(''); - const [sort, setSort] = useState('name'); - - // To focus when getting new results - const searchbarRef = useRef(null); - - const getInsights = usePixel( - `GetInsights(filterWord=["${search}"], onlyFavorites=[false], sort=["${sort}"]);`, - ); - - useEffect(() => { - // Pixel call to get all apps - if (getInsights.status !== 'SUCCESS' || !getInsights.data) { - return; - } - - dispatch({ - type: 'field', - field: 'insights', - value: getInsights.data, - }); - - () => { - console.warn('Cleaning up getInsights'); - }; - }, [getInsights.status, getInsights.data]); - - const formatInsightName = (str) => { - let i; - const frags = str.split('_'); - for (i = 0; i < frags.length; i++) { - frags[i] = frags[i].charAt(0).toUpperCase() + frags[i].slice(1); - } - return frags.join(' '); - }; - - // // Issue with focus on searchbar after - // if (getInsights.status !== 'SUCCESS') { - // return ; - // } else { - // searchbarRef.current?.focus(); - // } - - return ( - - - { - setSearch(e.target.value); - }} - size="small" - /> - - setSort(e.target.value)} - > - Name - - - - setView(v)} value={'tile'}> - - - setView(v)} value={'list'}> - - - - - - {insights.length - ? insights.map((insight, i) => { - return ( - - {view === 'list' ? ( - { - console.log('navigating'); - navigate( - `${insight.project_insight_id}/${insight.project_id}`, - { - state: { - name: formatInsightName( - insight.name, - ), - global: false, - permission: 3, - }, - }, - ); - }} - /> - ) : ( - { - console.log('navigate'); - navigate( - `${insight.project_insight_id}/${insight.project_id}`, - { - state: { - name: formatInsightName( - insight.name, - ), - global: false, - permission: 3, - }, - }, - ); - }} - /> - )} - - ); - }) - : 'No insights to choose from'} - - - ); + const { adminMode } = useSettings(); + const navigate = useNavigate(); + + const [state, dispatch] = useReducer(reducer, initialState); + const { insights } = state; + + const [view, setView] = useState("tile"); + const [search, setSearch] = useState(""); + const [sort, setSort] = useState("name"); + + // To focus when getting new results + const searchbarRef = useRef(null); + + const getInsights = usePixel( + `GetInsights(filterWord=["${search}"], onlyFavorites=[false], sort=["${sort}"]);`, + ); + + useEffect(() => { + // Pixel call to get all apps + if (getInsights.status !== "SUCCESS" || !getInsights.data) { + return; + } + + dispatch({ + type: "field", + field: "insights", + value: getInsights.data, + }); + + () => { + console.warn("Cleaning up getInsights"); + }; + }, [getInsights.status, getInsights.data]); + + const formatInsightName = (str) => { + let i; + const frags = str.split("_"); + for (i = 0; i < frags.length; i++) { + frags[i] = frags[i].charAt(0).toUpperCase() + frags[i].slice(1); + } + return frags.join(" "); + }; + + // // Issue with focus on searchbar after + // if (getInsights.status !== 'SUCCESS') { + // return ; + // } else { + // searchbarRef.current?.focus(); + // } + + return ( + + + { + setSearch(e.target.value); + }} + size="small" + /> + + setSort(e.target.value)} + > + Name + + + + setView(v)} value={"tile"}> + + + setView(v)} value={"list"}> + + + + + + {insights.length + ? insights.map((insight, i) => { + return ( + + {view === "list" ? ( + { + console.log("navigating"); + navigate( + `${insight.project_insight_id}/${insight.project_id}`, + { + state: { + name: formatInsightName( + insight.name, + ), + global: false, + permission: 3, + }, + }, + ); + }} + /> + ) : ( + { + console.log("navigate"); + navigate( + `${insight.project_insight_id}/${insight.project_id}`, + { + state: { + name: formatInsightName( + insight.name, + ), + global: false, + permission: 3, + }, + }, + ); + }} + /> + )} + + ); + }) + : "No insights to choose from"} + + + ); }; diff --git a/packages/client/src/pages/settings/MemberSettingsPage.tsx b/packages/client/src/pages/settings/MemberSettingsPage.tsx index 14431bb048..dd1c020f53 100644 --- a/packages/client/src/pages/settings/MemberSettingsPage.tsx +++ b/packages/client/src/pages/settings/MemberSettingsPage.tsx @@ -1,13 +1,13 @@ -import { Navigate } from 'react-router-dom'; -import { useSettings } from '@/hooks'; -import { UserTable } from '@/components/settings'; +import { Navigate } from "react-router-dom"; +import { UserTable } from "@/components/settings"; +import { useSettings } from "@/hooks"; export const MemberSettingsPage = () => { - const { adminMode } = useSettings(); + const { adminMode } = useSettings(); - if (!adminMode) { - return ; - } + if (!adminMode) { + return ; + } - return ; + return ; }; diff --git a/packages/client/src/pages/settings/MyProfilePage.tsx b/packages/client/src/pages/settings/MyProfilePage.tsx index a754dec979..cdcbaf1869 100644 --- a/packages/client/src/pages/settings/MyProfilePage.tsx +++ b/packages/client/src/pages/settings/MyProfilePage.tsx @@ -1,1076 +1,1074 @@ import { - Add, - Delete, - ContentCopyOutlined, - KeyboardArrowDown, - KeyboardArrowUp, -} from '@mui/icons-material'; - -import { useForm, Controller } from 'react-hook-form'; + Add, + ContentCopyOutlined, + Delete, + KeyboardArrowDown, + KeyboardArrowUp, +} from "@mui/icons-material"; +import { useState } from "react"; +import { Controller, useForm } from "react-hook-form"; import { - useNotification, - styled, - Stack, - Table, - IconButton, - Button, - Typography, - TextField, - Avatar, - Paper, - Modal, - Grid, - Alert, - Collapse, -} from '@semoss/ui'; - -import { useAPI, useRootStore } from '@/hooks'; -import { LoadingScreen } from '@/components/ui'; -import { useState } from 'react'; -import { getSDKSnippet } from '@/utility'; + Alert, + Avatar, + Button, + Collapse, + Grid, + IconButton, + Modal, + Paper, + Stack, + styled, + Table, + TextField, + Typography, + useNotification, +} from "@semoss/ui"; +import { LoadingScreen } from "@/components/ui"; +import { useAPI, useRootStore } from "@/hooks"; +import { getSDKSnippet } from "@/utility"; + const StyledAvatar = styled(Avatar)(({ theme }) => ({ - display: 'flex', - alignContent: 'center', - justifyContent: 'center', - backgroundColor: '#975FE4', + display: "flex", + alignContent: "center", + justifyContent: "center", + backgroundColor: "#975FE4", })); const StyledPaper = styled(Paper)(({ theme }) => ({ - padding: '40px 30px 20px 50px', + padding: "40px 30px 20px 50px", })); const StyledAccessTokensPaper = styled(Paper)(({ theme }) => ({ - padding: '40px 30px 20px 28px', + padding: "40px 30px 20px 28px", })); const HeaderCell = styled(Table.Cell)(({ theme }) => ({ - backgroundColor: '#f3f3f3', - borderBottom: '1px solid #ccc', + backgroundColor: "#f3f3f3", + borderBottom: "1px solid #ccc", })); const LeftHeaderCell = styled(Table.Cell)(({ theme }) => ({ - backgroundColor: '#f3f3f3', - borderBottom: '1px solid #ccc', - borderRadius: '20px 0 0 0', - textAlign: 'center', + backgroundColor: "#f3f3f3", + borderBottom: "1px solid #ccc", + borderRadius: "20px 0 0 0", + textAlign: "center", })); const RightHeaderCell = styled(Table.Cell)(({ theme }) => ({ - backgroundColor: '#f3f3f3', - borderBottom: '1px solid #ccc', - borderRadius: '0 20px 0 0', - textAlign: 'center', + backgroundColor: "#f3f3f3", + borderBottom: "1px solid #ccc", + borderRadius: "0 20px 0 0", + textAlign: "center", })); -const MessageDiv = styled('div')(({ theme }) => ({ - textAlign: 'center', - marginTop: '100px', - fontSize: '13px', - display: 'block', - color: '#666', - width: '100%', - margin: '75px auto 85px', +const MessageDiv = styled("div")(({ theme }) => ({ + textAlign: "center", + marginTop: "100px", + fontSize: "13px", + display: "block", + color: "#666", + width: "100%", + margin: "75px auto 85px", })); -const AvatarForm = styled('form')(({ theme }) => ({ - paddingTop: '15px', - width: '750px', +const AvatarForm = styled("form")(({ theme }) => ({ + paddingTop: "15px", + width: "750px", })); const CurrentAvatarStack = styled(Stack)(({ theme }) => ({ - alignItems: 'center', + alignItems: "center", })); const StyledTableContainer = styled(Table.Container)(({ theme }) => ({ - marginTop: '20px', + marginTop: "20px", })); const StyledGrid = styled(Grid)(({ theme }) => ({ - marginBottom: '40px', + marginBottom: "40px", })); const MonolithGrid = styled(Grid)(({ theme }) => ({ - display: 'flex', - alignItems: 'center', + display: "flex", + alignItems: "center", })); const StyledStack = styled(Stack)(({ theme }) => ({ - marginBottom: '15px', + marginBottom: "15px", })); const CopyGridItem = styled(Grid)(({ theme }) => ({ - padding: 0, - display: 'flex', - justifyContent: 'right', + padding: 0, + display: "flex", + justifyContent: "right", })); const GridItem = styled(Grid)(({ theme }) => ({ - padding: 0, + padding: 0, })); const CustomGridItem = styled(GridItem)(({ theme }) => ({ - padding: 0, - zIndex: 8, + padding: 0, + zIndex: 8, })); -const StyledCodeBlock = styled('pre')(({ theme }) => ({ - display: 'flex', - alignItems: 'center', - gap: theme.spacing(5), - background: theme.palette.background.default, - borderRadius: theme.shape.borderRadius, - padding: theme.spacing(2), - overflowX: 'scroll', - margin: '0px', +const StyledCodeBlock = styled("pre")(({ theme }) => ({ + display: "flex", + alignItems: "center", + gap: theme.spacing(5), + background: theme.palette.background.default, + borderRadius: theme.shape.borderRadius, + padding: theme.spacing(2), + overflowX: "scroll", + margin: "0px", })); -const StyledCodeContent = styled('code', { - shouldForwardProp: (prop) => prop !== 'maxWidth', +const StyledCodeContent = styled("code", { + shouldForwardProp: (prop) => prop !== "maxWidth", })<{ - /** Track if the page header is stuck */ - maxWidth?: string; + /** Track if the page header is stuck */ + maxWidth?: string; }>(({ theme, maxWidth }) => ({ - flex: 1, - maxWidth: maxWidth ? maxWidth : 'auto', - overflowY: 'scroll', + flex: 1, + maxWidth: maxWidth ? maxWidth : "auto", + overflowY: "scroll", })); -const StyledSDKBlock = styled('pre')(({ theme }) => ({ - display: 'flex', - alignItems: 'flex-start', - gap: '40px', - background: theme.palette.background.paper, - borderRadius: theme.shape.borderRadius, - padding: theme.spacing(2), - margin: '0px', +const StyledSDKBlock = styled("pre")(({ theme }) => ({ + display: "flex", + alignItems: "flex-start", + gap: "40px", + background: theme.palette.background.paper, + borderRadius: theme.shape.borderRadius, + padding: theme.spacing(2), + margin: "0px", })); const StyledCreatedKeyContainer = styled(Stack)(({ theme }) => ({ - background: theme.palette.background.default, - padding: theme.spacing(1), + background: theme.palette.background.default, + padding: theme.spacing(1), })); interface CreateAccessKeyForm { - TOKENNAME: string; - TOKENDESCRIPTION?: string; - ACCESSKEY: string; - SECRETKEY: string; - PLACEHOLDER: string; + TOKENNAME: string; + TOKENDESCRIPTION?: string; + ACCESSKEY: string; + SECRETKEY: string; + PLACEHOLDER: string; } interface EditUserInfoForm { - NAME: string; - USERNAME: string; - EMAIL: string; - USERID?: string | undefined; + NAME: string; + USERNAME: string; + EMAIL: string; + USERID?: string | undefined; } export const MyProfilePage = () => { - const notification = useNotification(); - const { configStore, monolithStore } = useRootStore(); - const { email, id, name, admin, loggedIn } = configStore.store.user; - - // track the models - const [addModal, setAddModal] = useState(false); - const [profileImgModal, setProfileImgModal] = useState(false); - - // get the keys - const getUserAccessKeys = useAPI(['getUserAccessKeys']); - - // NATIVE Login USERID must match Username - const logins = configStore.store.config.logins; - const nativeLogin = logins['NATIVE']; - - const { control, reset, setValue, handleSubmit, watch } = - useForm({ - defaultValues: { - TOKENNAME: '', - TOKENDESCRIPTION: '', - ACCESSKEY: '', - SECRETKEY: '', - PLACEHOLDER: '', - }, - }); - - const { - control: userInfoControl, - reset: userInfoReset, - setValue: userInfoSetValue, - handleSubmit: userInfoHandleSubmit, - watch: userInfoWatch, - } = useForm({ - defaultValues: { - NAME: name, - USERNAME: id, - USERID: id, - EMAIL: email, - }, - }); - - const ACCESSKEY = watch('ACCESSKEY'); - const SECRETKEY = watch('SECRETKEY'); - - // track if we can create a key - const isCreated = ACCESSKEY && SECRETKEY ? true : false; - - const [isJsSdkOpen, setIsJsSdkOpen] = useState(false); - const [isPySdkOpen, setIsPySdkOpen] = useState(false); - - /** - * Submit edit profile info - */ - const profileEditSubmit = async (data: EditUserInfoForm) => { - try { - // need to confirm reactor for runQuery or monolithStore method for editing profile - console.log(data); - - const userObj = { - password: '', - id: nativeLogin, - email: email, - username: id, - name: data.NAME, - }; - - data.USERID !== nativeLogin && (userObj['newId'] = data.USERID); - data.USERNAME !== id && (userObj['newUsername'] = data.USERNAME); - data.EMAIL !== email && (userObj['newEmail'] = data.EMAIL); - - const response = await monolithStore.editMemberInfo(true, userObj); - - if (response.data) { - notification.add({ - color: 'success', - message: 'Successfully edited profile information', - }); - } else { - notification.add({ - color: 'error', - message: 'Error editing profile information', - }); - } - } catch (e) { - notification.add({ - color: 'error', - message: String(e), - }); - } - }; - - /** - * Delete an accesskey - * @param accessKey - delete an access key - */ - const createAccessKey = async (data: CreateAccessKeyForm) => { - try { - const output = await monolithStore.createUserAccessKey( - data.TOKENNAME, - data.TOKENDESCRIPTION || '', - ); - - // update the values - setValue('ACCESSKEY', output.ACCESSKEY); - setValue('SECRETKEY', output.SECRETKEY); - - // add a new one - notification.add({ - color: 'success', - message: 'Successfully created key', - }); - } catch (e) { - if (e instanceof Error) { - notification.add({ - color: 'error', - message: e.message, - }); - } - } - }; - - /** - * Delete an accesskey - * @param accessKey - delete an access key - */ - const deleteAccessKey = async (accessKey: string) => { - try { - const response = await monolithStore.deleteUserAccessKeys( - accessKey, - ); - - if (!response) { - throw new Error('Error deleting key'); - } - - // refresh the keys - getUserAccessKeys.refresh(); - - // add a new one - notification.add({ - color: 'success', - message: 'Successfully deleted key', - }); - } catch (e) { - if (e instanceof Error) { - notification.add({ - color: 'error', - message: e.message, - }); - } - } - }; - - /** - * Callback that is triggered when the add modal closes - */ - const closeModel = () => { - // close it - setAddModal(false); - - // a new key was added refresh the current keys - if (isCreated) { - getUserAccessKeys.refresh(); - } - - // reset the form - reset({}); - }; - - const closeProfileEditModel = () => { - setProfileImgModal(false); - }; - - /** - * Copy text and add it to the clipboard - * @param text - text to copy - */ - const copy = async (text: string) => { - try { - await navigator.clipboard.writeText(text); - - notification.add({ - color: 'success', - message: 'Successfully copied code', - }); - } catch (e) { - notification.add({ - color: 'error', - message: 'Unable to copy code', - }); - } - }; - - if ( - getUserAccessKeys.status === 'INITIAL' || - getUserAccessKeys.status === 'LOADING' - ) { - return ; - } - const pySnippet = getSDKSnippet('py', ACCESSKEY, SECRETKEY); - const jsSnippet = getSDKSnippet('js', ACCESSKEY, SECRETKEY); - - return ( - - - - - - {nativeLogin - ? 'Edit profile information' - : 'Profile Info'} - - - - - {name[0].toUpperCase()} - - - - - - - - {/* spacer */} - - {nativeLogin ? ( -
    - - { - return ( - - field.onChange(value) - } - inputProps={{ - maxLength: 255, - }} - fullWidth={true} - disabled={!admin} - > - ); - }} - /> - - - - { - return ( - - field.onChange(value) - } - inputProps={{ - maxLength: 500, - }} - fullWidth={true} - disabled={!admin} - > - ); - }} - /> - - - { - return ( - - field.onChange(value) - } - inputProps={{ - maxLength: 500, - }} - fullWidth={true} - disabled={!admin} - > - ); - }} - /> - - - - { - return ( - - field.onChange(value) - } - inputProps={{ - maxLength: 500, - }} - fullWidth={true} - disabled={!admin} - > - ); - }} - /> - - - - - - - - - ) : ( - <> - - - - {Object.entries(configStore.store.user).map( - (kv) => { - if ( - kv[0] !== 'loggedIn' && - kv[0] !== 'admin' - ) { - return ( - - - - ); - } - }, - )} - - )} -
    -
    -
    - - - - - Javascript SDK - - - { - copy(jsSnippet); - }} - data-testid={'my-profile-js-copy-btn'} - > - - - - - - - - {jsSnippet} - - - - - - - - - Python SDK - - - - { - copy(pySnippet); - }} - data-testid={'my-profile-py-copy-btn'} - > - - - - - - - - {pySnippet} - - - - - - - - Personal Access Tokens - - - - - -
    - - - - Name - - - Description - - - Date Created - - - Last Used Created - - - Access Key - -   - - - - {getUserAccessKeys.status === 'SUCCESS' && - getUserAccessKeys.data.length !== 0 - ? getUserAccessKeys.data.map((k, idx) => { - return ( - - - {k.TOKENNAME} - - - {k.TOKENDESCRIPTION || ''} - - - {k.DATECREATED} - - - {k.LASTUSED} - - - {k.ACCESSKEY} - - - { - copy(k.ACCESSKEY); - }} - data-testid={ - 'my-profile-access-key-copy-btn' - } - > - - - { - deleteAccessKey( - k.ACCESSKEY, - ); - }} - data-testid={ - 'my-profile-access-key-delete-btn' - } - > - - - - - ); - }) - : null} - -
    - - {getUserAccessKeys.status === 'SUCCESS' && - getUserAccessKeys.data.length === 0 && ( - - No Personal Access Tokens to display at this time -
    - Click New Key to create a new Personal Access Token -
    - )} - - - closeModel()} maxWidth="lg"> - Generate Key - - -
    - - - Note: Your private key will only be - generated once - - - { - return ( - - field.onChange(value) - } - inputProps={{ maxLength: 255 }} - > - ); - }} - /> - - { - return ( - - field.onChange(value) - } - inputProps={{ maxLength: 500 }} - > - ); - }} - /> - - - - - {isCreated && ( - - - - Access Key - - - - {ACCESSKEY} - - - - - - - Secret Key - - - - {SECRETKEY} - - - - - - - - Javascript Example - - { - setIsJsSdkOpen( - !isJsSdkOpen, - ); - }} - data-testid={ - 'my-profile-page-js-toggle-btn' - } - > - {isJsSdkOpen ? ( - - ) : ( - - )} - - - - - - - {jsSnippet} - - - - - - - - - Python Example - - { - setIsPySdkOpen( - !isPySdkOpen, - ); - }} - data-testid={ - 'my-profile-page-py-toggle-btn' - } - > - {isPySdkOpen ? ( - - ) : ( - - )} - - - - - - {pySnippet} - - - - - - - )} - -
    -
    -
    - - - -
    - - closeModel()} - maxWidth="md" - > - Upload Profile Picture - - - {name[0].toUpperCase()} - Current avatar - - - - - { - return ( - - field.onChange(value) - } - inputProps={{ maxLength: 255 }} - fullWidth={true} - > - ); - }} - /> - - - - - - - - - - ); + const notification = useNotification(); + const { configStore, monolithStore } = useRootStore(); + const { email, id, name, admin, loggedIn } = configStore.store.user; + + // track the models + const [addModal, setAddModal] = useState(false); + const [profileImgModal, setProfileImgModal] = useState(false); + + // get the keys + const getUserAccessKeys = useAPI(["getUserAccessKeys"]); + + // NATIVE Login USERID must match Username + const logins = configStore.store.config.logins; + const nativeLogin = logins["NATIVE"]; + + const { control, reset, setValue, handleSubmit, watch } = + useForm({ + defaultValues: { + TOKENNAME: "", + TOKENDESCRIPTION: "", + ACCESSKEY: "", + SECRETKEY: "", + PLACEHOLDER: "", + }, + }); + + const { + control: userInfoControl, + reset: userInfoReset, + setValue: userInfoSetValue, + handleSubmit: userInfoHandleSubmit, + watch: userInfoWatch, + } = useForm({ + defaultValues: { + NAME: name, + USERNAME: id, + USERID: id, + EMAIL: email, + }, + }); + + const ACCESSKEY = watch("ACCESSKEY"); + const SECRETKEY = watch("SECRETKEY"); + + // track if we can create a key + const isCreated = ACCESSKEY && SECRETKEY ? true : false; + + const [isJsSdkOpen, setIsJsSdkOpen] = useState(false); + const [isPySdkOpen, setIsPySdkOpen] = useState(false); + + /** + * Submit edit profile info + */ + const profileEditSubmit = async (data: EditUserInfoForm) => { + try { + // need to confirm reactor for runQuery or monolithStore method for editing profile + console.log(data); + + const userObj = { + password: "", + id: nativeLogin, + email: email, + username: id, + name: data.NAME, + }; + + data.USERID !== nativeLogin && (userObj["newId"] = data.USERID); + data.USERNAME !== id && (userObj["newUsername"] = data.USERNAME); + data.EMAIL !== email && (userObj["newEmail"] = data.EMAIL); + + const response = await monolithStore.editMemberInfo(true, userObj); + + if (response.data) { + notification.add({ + color: "success", + message: "Successfully edited profile information", + }); + } else { + notification.add({ + color: "error", + message: "Error editing profile information", + }); + } + } catch (e) { + notification.add({ + color: "error", + message: String(e), + }); + } + }; + + /** + * Delete an accesskey + * @param accessKey - delete an access key + */ + const createAccessKey = async (data: CreateAccessKeyForm) => { + try { + const output = await monolithStore.createUserAccessKey( + data.TOKENNAME, + data.TOKENDESCRIPTION || "", + ); + + // update the values + setValue("ACCESSKEY", output.ACCESSKEY); + setValue("SECRETKEY", output.SECRETKEY); + + // add a new one + notification.add({ + color: "success", + message: "Successfully created key", + }); + } catch (e) { + if (e instanceof Error) { + notification.add({ + color: "error", + message: e.message, + }); + } + } + }; + + /** + * Delete an accesskey + * @param accessKey - delete an access key + */ + const deleteAccessKey = async (accessKey: string) => { + try { + const response = + await monolithStore.deleteUserAccessKeys(accessKey); + + if (!response) { + throw new Error("Error deleting key"); + } + + // refresh the keys + getUserAccessKeys.refresh(); + + // add a new one + notification.add({ + color: "success", + message: "Successfully deleted key", + }); + } catch (e) { + if (e instanceof Error) { + notification.add({ + color: "error", + message: e.message, + }); + } + } + }; + + /** + * Callback that is triggered when the add modal closes + */ + const closeModel = () => { + // close it + setAddModal(false); + + // a new key was added refresh the current keys + if (isCreated) { + getUserAccessKeys.refresh(); + } + + // reset the form + reset({}); + }; + + const closeProfileEditModel = () => { + setProfileImgModal(false); + }; + + /** + * Copy text and add it to the clipboard + * @param text - text to copy + */ + const copy = async (text: string) => { + try { + await navigator.clipboard.writeText(text); + + notification.add({ + color: "success", + message: "Successfully copied code", + }); + } catch (e) { + notification.add({ + color: "error", + message: "Unable to copy code", + }); + } + }; + + if ( + getUserAccessKeys.status === "INITIAL" || + getUserAccessKeys.status === "LOADING" + ) { + return ; + } + const pySnippet = getSDKSnippet("py", ACCESSKEY, SECRETKEY); + const jsSnippet = getSDKSnippet("js", ACCESSKEY, SECRETKEY); + + return ( + + + + + + {nativeLogin + ? "Edit profile information" + : "Profile Info"} + + + + + {name[0].toUpperCase()} + + + + + + + + {/* spacer */} + + {nativeLogin ? ( +
    + + { + return ( + + field.onChange(value) + } + inputProps={{ + maxLength: 255, + }} + fullWidth={true} + disabled={!admin} + > + ); + }} + /> + + + + { + return ( + + field.onChange(value) + } + inputProps={{ + maxLength: 500, + }} + fullWidth={true} + disabled={!admin} + > + ); + }} + /> + + + { + return ( + + field.onChange(value) + } + inputProps={{ + maxLength: 500, + }} + fullWidth={true} + disabled={!admin} + > + ); + }} + /> + + + + { + return ( + + field.onChange(value) + } + inputProps={{ + maxLength: 500, + }} + fullWidth={true} + disabled={!admin} + > + ); + }} + /> + + + + + + + +
    + ) : ( + <> + + + + {Object.entries(configStore.store.user).map( + (kv) => { + if ( + kv[0] !== "loggedIn" && + kv[0] !== "admin" + ) { + return ( + + + + ); + } + }, + )} + + )} +
    +
    +
    + + + + + Javascript SDK + + + { + copy(jsSnippet); + }} + data-testid={"my-profile-js-copy-btn"} + > + + + + + + + + {jsSnippet} + + + + + + + + + Python SDK + + + + { + copy(pySnippet); + }} + data-testid={"my-profile-py-copy-btn"} + > + + + + + + + + {pySnippet} + + + + + + + + Personal Access Tokens + + + + + + + + + + Name + + + Description + + + Date Created + + + Last Used Created + + + Access Key + +   + + + + {getUserAccessKeys.status === "SUCCESS" && + getUserAccessKeys.data.length !== 0 + ? getUserAccessKeys.data.map((k, idx) => { + return ( + + + {k.TOKENNAME} + + + {k.TOKENDESCRIPTION || ""} + + + {k.DATECREATED} + + + {k.LASTUSED} + + + {k.ACCESSKEY} + + + { + copy(k.ACCESSKEY); + }} + data-testid={ + "my-profile-access-key-copy-btn" + } + > + + + { + deleteAccessKey( + k.ACCESSKEY, + ); + }} + data-testid={ + "my-profile-access-key-delete-btn" + } + > + + + + + ); + }) + : null} + +
    +
    + {getUserAccessKeys.status === "SUCCESS" && + getUserAccessKeys.data.length === 0 && ( + + No Personal Access Tokens to display at this time +
    + Click New Key to create a new Personal Access Token +
    + )} +
    + + closeModel()} maxWidth="lg"> + Generate Key + + +
    + + + Note: Your private key will only be + generated once + + + { + return ( + + field.onChange(value) + } + inputProps={{ maxLength: 255 }} + > + ); + }} + /> + + { + return ( + + field.onChange(value) + } + inputProps={{ maxLength: 500 }} + > + ); + }} + /> + + + + + {isCreated && ( + + + + Access Key + + + + {ACCESSKEY} + + + + + + + Secret Key + + + + {SECRETKEY} + + + + + + + + Javascript Example + + { + setIsJsSdkOpen( + !isJsSdkOpen, + ); + }} + data-testid={ + "my-profile-page-js-toggle-btn" + } + > + {isJsSdkOpen ? ( + + ) : ( + + )} + + + + + + + {jsSnippet} + + + + + + + + + Python Example + + { + setIsPySdkOpen( + !isPySdkOpen, + ); + }} + data-testid={ + "my-profile-page-py-toggle-btn" + } + > + {isPySdkOpen ? ( + + ) : ( + + )} + + + + + + {pySnippet} + + + + + + + )} + +
    +
    +
    + + + +
    + + closeModel()} + maxWidth="md" + > + Upload Profile Picture + + + {name[0].toUpperCase()} + Current avatar + + + + + { + return ( + + field.onChange(value) + } + inputProps={{ maxLength: 255 }} + fullWidth={true} + > + ); + }} + /> + + + + + + + + +
    + ); }; diff --git a/packages/client/src/pages/settings/ProjectSettingsPage.tsx b/packages/client/src/pages/settings/ProjectSettingsPage.tsx index cf17ff2d80..4415757f52 100644 --- a/packages/client/src/pages/settings/ProjectSettingsPage.tsx +++ b/packages/client/src/pages/settings/ProjectSettingsPage.tsx @@ -1,398 +1,399 @@ -import { useEffect, useState, useRef, useReducer } from 'react'; - -import { useSettings, useAPI } from '../../hooks'; -import { useNavigate } from 'react-router-dom'; -import { ProjectTileCard } from '@/components/app'; - import { - Grid, - Search, - Select, - MenuItem, - ToggleButton, - ToggleButtonGroup, - styled, - Backdrop, - CircularProgress, - Stack, - Typography, - Tooltip, -} from '@semoss/ui'; - + ArrowDownward, + ArrowUpward, + FormatListBulletedOutlined, + SpaceDashboardOutlined, +} from "@mui/icons-material"; +import { useEffect, useReducer, useRef, useState } from "react"; +import { useNavigate } from "react-router-dom"; import { - SpaceDashboardOutlined, - FormatListBulletedOutlined, - ArrowUpward, - ArrowDownward, -} from '@mui/icons-material'; - -const StyledContainer = styled('div')(({ theme }) => ({ - display: 'flex', - width: 'auto', - flexDirection: 'column', - alignItems: 'flex-start', - gap: theme.spacing(3), + Backdrop, + CircularProgress, + Grid, + MenuItem, + Search, + Select, + Stack, + styled, + ToggleButton, + ToggleButtonGroup, + Tooltip, + Typography, +} from "@semoss/ui"; +import { ProjectTileCard } from "@/components/app"; +import { useAPI, useSettings } from "../../hooks"; + +const StyledContainer = styled("div")(({ theme }) => ({ + display: "flex", + width: "auto", + flexDirection: "column", + alignItems: "flex-start", + gap: theme.spacing(3), })); const StyledSearch = styled(Search)({ - width: '80%', + width: "80%", }); -const StyledSearchbarContainer = styled('div')(({ theme }) => ({ - display: 'flex', - width: '100%', - alignItems: 'flex-start', - gap: theme.spacing(3), +const StyledSearchbarContainer = styled("div")(({ theme }) => ({ + display: "flex", + width: "100%", + alignItems: "flex-start", + gap: theme.spacing(3), })); const StyledSort = styled(Select)({ - width: '20%', + width: "20%", }); const StyledBackdrop = styled(Backdrop)({ - backgroundColor: 'rgba(255, 255, 255, 0.5)', - zIndex: 1501, + backgroundColor: "rgba(255, 255, 255, 0.5)", + zIndex: 1501, }); const initialState = { - projects: [], + projects: [], }; const reducer = (state, action) => { - switch (action.type) { - case 'field': { - return { - ...state, - [action.field]: action.value, - }; - } - case 'sort': { - const sortedProjects = [...state.projects]; - if (action.sortBy === 'Name') { - sortedProjects.sort((a, b) => { - return action.sortType === 'ASC' - ? a.project_name - .toLowerCase() - .localeCompare(b.project_name.toLowerCase()) - : b.project_name - .toLowerCase() - .localeCompare(a.project_name.toLowerCase()); - }); - } else if (action.sortBy === 'Date Created') { - sortedProjects.sort((a, b) => { - return action.sortType === 'ASC' - ? new Date(a.project_date_created).getTime() - - new Date(b.project_date_created).getTime() - : new Date(b.project_date_created).getTime() - - new Date(a.project_date_created).getTime(); - }); - } - return { - ...state, - projects: sortedProjects, - }; - } - } - return state; + switch (action.type) { + case "field": { + return { + ...state, + [action.field]: action.value, + }; + } + case "sort": { + const sortedProjects = [...state.projects]; + if (action.sortBy === "Name") { + sortedProjects.sort((a, b) => { + return action.sortType === "ASC" + ? a.project_name + .toLowerCase() + .localeCompare(b.project_name.toLowerCase()) + : b.project_name + .toLowerCase() + .localeCompare(a.project_name.toLowerCase()); + }); + } else if (action.sortBy === "Date Created") { + sortedProjects.sort((a, b) => { + return action.sortType === "ASC" + ? new Date(a.project_date_created).getTime() - + new Date(b.project_date_created).getTime() + : new Date(b.project_date_created).getTime() - + new Date(a.project_date_created).getTime(); + }); + } + return { + ...state, + projects: sortedProjects, + }; + } + } + return state; }; export interface ProjectInterface { - project_global: boolean; - project_id: string; - project_name: string; - permission: number; + project_global: boolean; + project_id: string; + project_name: string; + permission: number; } export const ProjectSettingsPage = () => { - const { adminMode } = useSettings(); - const navigate = useNavigate(); - const [state, dispatch] = useReducer(reducer, initialState); - const { projects } = state; - - const [view, setView] = useState('tile'); - const [search, setSearch] = useState(''); - const [sort, setSort] = useState('Name'); - const [sortOrder, setSortOrder] = useState('ASC'); - const [canCollect, setCanCollect] = useState(true); - const [offset, setOffset] = useState(0); - - //** amount of items to be loaded */ - const limit = 30; - - // To focus when getting new results - const searchbarRef = useRef(null); - - const getProjects = useAPI([ - 'getProjects', - adminMode, - search, - offset, - limit, - ]); - - const formatProjectName = (str) => { - let i; - const frags = str.split('_'); - for (i = 0; i < frags.length; i++) { - frags[i] = frags[i].charAt(0).toUpperCase() + frags[i].slice(1); - } - return frags.join(' '); - }; - - //** reset dataMode if adminMode is toggled */ - useEffect(() => { - setOffset(0); - dispatch({ - type: 'field', - field: 'projects', - value: [], - }); - }, [adminMode, search]); - - //** append data through infinite scroll */ - useEffect(() => { - if (getProjects.status !== 'SUCCESS') { - return; - } - - if (getProjects.data.length < limit) { - setCanCollect(false); - } else { - if (!canCollectRef.current) { - setCanCollect(true); - } - } - - const mutateListWithVotes = projects; - - getProjects.data.forEach((proj) => { - mutateListWithVotes.push({ - ...proj, - project_global: proj.project_global, - project_id: proj.project_id, - project_name: proj.project_name, - project_permission: proj.project_permission, - project_visibility: proj.project_visibility, - }); - }); - - dispatch({ - type: 'field', - field: 'projects', - value: mutateListWithVotes, - }); - - searchbarRef.current?.focus(); - }, [getProjects.status, getProjects.data]); - - //** infinite sroll variables */ - let scrollEle, scrollTimeout, currentScroll, previousScroll; - const offsetRef = useRef(0); - offsetRef.current = offset; - const canCollectRef = useRef(true); - canCollectRef.current = canCollect; - - const scrollAll = () => { - currentScroll = scrollEle.scrollTop + scrollEle.offsetHeight; - if ( - currentScroll > scrollEle.scrollHeight * 0.75 && - currentScroll > previousScroll - ) { - if (scrollTimeout) { - clearTimeout(scrollTimeout); - } - - scrollTimeout = setTimeout(() => { - if (!canCollectRef.current) { - return; - } - - setOffset(offsetRef.current + limit); - }, 500); - } - - previousScroll = currentScroll; - }; - - /** - * @desc infinite scroll - */ - useEffect(() => { - scrollEle = document.querySelector('#home__content'); - - scrollEle.addEventListener('scroll', scrollAll); - return () => { - scrollEle.removeEventListener('scroll', scrollAll); - }; - }, [scrollEle]); - - return ( - <> - - - - Loading - Projects - - - - - { - setSearch(e.target.value); - }} - placeholder="Project" - size="small" - onClear={() => setSearch('')} - ref={searchbarRef} - /> - setSort(e.target.value)} - > - Name - Date Created - Views - Trending - Upvotes - - - - { - dispatch({ - type: 'sort', - sortBy: sort, - sortType: 'DESC', - }); - setSortOrder(v); - }} - value={'DESC'} - aria-label={'Descending Order'} - data-testid={'project-settings-desc-btn'} - > - - - - - { - dispatch({ - type: 'sort', - sortBy: sort, - sortType: 'ASC', - }); - setSortOrder(v); - }} - value={'ASC'} - aria-label={'Ascending Order'} - data-testid={'project-settings-asc-btn'} - > - - - - - - - - setView(v)} - value={'tile'} - data-testid={'project-settings-tile-btn'} - > - - - - - setView(v)} - value={'list'} - data-testid={'project-settings-list-btn'} - > - - - - - - - - {projects.length - ? projects.map((project, i) => { - return ( - - {view === 'list' ? ( - { - navigate( - `${project.project_id}`, - { - state: { - name: formatProjectName( - project.project_name, - ), - global: false, - permission: 3, - }, - }, - ); - }} - /> - ) : ( - { - navigate( - `${project.project_id}`, - { - state: { - name: formatProjectName( - project.project_name, - ), - global: false, - permission: 3, - }, - }, - ); - }} - /> - )} - - ); - }) - : 'No apps to choose from'} - - - - ); + const { adminMode } = useSettings(); + const navigate = useNavigate(); + const [state, dispatch] = useReducer(reducer, initialState); + const { projects } = state; + + const [view, setView] = useState("tile"); + const [search, setSearch] = useState(""); + const [sort, setSort] = useState("Name"); + const [sortOrder, setSortOrder] = useState("ASC"); + const [canCollect, setCanCollect] = useState(true); + const [offset, setOffset] = useState(0); + + //** amount of items to be loaded */ + const limit = 30; + + // To focus when getting new results + const searchbarRef = useRef(null); + + const getProjects = useAPI([ + "getProjects", + adminMode, + search, + offset, + limit, + ]); + + const formatProjectName = (str) => { + let i; + const frags = str.split("_"); + for (i = 0; i < frags.length; i++) { + frags[i] = frags[i].charAt(0).toUpperCase() + frags[i].slice(1); + } + return frags.join(" "); + }; + + //** reset dataMode if adminMode is toggled */ + useEffect(() => { + setOffset(0); + dispatch({ + type: "field", + field: "projects", + value: [], + }); + }, [adminMode, search]); + + //** append data through infinite scroll */ + useEffect(() => { + if (getProjects.status !== "SUCCESS") { + return; + } + + if (getProjects.data.length < limit) { + setCanCollect(false); + } else { + if (!canCollectRef.current) { + setCanCollect(true); + } + } + + const mutateListWithVotes = projects; + + getProjects.data.forEach((proj) => { + mutateListWithVotes.push({ + ...proj, + project_global: proj.project_global, + project_id: proj.project_id, + project_name: proj.project_name, + project_permission: proj.project_permission, + project_visibility: proj.project_visibility, + }); + }); + + dispatch({ + type: "field", + field: "projects", + value: mutateListWithVotes, + }); + + searchbarRef.current?.focus(); + }, [getProjects.status, getProjects.data]); + + //** infinite sroll variables */ + let scrollEle, scrollTimeout, currentScroll, previousScroll; + const offsetRef = useRef(0); + offsetRef.current = offset; + const canCollectRef = useRef(true); + canCollectRef.current = canCollect; + + const scrollAll = () => { + currentScroll = scrollEle.scrollTop + scrollEle.offsetHeight; + if ( + currentScroll > scrollEle.scrollHeight * 0.75 && + currentScroll > previousScroll + ) { + if (scrollTimeout) { + clearTimeout(scrollTimeout); + } + + scrollTimeout = setTimeout(() => { + if (!canCollectRef.current) { + return; + } + + setOffset(offsetRef.current + limit); + }, 500); + } + + previousScroll = currentScroll; + }; + + /** + * @desc infinite scroll + */ + useEffect(() => { + scrollEle = document.querySelector("#home__content"); + + scrollEle.addEventListener("scroll", scrollAll); + return () => { + scrollEle.removeEventListener("scroll", scrollAll); + }; + }, [scrollEle]); + + return ( + <> + + + + Loading + Projects + + + + + { + setSearch(e.target.value); + }} + placeholder="Project" + size="small" + onClear={() => setSearch("")} + ref={searchbarRef} + /> + setSort(e.target.value)} + > + Name + Date Created + Views + Trending + Upvotes + + + + { + dispatch({ + type: "sort", + sortBy: sort, + sortType: "DESC", + }); + setSortOrder(v); + }} + value={"DESC"} + aria-label={"Descending Order"} + data-testid={"project-settings-desc-btn"} + > + + + + + { + dispatch({ + type: "sort", + sortBy: sort, + sortType: "ASC", + }); + setSortOrder(v); + }} + value={"ASC"} + aria-label={"Ascending Order"} + data-testid={"project-settings-asc-btn"} + > + + + + + + + + setView(v)} + value={"tile"} + data-testid={"project-settings-tile-btn"} + > + + + + + setView(v)} + value={"list"} + data-testid={"project-settings-list-btn"} + > + + + + + + + + {projects.length + ? projects.map((project, i) => { + return ( + + {view === "list" ? ( + { + navigate( + `${project.project_id}`, + { + state: { + name: formatProjectName( + project.project_name, + ), + global: false, + permission: 3, + }, + }, + ); + }} + /> + ) : ( + { + navigate( + `${project.project_id}`, + { + state: { + name: formatProjectName( + project.project_name, + ), + global: false, + permission: 3, + }, + }, + ); + }} + /> + )} + + ); + }) + : "No apps to choose from"} + + + + ); }; diff --git a/packages/client/src/pages/settings/SettingsIndexPage.tsx b/packages/client/src/pages/settings/SettingsIndexPage.tsx index ab3c120b18..7a65f1fc0c 100644 --- a/packages/client/src/pages/settings/SettingsIndexPage.tsx +++ b/packages/client/src/pages/settings/SettingsIndexPage.tsx @@ -1,199 +1,194 @@ -import { useState, useEffect } from 'react'; import { - Card, - Grid, - IconButton, - MenuItem, - Select, - Search, - styled, - Typography, -} from '@semoss/ui'; - + Diversity3, + MoreVert, + Search as SearchIcon, +} from "@mui/icons-material"; +import { useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; import { - Search as SearchIcon, - MoreVert, - Diversity3, -} from '@mui/icons-material'; - -import { useNavigate } from 'react-router-dom'; - -import { AdminPanel } from '@/assets/img/AdminPanel'; -import { ArchiveBox } from '@/assets/img/ArchiveBox'; -import { Construction } from '@/assets/img/Construction'; -import { DatabaseLayers } from '@/assets/img/DatabaseLayers'; -import { Folder } from '@/assets/img/Folder'; -import { Group } from '@/assets/img/Group'; -import { GroupRounded } from '@/assets/img/GroupRounded'; -import { Jobs } from '@/assets/img/Jobs'; -import { Link } from '@/assets/img/Link'; -import { ModelBrain } from '@/assets/img/ModelBrain'; -import { PaintRounded } from '@/assets/img/PaintRounded'; -import { PersonRounded } from '@/assets/img/PersonRounded'; -import { SEMOSS } from '@/assets/img/SEMOSS'; -import { Function } from '@/assets/img/Function'; -import { Vector } from '@/assets/img/Vector'; - -import { useSettings } from '@/hooks'; - -import { SETTINGS_ROUTES } from './settings.constants'; - -const StyledContainer = styled('div')(({ theme }) => ({ - display: 'flex', - width: 'auto', - flexDirection: 'column', - alignItems: 'flex-start', - gap: theme.spacing(3), + Card, + Grid, + IconButton, + MenuItem, + Search, + Select, + styled, + Typography, +} from "@semoss/ui"; +import { AdminPanel } from "@/assets/img/AdminPanel"; +import { ArchiveBox } from "@/assets/img/ArchiveBox"; +import { Construction } from "@/assets/img/Construction"; +import { DatabaseLayers } from "@/assets/img/DatabaseLayers"; +import { Folder } from "@/assets/img/Folder"; +import { Function } from "@/assets/img/Function"; +import { Group } from "@/assets/img/Group"; +import { GroupRounded } from "@/assets/img/GroupRounded"; +import { Jobs } from "@/assets/img/Jobs"; +import { Link } from "@/assets/img/Link"; +import { ModelBrain } from "@/assets/img/ModelBrain"; +import { PaintRounded } from "@/assets/img/PaintRounded"; +import { PersonRounded } from "@/assets/img/PersonRounded"; +import { SEMOSS } from "@/assets/img/SEMOSS"; +import { Vector } from "@/assets/img/Vector"; +import { useSettings } from "@/hooks"; +import { SETTINGS_ROUTES } from "./settings.constants"; + +const StyledContainer = styled("div")(({ theme }) => ({ + display: "flex", + width: "auto", + flexDirection: "column", + alignItems: "flex-start", + gap: theme.spacing(3), })); const StyledCard = styled(Card)(() => ({ - '&:hover': { - cursor: 'pointer', - }, + "&:hover": { + cursor: "pointer", + }, })); const StyledCardHeader = styled(Card.Header)(({ theme }) => ({ - height: theme.spacing(7.75), - margin: '0px 0px 0px 0px', + height: theme.spacing(7.75), + margin: "0px 0px 0px 0px", })); const StyledCardContent = styled(Card.Content)(({ theme }) => ({ - height: theme.spacing(5), - margin: '0px 0px 0px 0px', + height: theme.spacing(5), + margin: "0px 0px 0px 0px", })); -const StyledSearchbarContainer = styled('div')(({ theme }) => ({ - display: 'flex', - width: '100%', - alignItems: 'flex-start', - gap: theme.spacing(3), +const StyledSearchbarContainer = styled("div")(({ theme }) => ({ + display: "flex", + width: "100%", + alignItems: "flex-start", + gap: theme.spacing(3), })); const StyledSort = styled(Select)(() => ({ - width: '20%', + width: "20%", })); -const CardActionsLeft = styled('div')({ - display: 'flex', - width: '100%', - alignItems: 'flex-start', +const CardActionsLeft = styled("div")({ + display: "flex", + width: "100%", + alignItems: "flex-start", }); -const CardActionsRight = styled('div')({ - display: 'flex', - marginLeft: 'auto', +const CardActionsRight = styled("div")({ + display: "flex", + marginLeft: "auto", }); -const StyledSearch = styled(Search)({ width: '80%' }); +const StyledSearch = styled(Search)({ width: "80%" }); const DEFAULT_CARDS = SETTINGS_ROUTES.filter( - (r) => !!r.path && r.history.length < 2, + (r) => !!r.path && r.history.length < 2, ); const IconMapper = { - 'Database Settings': , - 'Model Settings': ( - - ), - 'Storage Settings': , - 'App Settings': , - 'Vector Settings': , - 'Function Settings': , - 'Insight Settings': , - 'Member Settings': , - Configuration: , - 'Admin Query': , - 'External Connections': , - Teams: , - 'Teams Management': , - 'Team Permissions': , - 'My Profile': , - Theming: , - Jobs: , + "Database Settings": , + "Model Settings": ( + + ), + "Storage Settings": , + "App Settings": , + "Vector Settings": , + "Function Settings": , + "Insight Settings": , + "Member Settings": , + Configuration: , + "Admin Query": , + "External Connections": , + Teams: , + "Teams Management": , + "Team Permissions": , + "My Profile": , + Theming: , + Jobs: , }; export const SettingsIndexPage = () => { - const navigate = useNavigate(); - const { adminMode } = useSettings(); - const [cards, setCards] = useState(DEFAULT_CARDS); - const [search, setSearch] = useState(''); - const [sort, setSort] = useState('Name'); - - useEffect(() => { - // reset the options if there is no search value - if (!search) { - setCards(DEFAULT_CARDS); - return; - } - - const cleanedSearch = search.toLowerCase(); - - const filtered = DEFAULT_CARDS.filter((c) => { - return c.title.toLowerCase().includes(cleanedSearch); - }); - - setCards(filtered); - }, [search]); - - return ( - - - { - setSearch(e.target.value); - }} - /> - setSort(e.target.value)} - > - Name - - - - - {cards.map((c, i) => { - if (c.admin && !adminMode) { - return; - } else { - return ( - - navigate(c.path)}> - - - - {c.description} - - - {/* disabled for now */} - - - - - - - - - - - ); - } - })} - - - ); + const navigate = useNavigate(); + const { adminMode } = useSettings(); + const [cards, setCards] = useState(DEFAULT_CARDS); + const [search, setSearch] = useState(""); + const [sort, setSort] = useState("Name"); + + useEffect(() => { + // reset the options if there is no search value + if (!search) { + setCards(DEFAULT_CARDS); + return; + } + + const cleanedSearch = search.toLowerCase(); + + const filtered = DEFAULT_CARDS.filter((c) => { + return c.title.toLowerCase().includes(cleanedSearch); + }); + + setCards(filtered); + }, [search]); + + return ( + + + { + setSearch(e.target.value); + }} + /> + setSort(e.target.value)} + > + Name + + + + + {cards.map((c, i) => { + if (c.admin && !adminMode) { + return; + } else { + return ( + + navigate(c.path)}> + + + + {c.description} + + + {/* disabled for now */} + + + + + + + + + + + ); + } + })} + + + ); }; diff --git a/packages/client/src/pages/settings/SettingsLayout.tsx b/packages/client/src/pages/settings/SettingsLayout.tsx index ad5d3076d4..4c4184682b 100644 --- a/packages/client/src/pages/settings/SettingsLayout.tsx +++ b/packages/client/src/pages/settings/SettingsLayout.tsx @@ -1,255 +1,254 @@ -import { useEffect, useMemo, useState } from 'react'; import { - Outlet, - Link, - useLocation, - matchPath, - useParams, -} from 'react-router-dom'; + AdminPanelSettingsOutlined, + ContentCopyOutlined, +} from "@mui/icons-material"; +import { observer } from "mobx-react-lite"; +import { useEffect, useMemo, useState } from "react"; import { - styled, - Typography, - Breadcrumbs, - Stack, - Tooltip, - IconButton, - Chip, - Button, -} from '@semoss/ui'; - -import { useRootStore } from '@/hooks'; -import { SettingsContext } from '@/contexts'; -import { SETTINGS_ROUTES } from './settings.constants'; -import { observer } from 'mobx-react-lite'; + Link, + matchPath, + Outlet, + useLocation, + useParams, +} from "react-router-dom"; import { - AdminPanelSettingsOutlined, - ContentCopyOutlined, -} from '@mui/icons-material'; -import { PrivacyPreferenceCenterModal } from '@/components/cookies/PrivacyPreferenceCenterModal'; -import { NavbarLeft, NavbarHeader } from '../../components/shared'; - -const StyledHeader = styled('div')(({ theme }) => ({ - display: 'flex', - justifyContent: 'space-between', + Breadcrumbs, + Button, + Chip, + IconButton, + Stack, + styled, + Tooltip, + Typography, +} from "@semoss/ui"; +import { PrivacyPreferenceCenterModal } from "@/components/cookies/PrivacyPreferenceCenterModal"; +import { SettingsContext } from "@/contexts"; +import { useRootStore } from "@/hooks"; +import { NavbarHeader, NavbarLeft } from "../../components/shared"; +import { SETTINGS_ROUTES } from "./settings.constants"; + +const StyledHeader = styled("div")(({ theme }) => ({ + display: "flex", + justifyContent: "space-between", })); -const StyledAdminHeader = styled('div')(({ theme }) => ({ - display: 'flex', - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', +const StyledAdminHeader = styled("div")(({ theme }) => ({ + display: "flex", + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", })); -const StyledAdminActionButtons = styled('div')(({ theme }) => ({ - display: 'flex', - alignItems: 'center', - gap: theme.spacing(1), +const StyledAdminActionButtons = styled("div")(({ theme }) => ({ + display: "flex", + alignItems: "center", + gap: theme.spacing(1), })); const StyledId = styled(Typography)(({ theme }) => ({ - color: theme.palette.secondary.dark, + color: theme.palette.secondary.dark, })); const StyledChip = styled(Chip, { - shouldForwardProp: (prop) => prop !== 'adminMode', + shouldForwardProp: (prop) => prop !== "adminMode", })<{ adminMode: boolean }>(({ theme, adminMode }) => ({ - backgroundColor: `${ - adminMode ? 'rgba(46, 125, 50, .15)' : theme.palette.success - }`, - '&&:hover': { - backgroundColor: `${ - adminMode ? 'rgba(46, 125, 50, .25)' : theme.palette.grey[300] - }`, - }, + backgroundColor: `${ + adminMode ? "rgba(46, 125, 50, .15)" : theme.palette.success + }`, + "&&:hover": { + backgroundColor: `${ + adminMode ? "rgba(46, 125, 50, .25)" : theme.palette.grey[300] + }`, + }, })); -const IdContainer = styled('span')(({ theme }) => ({ - display: 'flex', - alignItems: 'center', +const IdContainer = styled("span")(({ theme }) => ({ + display: "flex", + alignItems: "center", })); -const StyledAdminContainer = styled('div')(({ theme }) => ({ - top: theme.spacing(1), - right: theme.spacing(1), - zIndex: 1, +const StyledAdminContainer = styled("div")(({ theme }) => ({ + top: theme.spacing(1), + right: theme.spacing(1), + zIndex: 1, })); const StyledLink = styled(Link)(({ theme }) => ({ - textDecoration: 'none', - color: 'inherit', + textDecoration: "none", + color: "inherit", })); export const SettingsLayout = observer(() => { - const { configStore } = useRootStore(); - const { id } = useParams(); - const { pathname, state } = useLocation(); - const [privacyCenterOpen, setPrivacyCenterOpen] = useState(false); - - // track the active breadcrumbs - const [adminMode, setAdminMode] = useState(false); - - // if the user is not an admin turn it off - useEffect(() => { - if (!configStore.store.user.admin) { - setAdminMode(false); - } - }, [configStore.store.user.admin]); - - const matchedRoute = useMemo(() => { - for (const r of SETTINGS_ROUTES) { - if (matchPath(`/settings/${r.path}`, pathname)) { - return r; - } - } - - return null; - }, [pathname]); - - if (!matchedRoute) { - return null; - } - - /** - * Copy text and add it to the clipboard - * @param text - text to copy - */ - const copy = (text: string) => { - navigator.clipboard.writeText(text); - }; - - return ( - <> - - - - - - - {matchedRoute.path && ( - - - - Settings - - {matchedRoute.history.map((link, idx) => { - return ( - ', id)} - underline="none" - color={ - matchedRoute.history - .length - - 1 === - idx - ? 'text.disabled' - : 'inherit' - } - variant="body1" - state={{ ...state }} - > - {link.includes('') - ? id - : matchedRoute.title} - - ); - })} - - - )} - - - - {matchedRoute.history.length < 2 - ? matchedRoute.title - : state - ? state.name - : matchedRoute.title} - - - - - - {configStore.store.user.admin && ( - - } - label={ - adminMode - ? 'Admin On' - : 'Admin Off' - } - onClick={() => - setAdminMode(!adminMode) - } - /> - )} - - - - {id ? ( - - {id} - { - copy(id); - }} - data-testid={'settings-layout-copy-btn'} - > - - - - - - ) : null} - - {!adminMode || matchedRoute.path !== '' - ? matchedRoute.description - : matchedRoute.adminDescription} - - - - - setPrivacyCenterOpen(false)} - /> - - - - ); + const { configStore } = useRootStore(); + const { id } = useParams(); + const { pathname, state } = useLocation(); + const [privacyCenterOpen, setPrivacyCenterOpen] = useState(false); + + // track the active breadcrumbs + const [adminMode, setAdminMode] = useState(false); + + // if the user is not an admin turn it off + useEffect(() => { + if (!configStore.store.user.admin) { + setAdminMode(false); + } + }, [configStore.store.user.admin]); + + const matchedRoute = useMemo(() => { + for (const r of SETTINGS_ROUTES) { + if (matchPath(`/settings/${r.path}`, pathname)) { + return r; + } + } + + return null; + }, [pathname]); + + if (!matchedRoute) { + return null; + } + + /** + * Copy text and add it to the clipboard + * @param text - text to copy + */ + const copy = (text: string) => { + navigator.clipboard.writeText(text); + }; + + return ( + <> + + + + + + + {matchedRoute.path && ( + + + + Settings + + {matchedRoute.history.map((link, idx) => { + return ( + ", id)} + underline="none" + color={ + matchedRoute.history + .length - + 1 === + idx + ? "text.disabled" + : "inherit" + } + variant="body1" + state={{ ...state }} + > + {link.includes("") + ? id + : matchedRoute.title} + + ); + })} + + + )} + + + + {matchedRoute.history.length < 2 + ? matchedRoute.title + : state + ? state.name + : matchedRoute.title} + + + + + + {configStore.store.user.admin && ( + + } + label={ + adminMode + ? "Admin On" + : "Admin Off" + } + onClick={() => + setAdminMode(!adminMode) + } + /> + )} + + + + {id ? ( + + {id} + { + copy(id); + }} + data-testid={"settings-layout-copy-btn"} + > + + + + + + ) : null} + + {!adminMode || matchedRoute.path !== "" + ? matchedRoute.description + : matchedRoute.adminDescription} + + + + + setPrivacyCenterOpen(false)} + /> + + + + ); }); diff --git a/packages/client/src/pages/settings/SettingsRouter.tsx b/packages/client/src/pages/settings/SettingsRouter.tsx index 8ea893eef7..2e71cc6dd0 100644 --- a/packages/client/src/pages/settings/SettingsRouter.tsx +++ b/packages/client/src/pages/settings/SettingsRouter.tsx @@ -1,84 +1,80 @@ -import { Routes, Route, Navigate } from 'react-router-dom'; -import { observer } from 'mobx-react-lite'; - -import { SETTINGS_ROUTES } from './settings.constants'; - -import { SettingsLayout } from './SettingsLayout'; -import { SettingsIndexPage } from './SettingsIndexPage'; - -import { EngineSettingsIndexPage } from './EngineSettingsIndexPage'; -import { EngineSettingsDetailPage } from './EngineSettingsDetailPage'; -import { DatabaseSettingsPage } from './DatabaseSettingsPage'; -import { ProjectSettingsPage } from './ProjectSettingsPage'; -import { TeamsSettingsPage } from './TeamsSettingsPage'; -import { AppSettingsDetailPage } from './AppSettingsDetailPage'; -import { TeamSettingsDetailPage } from './TeamSettingsDetailPage'; -import { InsightSettingsPage } from './InsightSettingsPage'; -import { InsightSettingsDetailPage } from './InsightSettingsDetailPage'; - -import { MemberSettingsPage } from './MemberSettingsPage'; -import { ConfigurationsPage } from './ConfigurationsPage'; -import { AdminQueryPage } from './AdminQueryPage'; -import { MyProfilePage } from './MyProfilePage'; -import { JobsPage } from '../jobs/JobsPage'; +import { observer } from "mobx-react-lite"; +import { Navigate, Route, Routes } from "react-router-dom"; +import { JobsPage } from "../jobs/JobsPage"; +import { AdminQueryPage } from "./AdminQueryPage"; +import { AppSettingsDetailPage } from "./AppSettingsDetailPage"; +import { ConfigurationsPage } from "./ConfigurationsPage"; +import { DatabaseSettingsPage } from "./DatabaseSettingsPage"; +import { EngineSettingsDetailPage } from "./EngineSettingsDetailPage"; +import { EngineSettingsIndexPage } from "./EngineSettingsIndexPage"; +import { InsightSettingsDetailPage } from "./InsightSettingsDetailPage"; +import { InsightSettingsPage } from "./InsightSettingsPage"; +import { MemberSettingsPage } from "./MemberSettingsPage"; +import { MyProfilePage } from "./MyProfilePage"; +import { ProjectSettingsPage } from "./ProjectSettingsPage"; +import { SettingsIndexPage } from "./SettingsIndexPage"; +import { SettingsLayout } from "./SettingsLayout"; +import { SETTINGS_ROUTES } from "./settings.constants"; +import { TeamSettingsDetailPage } from "./TeamSettingsDetailPage"; +import { TeamsSettingsPage } from "./TeamsSettingsPage"; // map each route to a component const SETTINGS_COMPONETS = { - '': SettingsIndexPage, - app: ProjectSettingsPage, - 'app/:id': AppSettingsDetailPage, - insight: InsightSettingsPage, - 'insight/:id/:projectId': InsightSettingsDetailPage, - members: MemberSettingsPage, - 'social-properties': ConfigurationsPage, - 'admin-query': AdminQueryPage, - 'my-profile': MyProfilePage, - jobs: JobsPage, - 'team-permissions': TeamsSettingsPage, - 'team-permissions/:id': TeamSettingsDetailPage, + "": SettingsIndexPage, + app: ProjectSettingsPage, + "app/:id": AppSettingsDetailPage, + insight: InsightSettingsPage, + "insight/:id/:projectId": InsightSettingsDetailPage, + members: MemberSettingsPage, + "social-properties": ConfigurationsPage, + "admin-query": AdminQueryPage, + "my-profile": MyProfilePage, + jobs: JobsPage, + "team-permissions": TeamsSettingsPage, + "team-permissions/:id": TeamSettingsDetailPage, - // engine - database: () => , - 'database/:id': () => , - model: () => , - 'model/:id': () => , - storage: () => , - 'storage/:id': () => , - function: () => , - 'function/:id': () => , - vector: () => , - 'vector/:id': () => , + // engine + database: () => , + "database/:id": () => , + model: () => , + "model/:id": () => , + storage: () => , + "storage/:id": () => , + function: () => , + "function/:id": () => , + vector: () => , + "vector/:id": () => , }; export const SettingsRouter = observer(() => { - return ( - - }> - {SETTINGS_ROUTES.map((r) => { - const Component = SETTINGS_COMPONETS[r.path]; + return ( + + }> + {SETTINGS_ROUTES.map((r) => { + const Component = SETTINGS_COMPONETS[r.path]; - if (!Component) { - throw Error( - `ERROR ::: missing component for path ${r.path}`, - ); - } + if (!Component) { + throw Error( + `ERROR ::: missing component for path ${r.path}`, + ); + } - if (!r.path) { - return ( - } /> - ); - } + if (!r.path) { + return ( + } /> + ); + } - return ( - } - /> - ); - })} - - } /> - - ); + return ( + } + /> + ); + })} + + } /> + + ); }); diff --git a/packages/client/src/pages/settings/TeamSettingsDetailPage.tsx b/packages/client/src/pages/settings/TeamSettingsDetailPage.tsx index 112edae417..5695a3e2cf 100644 --- a/packages/client/src/pages/settings/TeamSettingsDetailPage.tsx +++ b/packages/client/src/pages/settings/TeamSettingsDetailPage.tsx @@ -1,62 +1,61 @@ -import { useLocation, useSearchParams, useParams } from 'react-router-dom'; -import { styled } from '@semoss/ui'; - +import { useLocation, useParams, useSearchParams } from "react-router-dom"; +import { styled } from "@semoss/ui"; import { - TeamMembersTable, - TeamProjectsTable, - TeamEnginesTable, -} from '@/components/teams'; -import { TeamMembersProviderBanner } from '@/components/teams/TeamMembersProviderBanner'; - -const StyledContainer = styled('div')(({ theme }) => ({ - width: '100%', - display: 'flex', - alignSelf: 'stretch', - flexDirection: 'column', - alignItems: 'flex-start', - gap: theme.spacing(2), + TeamEnginesTable, + TeamMembersTable, + TeamProjectsTable, +} from "@/components/teams"; +import { TeamMembersProviderBanner } from "@/components/teams/TeamMembersProviderBanner"; + +const StyledContainer = styled("div")(({ theme }) => ({ + width: "100%", + display: "flex", + alignSelf: "stretch", + flexDirection: "column", + alignItems: "flex-start", + gap: theme.spacing(2), })); -const StyledContent = styled('div')(({ theme }) => ({ - display: 'flex', - width: '100%', - flexDirection: 'column', - alignItems: 'flex-start', - gap: theme.spacing(2), - flexShrink: '0', +const StyledContent = styled("div")(({ theme }) => ({ + display: "flex", + width: "100%", + flexDirection: "column", + alignItems: "flex-start", + gap: theme.spacing(2), + flexShrink: "0", })); export const TeamSettingsDetailPage = () => { - const { state } = useLocation(); - - /** - * TODO: Likely want to send with :id from url - * And pull info from database - */ - const type = state.type; - const id = state.name; - - return ( - - - {type === 'CUSTOM' ? ( - - ) : ( - - )} - - - - - - - ); + const { state } = useLocation(); + + /** + * TODO: Likely want to send with :id from url + * And pull info from database + */ + const type = state.type; + const id = state.name; + + return ( + + + {type === "CUSTOM" ? ( + + ) : ( + + )} + + + + + + + ); }; diff --git a/packages/client/src/pages/settings/TeamsSettingsPage.tsx b/packages/client/src/pages/settings/TeamsSettingsPage.tsx index 6679a25deb..aff69b5ed7 100644 --- a/packages/client/src/pages/settings/TeamsSettingsPage.tsx +++ b/packages/client/src/pages/settings/TeamsSettingsPage.tsx @@ -1,313 +1,311 @@ -import { useEffect, useState, useRef, useReducer, useCallback } from 'react'; -import { useNavigate } from 'react-router-dom'; -import { observer } from 'mobx-react-lite'; -import { Add, ExpandMore, ArrowForward, ArrowBack } from '@mui/icons-material'; +import { Add, ArrowBack, ArrowForward, ExpandMore } from "@mui/icons-material"; +import { observer } from "mobx-react-lite"; +import { useCallback, useEffect, useReducer, useRef, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { debounced } from "@semoss/sdk/react"; import { - Grid, - Search, - styled, - Backdrop, - CircularProgress, - Stack, - Typography, - Box, - Button, - IconButton, - Menu, - MenuItemTwo, -} from '@semoss/ui'; -import { debounced } from '@semoss/sdk/react'; - -import { useRootStore } from '@/hooks'; -import { useSettings } from '@/hooks/useSettings'; -import { TeamTileCard } from '@/components/teams/TeamTileCard'; -import { AddTeamModal } from '@/components/teams/AddTeamModal'; + Backdrop, + Box, + Button, + CircularProgress, + Grid, + IconButton, + Menu, + MenuItemTwo, + Search, + Stack, + styled, + Typography, +} from "@semoss/ui"; +import { AddTeamModal } from "@/components/teams/AddTeamModal"; +import { TeamTileCard } from "@/components/teams/TeamTileCard"; +import { useRootStore } from "@/hooks"; +import { useSettings } from "@/hooks/useSettings"; export interface DBMember { - ID: string; - NAME: string; - PERMISSION: string; - EMAIL: string; - SELECTED: boolean; + ID: string; + NAME: string; + PERMISSION: string; + EMAIL: string; + SELECTED: boolean; } export interface Database { - app_cost: string; - app_favorite: number; - app_id: string; - app_name: string; - app_type: string; - database_cost: string; - database_id: string; - database_name: string; - database_type: string; - low_database_name: string; - database_global: true; - database_favorite?: number; - permission?: number; - user_permission?: number; + app_cost: string; + app_favorite: number; + app_id: string; + app_name: string; + app_type: string; + database_cost: string; + database_id: string; + database_name: string; + database_type: string; + low_database_name: string; + database_global: true; + database_favorite?: number; + permission?: number; + user_permission?: number; } -const StyledContainer = styled('div')({ - display: 'flex', - width: '100%', - flexDirection: 'column', - alignItems: 'flex-start', - gap: '24px', +const StyledContainer = styled("div")({ + display: "flex", + width: "100%", + flexDirection: "column", + alignItems: "flex-start", + gap: "24px", }); -const StyledSearchbarContainer = styled('div')({ - display: 'flex', - width: '100%', - alignItems: 'flex-start', - justifyContent: 'space-between', - gap: '24px', +const StyledSearchbarContainer = styled("div")({ + display: "flex", + width: "100%", + alignItems: "flex-start", + justifyContent: "space-between", + gap: "24px", }); const StyledSearchbar = styled(Search)({ - width: '80%', + width: "80%", }); const StyledBackdrop = styled(Backdrop)({ - backgroundColor: 'rgba(255, 255, 255, 0.5)', - zIndex: 1501, + backgroundColor: "rgba(255, 255, 255, 0.5)", + zIndex: 1501, }); const initialState = { - favoritedDbs: [], - teams: [], + favoritedDbs: [], + teams: [], }; -const StyledSearchbarDiv = styled('div')({ - display: 'flex', - gap: '16px', +const StyledSearchbarDiv = styled("div")({ + display: "flex", + gap: "16px", }); const StyledAddButton = styled(Button)({ - width: '150px', - borderRadius: '12px', + width: "150px", + borderRadius: "12px", }); const reducer = (state, action) => { - switch (action.type) { - case 'field': { - return { - ...state, - [action.field]: action.value, - }; - } - } - return state; + switch (action.type) { + case "field": { + return { + ...state, + [action.field]: action.value, + }; + } + } + return state; }; -const StyledGrid = styled('div')({ - display: 'grid', - width: '100%', - gridTemplateColumns: 'repeat(4, 1fr)', - gap: '24px', +const StyledGrid = styled("div")({ + display: "grid", + width: "100%", + gridTemplateColumns: "repeat(4, 1fr)", + gap: "24px", }); export const TeamsSettingsPage = observer(() => { - const { adminMode } = useSettings(); - const { monolithStore } = useRootStore(); - const navigate = useNavigate(); - - const [addModal, setAddModal] = useState(false); - const [filteredTeams, setFilteredTeams] = useState([]); - const [state, dispatch] = useReducer(reducer, initialState); - const { teams } = state; - const [anchorEl, setAnchorEl] = useState(null); + const { adminMode } = useSettings(); + const { monolithStore } = useRootStore(); + const navigate = useNavigate(); - const [search, setSearch] = useState(''); + const [addModal, setAddModal] = useState(false); + const [filteredTeams, setFilteredTeams] = useState([]); + const [state, dispatch] = useReducer(reducer, initialState); + const { teams } = state; + const [anchorEl, setAnchorEl] = useState(null); - // To focus when getting new results - const searchbarRef = useRef(null); + const [search, setSearch] = useState(""); + // To focus when getting new results + const searchbarRef = useRef(null); - /* - **/ - useEffect(() => { - monolithStore.getTeams(true).then((data) => { - dispatch({ - type: 'field', - field: 'teams', - value: data, - }); - }); - }, [adminMode, search]); + /* + **/ + useEffect(() => { + monolithStore.getTeams(true).then((data) => { + dispatch({ + type: "field", + field: "teams", + value: data, + }); + }); + }, [adminMode, search]); - // Updated debounced filtering function - const filterTeams = useCallback(() => { - setFilteredTeams( - teams - .filter((d) => - d.id.toLowerCase().includes(search.toLowerCase()), - ) - .sort((a, b) => a.id.localeCompare(b.id)), - ); - }, [teams, search]); + // Updated debounced filtering function + const filterTeams = useCallback(() => { + setFilteredTeams( + teams + .filter((d) => + d.id.toLowerCase().includes(search.toLowerCase()), + ) + .sort((a, b) => a.id.localeCompare(b.id)), + ); + }, [teams, search]); - const debouncedFilterTeams = debounced(filterTeams, 150); + const debouncedFilterTeams = debounced(filterTeams, 150); - // Trigger debounced filtering when teams or search changes - useEffect(() => { - debouncedFilterTeams(); - }, [teams, search, debouncedFilterTeams]); + // Trigger debounced filtering when teams or search changes + useEffect(() => { + debouncedFilterTeams(); + }, [teams, search, debouncedFilterTeams]); - const handleMenuClick = (event) => { - setAnchorEl(event.currentTarget); - }; - const handleMenuClose = () => { - setAnchorEl(null); - }; - const handleSort = (order) => { - const sorted = [...filteredTeams].sort((a, b) => { - if (order === 'asc') { - return a.id.localeCompare(b.id); - } else { - return b.id.localeCompare(a.id); - } - }); - setFilteredTeams(sorted); - handleMenuClose(); - }; + const handleMenuClick = (event) => { + setAnchorEl(event.currentTarget); + }; + const handleMenuClose = () => { + setAnchorEl(null); + }; + const handleSort = (order) => { + const sorted = [...filteredTeams].sort((a, b) => { + if (order === "asc") { + return a.id.localeCompare(b.id); + } else { + return b.id.localeCompare(a.id); + } + }); + setFilteredTeams(sorted); + handleMenuClose(); + }; - const isAsc = () => { - const sorted = [...filteredTeams].sort((a, b) => { - return a.id.localeCompare(b.id); - }); - return JSON.stringify(filteredTeams) === JSON.stringify(sorted); - }; + const isAsc = () => { + const sorted = [...filteredTeams].sort((a, b) => { + return a.id.localeCompare(b.id); + }); + return JSON.stringify(filteredTeams) === JSON.stringify(sorted); + }; - const isDesc = () => { - const sorted = [...filteredTeams].sort((a, b) => { - return b.id.localeCompare(a.id); - }); - return JSON.stringify(filteredTeams) === JSON.stringify(sorted); - }; + const isDesc = () => { + const sorted = [...filteredTeams].sort((a, b) => { + return b.id.localeCompare(a.id); + }); + return JSON.stringify(filteredTeams) === JSON.stringify(sorted); + }; - return ( - <> - - - - Teams - - - { - setSearch(e.target.value); - }} - size="small" - ref={searchbarRef} - /> - } - onClick={() => setAddModal(true)} - data-testid={'teams-settings-add-btn'} - > - Add New - - - - {/* */} -
    - - - Sort By - - - -
    - - handleSort('asc')} - sx={{ - backgroundColor: isAsc() ? '#EBF3F8' : 'inherit', - }} - > - AZ - - handleSort('desc')} - sx={{ - backgroundColor: isDesc() ? '#EBF3F8' : 'inherit', - }} - > - ZA - - - {/* */} - - {filteredTeams.length - ? filteredTeams.map((team, i) => { - return ( -
    - { - navigate( - `${team.id - .toLowerCase() - .replace(/['"]+/g, '') - .replace(/\s/g, '-')}`, - { - state: { - name: team.id, - type: team.type, - }, - }, - ); - }} - /> -
    - ); - }) - : null} -
    + return ( + <> + + + + Teams + + + { + setSearch(e.target.value); + }} + size="small" + ref={searchbarRef} + /> + } + onClick={() => setAddModal(true)} + data-testid={"teams-settings-add-btn"} + > + Add New + + + + {/* */} +
    + + + Sort By + + + +
    + + handleSort("asc")} + sx={{ + backgroundColor: isAsc() ? "#EBF3F8" : "inherit", + }} + > + AZ + + handleSort("desc")} + sx={{ + backgroundColor: isDesc() ? "#EBF3F8" : "inherit", + }} + > + ZA + + + {/* */} + + {filteredTeams.length + ? filteredTeams.map((team, i) => { + return ( +
    + { + navigate( + `${team.id + .toLowerCase() + .replace(/['"]+/g, "") + .replace(/\s/g, "-")}`, + { + state: { + name: team.id, + type: team.type, + }, + }, + ); + }} + /> +
    + ); + }) + : null} +
    - { - if (team) { - const obj = { - id: team.id, - type: team.type, - description: team.description, - }; + { + if (team) { + const obj = { + id: team.id, + type: team.type, + description: team.description, + }; - dispatch({ - type: 'field', - field: 'teams', - value: [...teams, obj], - }); - } - setAddModal(false); - }} - /> -
    - - ); + dispatch({ + type: "field", + field: "teams", + value: [...teams, obj], + }); + } + setAddModal(false); + }} + /> +
    + + ); }); diff --git a/packages/client/src/pages/settings/index.ts b/packages/client/src/pages/settings/index.ts index ce29e41cd9..de9642373d 100644 --- a/packages/client/src/pages/settings/index.ts +++ b/packages/client/src/pages/settings/index.ts @@ -1,5 +1,5 @@ -export * from './settings.constants'; +export * from "./settings.constants"; -import { SettingsRouter } from './SettingsRouter'; +import { SettingsRouter } from "./SettingsRouter"; export { SettingsRouter }; diff --git a/packages/client/src/pages/settings/settings.constants.ts b/packages/client/src/pages/settings/settings.constants.ts index a9883ed0ce..adfdaa8efa 100644 --- a/packages/client/src/pages/settings/settings.constants.ts +++ b/packages/client/src/pages/settings/settings.constants.ts @@ -1,203 +1,203 @@ import { - mdiAccountGroup, - mdiClipboardTextOutline, - // mdiClock, - mdiCog, - mdiDatabase, - mdiDatabaseSearch, - mdiTabletCellphone, - // mdiTextBoxMultipleOutline, - mdiArchive, -} from '@mdi/js'; + mdiAccountGroup, + // mdiTextBoxMultipleOutline, + mdiArchive, + mdiClipboardTextOutline, + // mdiClock, + mdiCog, + mdiDatabase, + mdiDatabaseSearch, + mdiTabletCellphone, +} from "@mdi/js"; export const SETTINGS_ROUTES: { - /*** Title of the page */ - title: string; - /** Relative path to navigate to the page */ - path: string; - /** Description of the page */ - description: string; + /*** Title of the page */ + title: string; + /** Relative path to navigate to the page */ + path: string; + /** Description of the page */ + description: string; - /** Description of the page if admin */ - adminDescription?: string; + /** Description of the page if admin */ + adminDescription?: string; - /** Icon representing the page */ - icon: string; + /** Icon representing the page */ + icon: string; - /** Prior Links to nav to */ - history?: string[]; + /** Prior Links to nav to */ + history?: string[]; - admin?: boolean; + admin?: boolean; }[] = [ - { - title: 'Settings', - path: '', - description: 'View and edit settings for the application', - adminDescription: - 'View and make changes to settings at the database, app, and insight level. As an admin conduct queries on SEMOSS specific databases as well as view and edit existing social properties.', - icon: mdiCog, - history: [], - }, - { - title: 'App Settings', - path: 'app', - description: 'View and edit settings for apps', - icon: mdiClipboardTextOutline, - history: ['app'], - }, - { - title: 'App Settings', - path: 'app/:id', - description: - 'View member permissions, pending requests, and all other viewable settings pertaining to the app', - icon: mdiClipboardTextOutline, - history: ['app', 'app/'], - }, - { - title: 'Database Settings', - path: 'database', - description: 'View and edit settings for databases', - icon: mdiDatabase, - history: ['database'], - }, - { - title: 'Database Settings', - path: 'database/:id', - description: - 'View member permissions, pending requests, and all other viewable settings pertaining to the database', - icon: mdiDatabase, - history: ['database', 'database/'], - }, - { - title: 'Function Settings', - path: 'function', - description: 'View and edit settings for functions', - icon: mdiDatabase, - history: ['function'], - }, - { - title: 'Function Settings', - path: 'function/:id', - description: - 'View member permissions, pending requests, and all other viewable settings pertaining to the database', - icon: mdiDatabase, - history: ['function', 'function/'], - }, - { - title: 'Model Settings', - path: 'model', - description: 'View and edit settings for models', - icon: mdiDatabase, - history: ['model'], - }, - { - title: 'Model Settings', - path: 'model/:id', - description: - 'View member permissions, pending requests, and all other viewable settings pertaining to the model', - icon: mdiDatabase, - history: ['model', 'model/'], - }, - { - title: 'Storage Settings', - path: 'storage', - description: 'View and edit settings for storages', - icon: mdiArchive, - history: ['storage'], - }, - { - title: 'Storage Settings', - path: 'storage/:id', - description: - 'View member permissions, pending requests, and all other viewable settings pertaining to the storage', - icon: mdiArchive, - history: ['storage', 'storage/'], - }, - { - title: 'Vector Settings', - path: 'vector', - description: 'View and edit settings for vector databases', - icon: mdiDatabase, - history: ['vector'], - }, - { - title: 'Vector Settings', - path: 'vector/:id', - description: - 'View member permissions, pending requests, and all other viewable settings pertaining to the vector', - icon: mdiDatabase, - history: ['vector', 'vector/'], - }, - // { - // title: 'Insight Settings', - // path: 'insight', - // description: 'View and edit settings for app insights', - // icon: mdiTextBoxMultipleOutline, - // history: ['insight'], - // }, - // { - // title: 'Insight Settings', - // path: 'insight/:id/:appId', - // description: - // 'View member permissions, pending requests, and all other viewable settings pertaining to the app', - // icon: mdiClipboardTextOutline, - // history: ['insight', 'insight//'], - // }, - { - title: 'Jobs', - path: 'jobs', - description: 'Search by job name or filter using job tags', - icon: mdiTabletCellphone, - history: ['settings/'], - }, - { - title: 'Member Settings', - path: 'members', - description: - 'Add new members, reset passwords, and edit member-based permissions.', - icon: mdiAccountGroup, - history: ['settings/'], - admin: true, - }, - { - title: 'Team Permissions', - path: 'team-permissions', - description: 'View and edit permissions for teams', - icon: mdiDatabase, - history: ['team-permissions'], - admin: true, - }, - { - title: 'Team Permissions', - path: 'team-permissions/:id', - description: - 'View member permissions, pending requests, and all other viewable settings pertaining to the team', - icon: mdiDatabase, - history: ['team-permissions', 'team-permissions/'], - admin: true, - }, - { - title: 'Configuration', - path: 'social-properties', - description: 'Use this portal to change configuration settings.', - icon: mdiTabletCellphone, - history: ['settings/'], - admin: true, - }, - { - title: 'Admin Query', - path: 'admin-query', - description: 'Query on SEMOSS based databases', - icon: mdiDatabaseSearch, - history: ['settings/'], - admin: true, - }, - { - title: 'My Profile', - path: 'my-profile', - description: 'Update settings related to your profile.', - icon: mdiDatabase, - history: ['settings/'], - admin: false, - }, + { + title: "Settings", + path: "", + description: "View and edit settings for the application", + adminDescription: + "View and make changes to settings at the database, app, and insight level. As an admin conduct queries on SEMOSS specific databases as well as view and edit existing social properties.", + icon: mdiCog, + history: [], + }, + { + title: "App Settings", + path: "app", + description: "View and edit settings for apps", + icon: mdiClipboardTextOutline, + history: ["app"], + }, + { + title: "App Settings", + path: "app/:id", + description: + "View member permissions, pending requests, and all other viewable settings pertaining to the app", + icon: mdiClipboardTextOutline, + history: ["app", "app/"], + }, + { + title: "Database Settings", + path: "database", + description: "View and edit settings for databases", + icon: mdiDatabase, + history: ["database"], + }, + { + title: "Database Settings", + path: "database/:id", + description: + "View member permissions, pending requests, and all other viewable settings pertaining to the database", + icon: mdiDatabase, + history: ["database", "database/"], + }, + { + title: "Function Settings", + path: "function", + description: "View and edit settings for functions", + icon: mdiDatabase, + history: ["function"], + }, + { + title: "Function Settings", + path: "function/:id", + description: + "View member permissions, pending requests, and all other viewable settings pertaining to the database", + icon: mdiDatabase, + history: ["function", "function/"], + }, + { + title: "Model Settings", + path: "model", + description: "View and edit settings for models", + icon: mdiDatabase, + history: ["model"], + }, + { + title: "Model Settings", + path: "model/:id", + description: + "View member permissions, pending requests, and all other viewable settings pertaining to the model", + icon: mdiDatabase, + history: ["model", "model/"], + }, + { + title: "Storage Settings", + path: "storage", + description: "View and edit settings for storages", + icon: mdiArchive, + history: ["storage"], + }, + { + title: "Storage Settings", + path: "storage/:id", + description: + "View member permissions, pending requests, and all other viewable settings pertaining to the storage", + icon: mdiArchive, + history: ["storage", "storage/"], + }, + { + title: "Vector Settings", + path: "vector", + description: "View and edit settings for vector databases", + icon: mdiDatabase, + history: ["vector"], + }, + { + title: "Vector Settings", + path: "vector/:id", + description: + "View member permissions, pending requests, and all other viewable settings pertaining to the vector", + icon: mdiDatabase, + history: ["vector", "vector/"], + }, + // { + // title: 'Insight Settings', + // path: 'insight', + // description: 'View and edit settings for app insights', + // icon: mdiTextBoxMultipleOutline, + // history: ['insight'], + // }, + // { + // title: 'Insight Settings', + // path: 'insight/:id/:appId', + // description: + // 'View member permissions, pending requests, and all other viewable settings pertaining to the app', + // icon: mdiClipboardTextOutline, + // history: ['insight', 'insight//'], + // }, + { + title: "Jobs", + path: "jobs", + description: "Search by job name or filter using job tags", + icon: mdiTabletCellphone, + history: ["settings/"], + }, + { + title: "Member Settings", + path: "members", + description: + "Add new members, reset passwords, and edit member-based permissions.", + icon: mdiAccountGroup, + history: ["settings/"], + admin: true, + }, + { + title: "Team Permissions", + path: "team-permissions", + description: "View and edit permissions for teams", + icon: mdiDatabase, + history: ["team-permissions"], + admin: true, + }, + { + title: "Team Permissions", + path: "team-permissions/:id", + description: + "View member permissions, pending requests, and all other viewable settings pertaining to the team", + icon: mdiDatabase, + history: ["team-permissions", "team-permissions/"], + admin: true, + }, + { + title: "Configuration", + path: "social-properties", + description: "Use this portal to change configuration settings.", + icon: mdiTabletCellphone, + history: ["settings/"], + admin: true, + }, + { + title: "Admin Query", + path: "admin-query", + description: "Query on SEMOSS based databases", + icon: mdiDatabaseSearch, + history: ["settings/"], + admin: true, + }, + { + title: "My Profile", + path: "my-profile", + description: "Update settings related to your profile.", + icon: mdiDatabase, + history: ["settings/"], + admin: false, + }, ]; diff --git a/packages/client/src/stores/config/config.store.ts b/packages/client/src/stores/config/config.store.ts index d4e3f810d2..62542350a8 100644 --- a/packages/client/src/stores/config/config.store.ts +++ b/packages/client/src/stores/config/config.store.ts @@ -1,10 +1,14 @@ import { makeAutoObservable, runInAction } from "mobx"; // TODO: Pull from sdk import { runPixel } from "@semoss/sdk/react"; -import { AppMetadata } from "@/components/app"; +import type { AppMetadata } from "@/components/app"; import { THEME } from "@/constants"; -import { RootStore, WorkspaceConfigInterface, WorkspaceStore } from "@/stores"; -import { ALL_TYPES } from "@/types"; +import { + type RootStore, + type WorkspaceConfigInterface, + WorkspaceStore, +} from "@/stores"; +import type { ALL_TYPES } from "@/types"; interface ConfigStoreInterface { /** Status of the application */ diff --git a/packages/client/src/stores/config/index.ts b/packages/client/src/stores/config/index.ts index 034a4ba459..e1f7d70428 100644 --- a/packages/client/src/stores/config/index.ts +++ b/packages/client/src/stores/config/index.ts @@ -1 +1 @@ -export { ConfigStore } from './config.store'; +export { ConfigStore } from "./config.store"; diff --git a/packages/client/src/stores/designer/designer.store.ts b/packages/client/src/stores/designer/designer.store.ts index 59e809ea00..459a133583 100644 --- a/packages/client/src/stores/designer/designer.store.ts +++ b/packages/client/src/stores/designer/designer.store.ts @@ -1,277 +1,276 @@ -import { makeAutoObservable } from 'mobx'; - -import { StateStore } from '@semoss/renderer'; +import { makeAutoObservable } from "mobx"; +import type { StateStore } from "@semoss/renderer"; export interface DesignerStoreInterface { - /** Blocks state information */ - state: StateStore; - /** Current rendered block */ - rendered: string; - /** Current selected block */ - selected: string; - /** Current hovered block */ - hovered: string; - /** Current selected multiple block ids */ - selectedBlocks: string[]; - /** drag information */ - drag: { - /** Is the drag active? */ - active: boolean; - /** Method that is triggered when the item is dropped */ - canDrop: (parent: string, slot: string) => boolean; - /** Name of the dragged widget */ - ghostWidget: string; - /** Display name of the dragged widget */ - ghostDisplay: string; - /** Icon of the dragged widget */ - ghostIcon: any; - /** Position of the dragged item */ - ghostPosition: { - x: number; - y: number; - } | null; - /** Type of action for the placeholder */ - placeholderAction: - | { - type: 'before' | 'after'; - id: string; - } - | { - type: 'replace'; - id: string; - slot: string; - } - | null; - /** Size of the placeholder */ - placeholderSize: { - top: number; - left: number; - height: number; - width: number; - } | null; - }; + /** Blocks state information */ + state: StateStore; + /** Current rendered block */ + rendered: string; + /** Current selected block */ + selected: string; + /** Current hovered block */ + hovered: string; + /** Current selected multiple block ids */ + selectedBlocks: string[]; + /** drag information */ + drag: { + /** Is the drag active? */ + active: boolean; + /** Method that is triggered when the item is dropped */ + canDrop: (parent: string, slot: string) => boolean; + /** Name of the dragged widget */ + ghostWidget: string; + /** Display name of the dragged widget */ + ghostDisplay: string; + /** Icon of the dragged widget */ + ghostIcon: any; + /** Position of the dragged item */ + ghostPosition: { + x: number; + y: number; + } | null; + /** Type of action for the placeholder */ + placeholderAction: + | { + type: "before" | "after"; + id: string; + } + | { + type: "replace"; + id: string; + slot: string; + } + | null; + /** Size of the placeholder */ + placeholderSize: { + top: number; + left: number; + height: number; + width: number; + } | null; + }; } export interface DesignerConfigInterface { - /** Current rendered block */ - rendered: string; + /** Current rendered block */ + rendered: string; } /** * Internal state management of the designer object */ export class DesignerStore { - private _store: DesignerStoreInterface = { - state: undefined, - rendered: '', - selected: '', - hovered: '', - drag: { - active: false, - canDrop: () => false, - ghostWidget: '', - ghostDisplay: '', - ghostIcon: null, - ghostPosition: null, - placeholderSize: null, - placeholderAction: null, - }, - selectedBlocks: [], - }; + private _store: DesignerStoreInterface = { + state: undefined, + rendered: "", + selected: "", + hovered: "", + drag: { + active: false, + canDrop: () => false, + ghostWidget: "", + ghostDisplay: "", + ghostIcon: null, + ghostPosition: null, + placeholderSize: null, + placeholderAction: null, + }, + selectedBlocks: [], + }; - constructor(state: StateStore, config: DesignerConfigInterface) { - // register the blocks - this._store.state = state; + constructor(state: StateStore, config: DesignerConfigInterface) { + // register the blocks + this._store.state = state; - if (config.rendered) { - this._store.rendered = config.rendered; - } + if (config.rendered) { + this._store.rendered = config.rendered; + } - // make it observable - makeAutoObservable(this); - } + // make it observable + makeAutoObservable(this); + } - /** - * Getters - */ - /** - * Get the selected block - * @returns the selected block - */ - get selected() { - return this._store.selected; - } + /** + * Getters + */ + /** + * Get the selected block + * @returns the selected block + */ + get selected() { + return this._store.selected; + } - /** - * Getter for retrieving the currently selected IDs from the store. - * - * @returns An array of selected IDs from the internal store. - */ - get selectedBlocks() { - return this._store.selectedBlocks; - } + /** + * Getter for retrieving the currently selected IDs from the store. + * + * @returns An array of selected IDs from the internal store. + */ + get selectedBlocks() { + return this._store.selectedBlocks; + } - /** - * Get the rendered block - * @returns the rendered block - */ - get rendered() { - return this._store.rendered; - } + /** + * Get the rendered block + * @returns the rendered block + */ + get rendered() { + return this._store.rendered; + } - /** - * Get the hovered block - * @returns the hovered block - */ - get hovered() { - return this._store.hovered; - } + /** + * Get the hovered block + * @returns the hovered block + */ + get hovered() { + return this._store.hovered; + } - /** - * Get the drag information - * @returns the drag information - */ - get drag() { - return this._store.drag; - } + /** + * Get the drag information + * @returns the drag information + */ + get drag() { + return this._store.drag; + } - /** - * Actions - */ - /** - * Set the selected block - * @param id - id of the block that is selected - */ - setSelected(id: string) { - this._store.selected = id; - } + /** + * Actions + */ + /** + * Set the selected block + * @param id - id of the block that is selected + */ + setSelected(id: string) { + this._store.selected = id; + } - /** - * Set the multi-selected block IDs - * @param id - id of the block to add to the multi-selected list, or "clear" to reset the list - */ - addBlockToSelected(id?: string) { - if (id === 'clear') { - this._store.selectedBlocks = []; - } else { - this._store.selectedBlocks.push(id); - } - } + /** + * Set the multi-selected block IDs + * @param id - id of the block to add to the multi-selected list, or "clear" to reset the list + */ + addBlockToSelected(id?: string) { + if (id === "clear") { + this._store.selectedBlocks = []; + } else { + this._store.selectedBlocks.push(id); + } + } - /** - * Set the rendered block - * @param id - id of the block that is rendered - */ - setRendered(id: string) { - // set the rendered block - this._store.rendered = id; - } + /** + * Set the rendered block + * @param id - id of the block that is rendered + */ + setRendered(id: string) { + // set the rendered block + this._store.rendered = id; + } - /** - * Set the hovered block - * @param id - id of the block that is hovered - */ - setHovered(id: string) { - this._store.hovered = id; - } + /** + * Set the hovered block + * @param id - id of the block that is hovered + */ + setHovered(id: string) { + this._store.hovered = id; + } - /** - * Activate the drag - * @param title - title of the dragged item - * @param canDrop - check if the block can be dropped onto the parent and slot - */ - activateDrag( - widget: DesignerStoreInterface['drag']['ghostWidget'], - canDrop: DesignerStoreInterface['drag']['canDrop'], - display: DesignerStoreInterface['drag']['ghostDisplay'], - icon?: DesignerStoreInterface['drag']['ghostIcon'], - ) { - // activate the drag - this._store.drag.active = true; + /** + * Activate the drag + * @param title - title of the dragged item + * @param canDrop - check if the block can be dropped onto the parent and slot + */ + activateDrag( + widget: DesignerStoreInterface["drag"]["ghostWidget"], + canDrop: DesignerStoreInterface["drag"]["canDrop"], + display: DesignerStoreInterface["drag"]["ghostDisplay"], + icon?: DesignerStoreInterface["drag"]["ghostIcon"], + ) { + // activate the drag + this._store.drag.active = true; - // set the block - this._store.drag.canDrop = canDrop; + // set the block + this._store.drag.canDrop = canDrop; - // initialize the ghost - this._store.drag.ghostWidget = widget; - this._store.drag.ghostDisplay = display; - if (icon) { - this._store.drag.ghostIcon = icon; - } - this._store.drag.ghostPosition = null; + // initialize the ghost + this._store.drag.ghostWidget = widget; + this._store.drag.ghostDisplay = display; + if (icon) { + this._store.drag.ghostIcon = icon; + } + this._store.drag.ghostPosition = null; - // reset the placeholder - this.resetPlaceholder(); - } + // reset the placeholder + this.resetPlaceholder(); + } - /** - * Deactivate the drag - */ - deactivateDrag() { - // reset the placeholder - this.resetPlaceholder(); + /** + * Deactivate the drag + */ + deactivateDrag() { + // reset the placeholder + this.resetPlaceholder(); - // reset the ghost - this._store.drag.ghostWidget = ''; - this._store.drag.ghostDisplay = ''; - this._store.drag.ghostIcon = ''; - this._store.drag.ghostPosition = null; + // reset the ghost + this._store.drag.ghostWidget = ""; + this._store.drag.ghostDisplay = ""; + this._store.drag.ghostIcon = ""; + this._store.drag.ghostPosition = null; - // reset the validation - this._store.drag.canDrop = () => false; + // reset the validation + this._store.drag.canDrop = () => false; - // deactivate the drag - this._store.drag.active = false; - } + // deactivate the drag + this._store.drag.active = false; + } - /** - * Update the ghost - * @param position - position of the ghost - */ - updateGhostPosition( - position: DesignerStoreInterface['drag']['ghostPosition'], - ) { - if (!this._store.drag.active) { - return; - } + /** + * Update the ghost + * @param position - position of the ghost + */ + updateGhostPosition( + position: DesignerStoreInterface["drag"]["ghostPosition"], + ) { + if (!this._store.drag.active) { + return; + } - // update the size - this._store.drag.ghostPosition = position; - } + // update the size + this._store.drag.ghostPosition = position; + } - /** - * Reset the placeholder - */ - resetPlaceholder() { - if (!this._store.drag.active) { - return; - } - // reset the size - this._store.drag.placeholderSize = null; + /** + * Reset the placeholder + */ + resetPlaceholder() { + if (!this._store.drag.active) { + return; + } + // reset the size + this._store.drag.placeholderSize = null; - // reset the type - this._store.drag.placeholderAction = null; - } + // reset the type + this._store.drag.placeholderAction = null; + } - /** - * Update the placeholder - * @param action - action of the placeholder - * @param size - size of the element the placeholder is masking - */ - updatePlaceholder( - action: NonNullable< - DesignerStoreInterface['drag']['placeholderAction'] - >, - size: NonNullable, - ) { - if (!this._store.drag.active) { - return; - } + /** + * Update the placeholder + * @param action - action of the placeholder + * @param size - size of the element the placeholder is masking + */ + updatePlaceholder( + action: NonNullable< + DesignerStoreInterface["drag"]["placeholderAction"] + >, + size: NonNullable, + ) { + if (!this._store.drag.active) { + return; + } - // update the action - this._store.drag.placeholderAction = action; + // update the action + this._store.drag.placeholderAction = action; - // update the size for the placeholder - this._store.drag.placeholderSize = size; - } + // update the size for the placeholder + this._store.drag.placeholderSize = size; + } } diff --git a/packages/client/src/stores/designer/designer.utility.ts b/packages/client/src/stores/designer/designer.utility.ts index 703c21ad27..9edcfa8cdd 100644 --- a/packages/client/src/stores/designer/designer.utility.ts +++ b/packages/client/src/stores/designer/designer.utility.ts @@ -9,29 +9,29 @@ * @returns the relative size of the element */ export const getRelativeSize = ( - element: Element, - parent: Element, + element: Element, + parent: Element, ): { - top: number; - left: number; - height: number; - width: number; + top: number; + left: number; + height: number; + width: number; } => { - const elementBoundingClientRect = element.getBoundingClientRect(); - const parentBloundingClientRect = parent.getBoundingClientRect(); - - return { - top: - elementBoundingClientRect.top - - parentBloundingClientRect.top + - parent.scrollTop, - left: - elementBoundingClientRect.left - - parentBloundingClientRect.left + - parent.scrollLeft, - height: elementBoundingClientRect.height, - width: elementBoundingClientRect.width, - }; + const elementBoundingClientRect = element.getBoundingClientRect(); + const parentBloundingClientRect = parent.getBoundingClientRect(); + + return { + top: + elementBoundingClientRect.top - + parentBloundingClientRect.top + + parent.scrollTop, + left: + elementBoundingClientRect.left - + parentBloundingClientRect.left + + parent.scrollLeft, + height: elementBoundingClientRect.height, + width: elementBoundingClientRect.width, + }; }; /** Widget **/ @@ -43,8 +43,8 @@ export const getRelativeSize = ( * @returns the element of the block if found */ export const getBlockElement = (id: string): Element | null => { - // get the block - return document.querySelector(`[data-block="${id}"]`); + // get the block + return document.querySelector(`[data-block="${id}"]`); }; /** @@ -55,12 +55,12 @@ export const getBlockElement = (id: string): Element | null => { * @returns id of the nearest block if found */ export const getNearestBlock = (element: Element | null): string => { - const blockElement = getNearestBlockElement(element); - if (!blockElement) { - return ''; - } + const blockElement = getNearestBlockElement(element); + if (!blockElement) { + return ""; + } - return blockElement.getAttribute('data-block') as string; + return blockElement.getAttribute("data-block") as string; }; /** @@ -71,27 +71,27 @@ export const getNearestBlock = (element: Element | null): string => { * @returns element of the nearest block if found */ export const getNearestBlockElement = ( - element: Element | null, + element: Element | null, ): Element | null => { - // there is no element or we have reached the top - if (!element) { - return null; - } + // there is no element or we have reached the top + if (!element) { + return null; + } - // get the block's id - const id = element.getAttribute('data-block'); + // get the block's id + const id = element.getAttribute("data-block"); - // we have reached the root can't go up more - if (id === 'root') { - return null; - } + // we have reached the root can't go up more + if (id === "root") { + return null; + } - // found the id - if (id) { - return element; - } + // found the id + if (id) { + return element; + } - return getNearestBlockElement(element.parentElement); + return getNearestBlockElement(element.parentElement); }; /** Slot **/ @@ -104,36 +104,36 @@ export const getNearestBlockElement = ( * @returns the element of the slot if found */ export const getSlotElement = (id: string, slot: string): Element | null => { - const blockElement = getBlockElement(id); + const blockElement = getBlockElement(id); - const queue = [blockElement]; - while (queue.length) { - const currentElement = queue.shift(); + const queue = [blockElement]; + while (queue.length) { + const currentElement = queue.shift(); - if (!currentElement) { - continue; - } + if (!currentElement) { + continue; + } - const currentSlot = currentElement.getAttribute('data-slot'); - if (currentSlot === slot) { - return null; - } + const currentSlot = currentElement.getAttribute("data-slot"); + if (currentSlot === slot) { + return null; + } - // look at the children that are not blocks to find the slot - let childElement = currentElement.firstElementChild; - while (childElement) { - // get the block's id - const id = childElement.getAttribute('data-block'); + // look at the children that are not blocks to find the slot + let childElement = currentElement.firstElementChild; + while (childElement) { + // get the block's id + const id = childElement.getAttribute("data-block"); - if (!id) { - queue.push(childElement); - } + if (!id) { + queue.push(childElement); + } - childElement = childElement.nextElementSibling; - } - } + childElement = childElement.nextElementSibling; + } + } - return null; + return null; }; /** @@ -144,12 +144,12 @@ export const getSlotElement = (id: string, slot: string): Element | null => { * @returns element of the nearest slot if found */ export const getNearestSlot = (element: Element | null): string | null => { - const slotElement = getNearestSlotElement(element); - if (!slotElement) { - return null; - } + const slotElement = getNearestSlotElement(element); + if (!slotElement) { + return null; + } - return slotElement.getAttribute('data-slot') as string; + return slotElement.getAttribute("data-slot") as string; }; /** @@ -160,24 +160,24 @@ export const getNearestSlot = (element: Element | null): string | null => { * @returns element of the nearest slot if found */ export const getNearestSlotElement = ( - element: Element | null, + element: Element | null, ): Element | null => { - // there is no element or we have reached the top - if (!element) { - return null; - } - - // get the block's id - const id = element.getAttribute('data-block'); - if (id) { - return null; - } - - // get slot if possible - const slot = element.getAttribute('data-slot'); - if (slot) { - return element; - } - - return getNearestSlotElement(element.parentElement); + // there is no element or we have reached the top + if (!element) { + return null; + } + + // get the block's id + const id = element.getAttribute("data-block"); + if (id) { + return null; + } + + // get slot if possible + const slot = element.getAttribute("data-slot"); + if (slot) { + return element; + } + + return getNearestSlotElement(element.parentElement); }; diff --git a/packages/client/src/stores/designer/index.ts b/packages/client/src/stores/designer/index.ts index 48c2836bd4..9982d4ad41 100644 --- a/packages/client/src/stores/designer/index.ts +++ b/packages/client/src/stores/designer/index.ts @@ -1,2 +1,2 @@ -export * from './designer.utility'; -export * from './designer.store'; +export * from "./designer.store"; +export * from "./designer.utility"; diff --git a/packages/client/src/stores/index.ts b/packages/client/src/stores/index.ts index f247d4ccb8..9627ebc4f8 100644 --- a/packages/client/src/stores/index.ts +++ b/packages/client/src/stores/index.ts @@ -1,6 +1,6 @@ -export * from './config'; -export * from './designer'; -export * from './monolith'; -export * from './root'; -export * from './page'; -export * from './workspace'; +export * from "./config"; +export * from "./designer"; +export * from "./monolith"; +export * from "./page"; +export * from "./root"; +export * from "./workspace"; diff --git a/packages/client/src/stores/monolith/index.ts b/packages/client/src/stores/monolith/index.ts index dcce87ba9a..ef64ed72f1 100644 --- a/packages/client/src/stores/monolith/index.ts +++ b/packages/client/src/stores/monolith/index.ts @@ -1 +1 @@ -export { MonolithStore } from './monolith.store'; +export { MonolithStore } from "./monolith.store"; diff --git a/packages/client/src/stores/monolith/monolith.store.ts b/packages/client/src/stores/monolith/monolith.store.ts index 2a7f7d3ff8..7185819863 100644 --- a/packages/client/src/stores/monolith/monolith.store.ts +++ b/packages/client/src/stores/monolith/monolith.store.ts @@ -1,10 +1,8 @@ -import axios from 'axios'; -import { makeAutoObservable } from 'mobx'; - -import { Env } from '@semoss/sdk/react'; - -import { Role } from '@/types'; -import { RootStore } from '@/stores'; +import axios from "axios"; +import { makeAutoObservable } from "mobx"; +import { Env } from "@semoss/sdk/react"; +import type { RootStore } from "@/stores"; +import type { Role } from "@/types"; /** * Store that manages instances of the insights and handles applicaiton level querying @@ -14,3030 +12,3028 @@ import { RootStore } from '@/stores'; * @deprecated Will be removed in future release, use SDK instead */ export class MonolithStore { - private _root: RootStore; - - constructor(root: RootStore) { - // register the root - this._root = root; - - // make it observable - makeAutoObservable(this); - } - - // ********************************************************* - // Actions - // ********************************************************* - /** - * Get the config - */ - async config() { - // get the response - const response = await axios - .get<{ - logins: { [key: string]: unknown }; - /** - * List of available providers (logins) that are available - */ - availableProviders: { - provider: string; - name: string; - isOauth: boolean; - }[]; - [key: string]: unknown; - }>(`${Env.MODULE}/api/config`) - .catch((error) => { - throw Error(error); - }); - - // there was an error, no response - if (!response) { - throw Error('No Config Response'); - } - - // save the config data - return response.data; - } - - /** - * Run a pixel string - * - * @param insightID - insightID to execute the pixel against - * @param pixel - pixel to execute - */ - async run(insightID: string, pixel: string) { - // build the expression - let postData = ''; - - postData += 'expression=' + encodeURIComponent(pixel); - if (insightID) { - postData += '&insightId=' + encodeURIComponent(insightID); - } - - const response = await axios - .post<{ - insightID: string; - pixelReturn: { - isMeta: boolean; - operationType: string[]; - additionalOutput: { output: string }[]; - output: O[number]; - pixelExpression: string; - pixelId: string; - }[]; - }>(`${Env.MODULE}/api/engine/runPixel`, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }) - .catch((error) => { - throw Error(error); - }); - - // there was no response, that is an error - if (!response) { - throw Error('No Pixel Response'); - } - - // collect the errors - const errors: string[] = []; - for (const p of response.data.pixelReturn) { - const { output, operationType } = p; - - if (operationType.indexOf('ERROR') > -1) { - errors.push(output as string); - } - } - - return { - errors: errors, - insightId: response.data.insightID, - pixelReturn: response.data.pixelReturn, - }; - } - - /** - * Run a pixel off of the query insight - * - * @param pixel - pixel to execute - */ - //TODO: switch to extend unknown - async runQuery(pixel: string, insightId?: string) { - const { configStore } = this._root; - - return this.run(insightId ?? configStore.store.insightID, pixel); - } - - /** - * Download a file by using a unique key - * - * @param insightID - insightID to download the file - * @param fileKey - id for the file to download - */ - async download(insightID: string, fileKey: string) { - return new Promise((resolve) => { - // create the download url - const url = `${ - Env.MODULE - }/api/engine/downloadFile?insightId=${insightID}&fileKey=${encodeURIComponent( - fileKey, - )}`; - - // fake clicking a link - const link: HTMLAnchorElement = document.createElement('a'); - - link.href = url; - link.target = '_blank'; - document.body.appendChild(link); - link.click(); - - document.body.removeChild(link); - - // resolve the promise - resolve(); - }); - } - - /** - * Run a download a file off of the query insight - * - * @param fileKey - id for the file to download - */ - async downloadQuery(fileKey: string) { - const { configStore } = this._root; - - return this.download(configStore.store.insightID, fileKey); - } - - /** - * Allow the user to login - * - * @param username - username to login with - * @param password - password to login with - * @returns true if successful - */ - async login(username: string, password: string): Promise { - const postData = `username=${encodeURIComponent( - username, - )}&password=${encodeURIComponent(password)}&disableRedirect=true`; - - try { - const response = await axios.post( - `${Env.MODULE}/api/auth/login`, - postData, - { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - validateStatus: () => true, - }, - ); - - if (response?.data?.errorMessage) { - throw new Error(response.data.errorMessage); - } - - return true; - } catch (error) { - throw new Error(error.message); - } - } - - /** - * Allow the user to login with lin otp - * - * @param username - username to login with - * @param password - password to login with - * @returns true if successful - */ - async loginOTP( - username: string, - password: string, - ): Promise<'success' | 'change-password'> { - const postData = `username=${encodeURIComponent( - username, - )}&pin=${encodeURIComponent(password)}&disableRedirect=true`; - - // track the status - let status: 'success' | 'change-password' = 'success'; - - await axios - .post(`${Env.MODULE}/api/auth/loginLinOTP`, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }) - .catch((error) => { - if ( - error.response && - error.response.status === 401 && - error.response.data && - error.response.data.requirePwdChange - ) { - status = 'change-password'; - return; - } - - // throw the message - throw Error(error); - }); - - return status; - } - - /** - * Confirm the OTP from LinOTP - * - * @param otp - otp to login with - * @returns true if successful - */ - async confirmOTP(otp: string): Promise { - const postData = `otp=${encodeURIComponent(otp)}&disableRedirect=true`; - - await axios - .post(`${Env.MODULE}/api/auth/loginLinOTP`, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }) - .catch((error) => { - // throw the message - throw Error(error.response.data.errorMessage); - }); - - return true; - } - - /** - * Allow the user to login with lin otp - * - * @param username - username to login with - * @param password - password to login with - * @returns true if successful - */ - async loginLDAP( - username: string, - password: string, - ): Promise<'success' | 'change-password'> { - const postData = `username=${encodeURIComponent( - username, - )}&pin=${encodeURIComponent(password)}&disableRedirect=true`; - - // track the status - let status: 'success' | 'change-password' = 'success'; - - await axios - .post(`${Env.MODULE}/api/auth/loginLDAP`, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }) - .catch((error) => { - if ( - error.response && - error.response.status === 401 && - error.response.data && - error.response.data.requirePwdChange - ) { - status = 'change-password'; - return; - } - - // throw the message - throw Error(error); - }); - - return status; - } - - /** - * @name createUser - * @desc this call will run createUser endpoint - * @param name, name of new user - * @param username, username of new user - * @param email, email of new user - * @param password, password of new user - * @param phone, phone of new user - * @param phoneextension, phoneextension of new user - * @param countrycode, countrycode of new user - * @returns $http promise - */ - async registerUser( - name: string, - username: string, - email: string, - password: string, - phone: string, - phoneextension: string, - countrycode: string, - ) { - const create: string = - 'name=' + - encodeURIComponent(name) + - '&username=' + - encodeURIComponent(username) + - '&email=' + - encodeURIComponent(email) + - '&password=' + - encodeURIComponent(password) + - '&phone=' + - encodeURIComponent(phone) + - '&phoneextension=' + - encodeURIComponent(phoneextension) + - '&countrycode=' + - encodeURIComponent(countrycode); - try { - const response = await axios.post( - `${Env.MODULE}/api/auth/createUser`, - create, - { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - validateStatus: () => true, - }, - ); - - if (response.data?.errorMessage) { - throw new Error(response.data.errorMessage); - } - return response.data; - } catch (error) { - throw new Error(error.message); - } - } - - /** * - * @returns true if successful - */ - async logout(): Promise { - await axios - .get(`${Env.MODULE}/api/auth/logout/all`, { - validateStatus: function (status) { - return true; - }, - }) - .catch((err) => { - throw Error(err); - }); - - return true; - } - - /** - * Allow the user to login using oauth - * - * @param provider - provider to login with - * @returns true if successful - */ - async oauth(provider: string): Promise { - // check if the user is logged in - const response = await axios - .get<{ name: string }>( - `${Env.MODULE}/api/auth/userinfo/${provider}`, - ) - .catch((error) => { - throw Error(error); - }); - - //check if they are already logged in - if (response.data && response.data.name) { - return true; - } - - return new Promise((resolve) => { - const url = `${Env.MODULE}/api/auth/login/${provider}`; - const popUpWindow = window.top.open( - url, - '_blank', - 'height=600,width=400,top=300,left=' + 600, - ); - - // setup an interval to see if the popup window is closed or successful - const interval = setInterval(async () => { - try { - if ( - !popUpWindow || - popUpWindow.closed || - popUpWindow.closed === undefined - ) { - clearInterval(interval); - } else if ( - popUpWindow.document.location.href.indexOf( - `${window.location.host}`, - ) > -1 - ) { - clearInterval(interval); - - // close it - popUpWindow.close(); - - // try to get the info again - const response = await this.oauth(provider); - - // close it - resolve(response); - } - } catch (err) { - // do nothing - // this is to work around the blocked frame error that comes up - } - }, 1000); - }); - } - - /** - * @name getLoginProperties - * @returns - */ - async getLoginProperties() { - const url = `${Env.MODULE}/api/auth/loginProperties`; - - const response = await axios.get(url).catch((error) => { - throw Error(error); - }); - - return response.data; - } - - async modifyLoginProperties(provider, properties) { - const url = `${Env.MODULE}/api/auth/modifyLoginProperties/` + provider; - let postData = ''; - - postData += 'modifications=' + JSON.stringify(properties); - - const response = await axios - .post(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }) - .catch((error) => { - throw Error(error); - }); - - return response.data; - } - - /** - * @name isAdminUser - * @description Determines whether user is admin or - * @returns boolean - */ - async isAdminUser() { - const url = `${Env.MODULE}/api/auth/admin/user/isAdminUser`; - - const response = await axios.get(url).catch((error) => { - throw Error(error); - }); - - if (!response) { - throw Error('No Response to isAdminUSer'); - } - - return response.data; - } - - /** - * @name createAdminTheme - * @param data the data that will be sent to the BE to define a theme - * @desc this call will create a new theme defined by the admin - */ - async createAdminTheme(data: { - name: string; - json: any; - isActive: boolean; - }) { - const url = `${Env.MODULE}/api/themes/createAdminTheme`; - - let postData = ''; - - postData += 'name=' + encodeURIComponent(data.name); - postData += '&json=' + encodeURIComponent(JSON.stringify(data.json)); - postData += '&isActive=' + encodeURIComponent(data.isActive); - - const response = await axios.post(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response.data; - - // Sets an Active theme with material ui properties - // const map = JSON.parse(data['theme']['THEME_MAP']); - // const material_map = { - // ...map, - // materialTheme: lightTheme, - // }; - - // console.log(JSON.stringify(material_map)); - // monolithStore.createAdminTheme({ - // name: 'SEMOSS-TEST-DARK', - // isActive: true, - // json: material_map, - // }); - } - - // ---------------------------------------------------------------------- - // Engine - // ---------------------------------------------------------------------- - /** - * @name getEngines - * @param admin - is admin user - * @returns AppInterface[] - */ - async getEngines( - admin: boolean, - search: string, - engineType: string, - offset?: number, - limit?: number, - ) { - let url = `${Env.MODULE}/api/auth/`; - - if (admin) { - url += 'admin/'; - } - - url += 'engine/getEngines'; - - const params = {}; - - params['engineTypes'] = engineType; - search && (params['filterWord'] = search); - - offset && (params['offset'] = offset); - - limit && (params['limit'] = limit); - - // get the response - const response = await axios - .get(url, { - params: params, - }) - .catch((error) => { - throw Error(error); - }); - - // there was no response, that is an error - if (!response) { - throw Error('No Response to get Apps'); - } - - return response.data; - } - - /** - * @name getUserEnginePermission - * @desc Get a user's role for the engine - * @param id - id of engine (db, storage, model) - */ - async getUserEnginePermission(id: string) { - const response = await axios - .get<{ permission: Role }>( - `${Env.MODULE}/api/auth/engine/getUserEnginePermission`, - { - params: { engineId: id }, - }, - ) - .catch((error) => { - throw Error(error); - }); - - // there was no response, that is an error - if (!response) { - throw Error('No roles for the app user'); - } - - return response.data; - } - - /** - * @name getEngineUsers - * @param admin - * @param appId - * @returns MemberInterface[] - */ - async getEngineUsers( - admin: boolean, - databaseId: string, - user: string, - permission: string, - offset?: number, - limit?: number, - projectId?, - ) { - let url = `${Env.MODULE}/api/auth/`; - - if (admin) { - url += 'admin/'; - } - - url += 'engine/getEngineUsers'; - - // get the response - const response = await axios - .get<{ - members: { - id: string; - name: string; - permission: string; - }[]; - totalMembers: number; - }>(url, { - params: { - engineId: databaseId, - searchTerm: user, - permission: permission, - offset: offset, - limit: limit, - }, - }) - .catch((error) => { - throw Error(error); - }); - - // there was no response, that is an error - if (!response) { - throw Error('No Response to get users associated with app'); - } - - console.warn( - 'Project Id is not a necessary param, optional due to the similarity of usage for getInsightUsers', - projectId, - ); - - return response.data; - } - - /** - * @name getEngineUsersNoCredentials - * @param admin - * @param engineId - * @param limit - * @param offSet - * @param searchTerm - * @returns - */ - async getEngineUsersNoCredentials( - admin: boolean, - engineId: string, - limit: number, - offset: number, - searchTerm: string, - ) { - let url = `${Env.MODULE}/api/auth/`; - - // Currently no admin ENDPOINT; - if (admin) { - url += 'admin/'; - } - - url += 'engine/getEngineUsersNoCredentials'; - - // get the response - const response = await axios - .get< - { - id: string; - email: string; - name: string; - type: string; - username: string; - }[] - >(url, { - params: { - engineId: engineId, - limit: limit, - offset: offset, - searchTerm: searchTerm, - }, - }) - .catch((error) => { - throw Error(error); - }); - - // there was no response, that is an error - if (!response) { - throw Error('No Response to get non credentialed users'); - } - - return response; - } - - /** - * @name addEngineUserPermissions - * @param admin - * @param appId - * @param users - * @returns - */ - async addEngineUserPermissions( - admin: boolean, - appId: string, - users: any[], - ) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - // No Admin endpoint currently - if (admin) { - url += 'admin/'; - } - - url += 'engine/addEngineUserPermissions'; - - postData += 'engineId=' + encodeURIComponent(appId); - postData += - '&userpermissions=' + encodeURIComponent(JSON.stringify(users)); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - - // figure out whether we want to do .catch here - } - - /** - * @name editEngineUserPermissions - * @param admin - * @param appId - * @param users - * @returns - */ - async editEngineUserPermissions( - admin: boolean, - appId: string, - users: any[], - ) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - - url += 'engine/editEngineUserPermissions'; - - postData += 'engineId=' + encodeURIComponent(appId); - postData += - '&userpermissions=' + encodeURIComponent(JSON.stringify(users)); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - - // figure out whether we want to do .catch here - } - - /** - * @name removeEngineUserPermissions - * @param admin - * @param appId - * @param users - * @returns - */ - async removeEngineUserPermissions( - admin: boolean, - appId: string, - users: any[], - ) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - - url += 'engine/removeEngineUserPermissions'; - - postData += 'engineId=' + encodeURIComponent(appId); - postData += '&ids=' + encodeURIComponent(JSON.stringify(users)); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - /** - * @name setEngineGlobal - * @param admin - * @param appId - * @param global - */ - async setEngineGlobal(admin: boolean, engineId: string, global: boolean) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - - // change to database - url += 'engine/setEngineGlobal'; - - postData += 'engineId=' + encodeURIComponent(engineId); - postData += '&public=' + encodeURIComponent(global); - - const response = await axios - .post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }) - .catch((error) => { - throw Error(error); - }); - - return response; - } - - /** - * @name setEngineVisiblity - * @param admin - * @param appId - * @param visible - */ - async setEngineVisiblity( - admin: boolean, - engineId: string, - visible: boolean, - ) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - - url += 'engine/setEngineDiscoverable'; - - postData += 'engineId=' + encodeURIComponent(engineId); - postData += '&discoverable=' + encodeURIComponent(visible); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - async setEngineFavorite(engineId: string, favorite: boolean) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - url += 'engine/setEngineFavorite'; - postData += 'engineId=' + encodeURIComponent(engineId); - postData += '&isFavorite=' + encodeURIComponent(favorite); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - /** - * @name setProjectFavorite - * @param projectId - * @param favorite - */ - async setProjectFavorite(projectId: string, favorite: boolean) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - url += 'project/setProjectFavorite'; - postData += 'projectId=' + encodeURIComponent(projectId); - postData += '&isFavorite=' + encodeURIComponent(favorite); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - /** - * @name approveEngineUserAccessRequest - * @param admin - * @param engineId - * @param requests - * @returns - */ - async approveEngineUserAccessRequest( - admin: boolean, - engineId: string, - requests: any[], - ) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - url += 'engine/approveEngineUserAccessRequest'; - - postData += 'engineId=' + encodeURIComponent(engineId); - postData += '&requests=' + encodeURIComponent(JSON.stringify(requests)); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - /** - * @name denyEngineUserAccessRequest - * @param admin - * @param appId - * @param userIds - * @returns - */ - async denyEngineUserAccessRequest( - admin: boolean, - engineId: string, - userIds: string[], - ) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - url += 'engine/denyEngineUserAccessRequest'; - - postData += 'engineId=' + encodeURIComponent(engineId); - postData += - '&requestIds=' + encodeURIComponent(JSON.stringify(userIds)); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - return response; - } - - // ---------------------------------------------------------------------- - // Database Level - // ---------------------------------------------------------------------- - /** - * @name getDatabases - * @param admin - is admin user - * @returns AppInterface[] - */ - async getDatabases(admin: boolean) { - let url = `${Env.MODULE}/api/auth/`; - - if (admin) { - url += 'admin/'; - } - - url += 'database/getDatabases'; - // get the response - const response = await axios - .get< - { - app_global: boolean; - app_id: string; - app_name: string; - app_permission: string; - app_visibility: boolean; - }[] - >(url) - .catch((error) => { - throw Error(error); - }); - - // there was no response, that is an error - if (!response) { - throw Error('No Response to get Apps'); - } - - return response.data; - } - - // ----- Users Start ----- - - // ----- Users End ----- - - // ---------------------------------------------------------------------- - // Teams Start - // ---------------------------------------------------------------------- - - /** - * @name getTeams - * @param admin - is admin user - */ - async getTeams(admin: boolean) { - let url = `${Env.MODULE}/api/auth/`; - - if (admin) { - url += 'admin/'; - } - - url += 'group/getGroups'; - // get the response - const response = await axios.get(url).catch((error) => { - throw Error(error); - }); - - // there was no response, that is an error - if (!response) { - throw Error('No Response to get teams'); - } - - return response.data; - } - - /** - * @name addTeam - * @param groupId - * @param description - * @param type - * @returns - */ - async addTeam(groupId: string, description: string, type?: string) { - let url = `${Env.MODULE}/api/auth/admin/`, - postData = ''; - - url += 'group/addGroup'; - - postData += 'groupId=' + encodeURIComponent(groupId); - postData += '&description=' + encodeURIComponent(description); - if (type) { - postData += '&type=' + encodeURIComponent(type); - } - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - /** - * @name editTeam - * @param groupId - * @param description - * @param type - * @returns - */ - async editTeam( - groupId: string, - description: string, - type?: string, - previousTeamName?: string, - previousType?: string, - ) { - let url = `${Env.MODULE}/api/auth/admin/`, - postData = ''; - - url += 'group/editGroupDetails'; - - postData += 'groupId=' + encodeURIComponent(previousTeamName); - postData += '&newGroupId=' + encodeURIComponent(groupId); - postData += '&newDescription=' + encodeURIComponent(description); - postData += '&type=' + encodeURIComponent(previousType); - postData += '&newType=' + encodeURIComponent(type); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - /** - * @name deleteTeam - * @param groupId - * @param description - * @param type - * @returns - */ - async deleteTeam(groupid: string, type?: string) { - let url = `${Env.MODULE}/api/auth/admin/`, - postData = ''; - - url += 'group/deleteGroup'; - - postData += 'groupId=' + encodeURIComponent(groupid); - - if (type) { - postData += '&type=' + encodeURIComponent(type); - } - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - /** - * @name getTeamUsers - * @param groupId - * @param limit - * @param offSet - * @param searchTerm - */ - async getTeamUsers( - groupId: string, - limit: number, - offset: number, - searchTerm: string, - ) { - let url = `${Env.MODULE}/api/auth/admin/`; - - url += 'group/getGroupMembers'; - - const params = {}; - - groupId && (params['groupId'] = groupId); - limit && (params['limit'] = limit); - offset && (params['offset'] = offset); - searchTerm && (params['searchTerm'] = searchTerm); - - const response = await axios - .get(url, { - params: params, - }) - .catch((error) => { - throw Error(error); - }); - - // there was no response, that is an error - if (!response) { - throw Error('No Response to get group members'); - } - - return response.data; - } - - /** - * @name getTeamUsersCount - * @param groupId - */ - async getTeamUsersCount(groupId: string) { - let url = `${Env.MODULE}/api/auth/admin/`; - - url += 'group/getNumMembersInGroup'; - - const params = {}; - - groupId && (params['groupId'] = groupId); - const response = await axios - .get(url, { - params: params, - }) - .catch((error) => { - throw Error(error); - }); - - // there was no response, that is an error - if (!response) { - throw Error('No Response to get group member count'); - } - - return response.data; - } - - /** - * @name getNonTeamUsers - * @param groupId - */ - async getNonTeamUsers( - groupId: string, - limit: number, - offset: number, - searchTerm: string, - ) { - let url = `${Env.MODULE}/api/auth/admin/`; - - url += 'group/getNonGroupMembers'; - - const params = {}; - - groupId && (params['groupId'] = groupId); - limit && (params['limit'] = limit); - offset && (params['offset'] = offset); - searchTerm && (params['searchTerm'] = searchTerm); - - const response = await axios - .get(url, { - params: params, - }) - .catch((error) => { - throw Error(error); - }); - - // there was no response, that is an error - if (!response) { - throw Error('No Response to get non group members'); - } - - return response.data; - } - - /** - * @name addTeamUser - * @param groupId - * @param type - * @param userId - * @param admin - * @param endDate - * @returns - */ - async addTeamUser( - groupId: string, - type: string, - userId: string, - admin: boolean, - endDate?: string, - ) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - - url += 'group/addGroupMember'; - - postData += 'groupId=' + encodeURIComponent(groupId); - postData += '&type=' + encodeURIComponent(type); - postData += '&userId=' + encodeURIComponent(userId); - - if (endDate) { - postData += '&endDate=' + encodeURIComponent(endDate); - } - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - /** - * @name deleteTeamUser - * @param groupId - * @param type - * @param userId - * @returns - */ - async deleteTeamUser(user: { - groupid: string; - type: string; - userid: string; - }) { - let url = `${Env.MODULE}/api/auth/admin/`, - postData = ''; - - url += 'group/deleteGroupMember'; - - postData += 'groupId=' + encodeURIComponent(user.groupid); - postData += '&userId=' + encodeURIComponent(user.userid); - postData += '&type=' + encodeURIComponent(user.type); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - /** - * @name addProjectPermission - * @param groupId - * @param type - * @param projectId - * @param permission - * @param endDate - * @returns - */ - async addProject( - groupId: string, - projectId: string, - permission: number, - type?: string, - endDate?: string, - ) { - let url = `${Env.MODULE}/api/auth/admin/`, - postData = ''; - - url += 'group/addGroupProjectPermission'; - - postData += 'groupId=' + encodeURIComponent(groupId); - postData += '&projectId=' + encodeURIComponent(projectId); - postData += '&permission=' + encodeURIComponent(permission); - - if (endDate) { - postData += '&endDate=' + encodeURIComponent(endDate); - } - - if (type) { - postData += '&type=' + encodeURIComponent(type); - } - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - /** - * @name editProjectPermission - * @param groupId - * @param type - * @param projectId - * @param permission - * @param endDate - * @returns - */ - async editProjectPermisison( - groupId: string, - groupType: string, - project: { - projectid: string; - permission: number; - project_type?: string; - endDate?: string; - }, - ) { - let url = `${Env.MODULE}/api/auth/admin/`, - postData = ''; - - url += 'group/editGroupProjectPermission'; - - postData += 'groupId=' + encodeURIComponent(groupId); - postData += '&projectId=' + encodeURIComponent(project.projectid); - postData += '&permission=' + encodeURIComponent(project.permission); - - if (groupType) { - postData += '&type=' + encodeURIComponent(groupType); - } - if (project.endDate) { - postData += '&endDate=' + encodeURIComponent(project.endDate); - } - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - /** - * @name deleteProjectPermission - * @param groupId - * @param type - * @param projectId - * @returns - */ - async deleteProjectPermission( - groupId, - groupType: string, - project: { - projectid: string; - group_type?: string; - }, - ) { - let url = `${Env.MODULE}/api/auth/admin/`, - postData = ''; - - url += 'group/removeGroupProjectPermission'; - - postData += 'groupId=' + encodeURIComponent(groupId); - postData += '&projectId=' + encodeURIComponent(project.projectid); - if (groupType) { - postData += '&type=' + encodeURIComponent(groupType); - } - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - /** - * @name getTeamProjects - * @param groupId - * @param limit - * @param offSet - * @param searchTerm - */ - async getTeamProjects( - groupId: string, - groupType: string, - limit: number, - offset: number, - searchTerm: string, - onlyApps: boolean, - type?: string, - ) { - let url = `${Env.MODULE}/api/auth/admin/`; - - url += 'group/getProjectsForGroup'; - - const params = {}; - - groupId && (params['groupId'] = groupId); - groupType && (params['groupType'] = groupType); - limit && (params['limit'] = limit); - offset && (params['offset'] = offset); - searchTerm && (params['searchTerm'] = searchTerm); - - // searchTerm - // ? (params['searchTerm'] = searchTerm) - // : (params['searchTerm'] = ''); - onlyApps && (params['onlApps'] = onlyApps); - type ? (params['type'] = type) : (params['type'] = null); - - const response = await axios - .get(url, { - params: params, - }) - .catch((error) => { - throw Error(error); - }); - - // there was no response, that is an error - if (!response) { - throw Error('No Response to get group members'); - } - - return response.data; - } - - /** - * @name getUnassignedTeamProjects - * @param groupId - * @param limit - * @param offSet - * @param searchTerm - */ - async getUnassignedTeamProjects( - groupId: string, - groupType: string, - limit: number, - offset: number, - searchTerm: string, - ) { - let url = `${Env.MODULE}/api/auth/admin/`; - - url += 'group/getAvailableProjectsForGroup'; - - const params = {}; - - groupId && (params['groupId'] = groupId); - groupType && (params['groupType'] = groupType); - limit && (params['limit'] = limit); - offset && (params['offset'] = offset); - searchTerm && (params['searchTerm'] = searchTerm); - - const response = await axios - .get(url, { - params: params, - }) - .catch((error) => { - throw Error(error); - }); - - // there was no response, that is an error - if (!response) { - throw Error('No Response to get group members'); - } - - return response.data; - } - - /** - * @name addEnginePermission - * @param groupId - * @param type - * @param projectId - * @param permission - * @param endDate - * @returns - */ - async addEnginePermission( - groupId: string, - engineId: string, - permission: number, - type?: string, - endDate?: string, - ) { - let url = `${Env.MODULE}/api/auth/admin/`, - postData = ''; - - url += 'group/addGroupEnginePermission'; - - postData += 'groupId=' + encodeURIComponent(groupId); - postData += '&engineId=' + encodeURIComponent(engineId); - postData += '&permission=' + encodeURIComponent(permission); - - if (type) { - postData += '&type=' + encodeURIComponent(type); - } - - if (endDate) { - postData += '&endDate=' + encodeURIComponent(endDate); - } - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - /** - * @name editEnginePermission - * @param groupId - * @param type - * @param projectId - * @param permission - * @param endDate - * @returns - */ - async editEnginePermission( - groupId: string, - engine: { - engineid: string; - permission: string; - type?: string; - endDate?: string; - }, - ) { - let url = `${Env.MODULE}/api/auth/admin/`, - postData = ''; - - url += 'group/editGroupEnginePermission'; - - postData += 'groupId=' + encodeURIComponent(groupId); - postData += '&engineId=' + encodeURIComponent(engine.engineid); - postData += '&permission=' + encodeURIComponent(engine.permission); - - if (engine.type) { - postData += '&type=' + encodeURIComponent(engine.type); - } - - if (engine.endDate) { - postData += '&endDate=' + encodeURIComponent(engine.endDate); - } - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - /** - * @name deleteEnginePermission - * @param groupId - * @param type - * @param projectId - * @returns - */ - async deleteEnginePermission( - groupId: string, - groupType: string, - engine: { - engineid: string; - type?: string; - }, - ) { - let url = `${Env.MODULE}/api/auth/admin/`, - postData = ''; - - url += 'group/removeGroupEnginePermission'; - - postData += 'groupId=' + encodeURIComponent(groupId); - postData += '&engineId=' + encodeURIComponent(engine.engineid); - - if (groupType) { - postData += '&type=' + encodeURIComponent(groupType); - } - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - /** - * @name getTeamEngines - * @param groupId - * @param limit - * @param offSet - * @param searchTerm - */ - async getTeamEngines( - groupId: string, - groupType: string, - limit: number, - offset: number, - searchTerm: string, - ) { - let url = `${Env.MODULE}/api/auth/admin/`; - - url += 'group/getEnginesForGroup'; - - const params = {}; - - groupId && (params['groupId'] = groupId); - groupType && (params['groupType'] = groupType); - limit && (params['limit'] = limit); - offset && (params['offset'] = offset); - searchTerm && (params['searchTerm'] = searchTerm); - - const response = await axios - .get(url, { - params: params, - }) - .catch((error) => { - throw Error(error); - }); - - // there was no response, that is an error - if (!response) { - throw Error('No Response to get group members'); - } - - return response.data; - } - - /** - * @name getUnassignedTeamEngines - * @param groupId - * @param limit - * @param offSet - * @param searchTerm - */ - async getUnassignedTeamEngines( - groupId: string, - groupType: string, - limit: number, - offset: number, - searchTerm: string, - ) { - let url = `${Env.MODULE}/api/auth/admin/`; - - url += 'group/getAvailableEnginesForGroup'; - - const params = {}; - - groupId && (params['groupId'] = groupId); - groupType && (params['groupType'] = groupType); - limit && (params['limit'] = limit); - offset && (params['offset'] = offset); - searchTerm && (params['searchTerm'] = searchTerm); - - const response = await axios - .get(url, { - params: params, - }) - .catch((error) => { - throw Error(error); - }); - - // there was no response, that is an error - if (!response) { - throw Error('No Response to get group members'); - } - - return response.data; - } - - // ---------- Teams End ----------------- - - // ----- Properties Start ----- - - /** - * @name updateDatabaseSmmsProperties - * @param databaseId - * @param smssProps - * @returns - */ - async updateDatabaseSmssProperties(databaseId: string, smssProps: string) { - const url = `${Env.MODULE}/api/e-${databaseId}/updateSmssFile`; - - let postData = ''; - postData += 'engineId=' + encodeURIComponent(databaseId); - postData += '&smss=' + encodeURIComponent(smssProps); - - const response = await axios - .post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }) - .catch((error) => { - throw Error(error); - }); - - return response; - } - - /** - * @name setDatabaseDiscoverable - * @param admin - * @param appId - * @param discoverable - */ - async setDatabaseDiscoverable( - admin: boolean, - appId: string, - discoverable: boolean, - ) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - - // change to database - url += 'app/setAppDiscoverable'; - - postData += 'appId=' + encodeURIComponent(appId); - postData += '&discoverable=' + encodeURIComponent(discoverable); - - const response = await axios - .post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }) - .catch((error) => { - throw Error(error); - }); - - return response; - } - - // ----- Properties End ----- - - // ---------------------------------------------------------------------- - // Project Level - // ---------------------------------------------------------------------- - /** - * @name getProjects - * @param admin - is admin user - * @returns Projects retrieved from Promise - */ - async getProjects( - admin: boolean, - search?: string, - offset?: number, - limit?: number, - ) { - let url = `${Env.MODULE}/api/auth/`; - - if (admin) { - url += 'admin/'; - } - - url += 'project/getProjects'; - - const params = {}; - - search && (params['filterWord'] = search); - - offset && (params['offset'] = offset); - - limit && (params['limit'] = limit); - - const response = await axios - .get< - { - project_global: boolean; - project_id: string; - project_name: string; - project_permission: string; - project_visibility: boolean; - }[] - >(url, { - params: params, - }) - .catch((error) => { - throw Error(error); - }); - - // there was no response, that is an error - if (!response) { - throw Error('No Response to get Projects'); - } - - return response.data; - } - - /** - * @name getUserProjectPermission - * @param admin - is admin user - * @returns Projects retrieved from Promise - */ - async getUserProjectPermission( - projectId: string, - ): Promise<{ permission: Role }> { - let url = `${Env.MODULE}/api/auth/`; - - url += 'project/getUserProjectPermission'; - - try { - const response = await axios.get(url, { - params: { - projectId: projectId, - }, - }); - - // there was no response, that is an error - if (!response) { - if (response.status === 401) { - throw Error('User does not have access to this project'); - } else { - throw Error('No Response to get permission'); - } - } - - return response.data; - } catch (error) { - throw Error(error); - } - } - - // ----- Users Start ----- - - /** - * @name getProjectUsers - * @param admin - * @param projectId - * @returns MemberInterface[] - */ - async getProjectUsers( - admin: boolean, - projectId: string, - user: string, - permission: string, - offset?: number, - limit?: number, - id?: string, - ) { - let url = `${Env.MODULE}/api/auth/`; - - if (admin) { - url += 'admin/'; - } - - url += 'project/getProjectUsers'; - // get the response - const response = await axios - .get<{ - members: { - id: string; - name: string; - permission: string; - }[]; - totalMembers: number; - }>(url, { - params: { - projectId: projectId, - userId: user, - permission: permission, - offset: offset, - limit: limit, - }, - }) - .catch((error) => { - throw Error(error); - }); - - // there was no response, that is an error - if (!response) { - throw Error('No Response to get users associated with app'); - } - - return response.data; - } - - /** - * @name getProjectUsersNoCredentials - * @param admin if admin initiated the call - * @param appId the id of app - * @param limit - * @param offSet - * @param searchTerm - * @desc get the existing users and their permissions for this app - */ - async getProjectUsersNoCredentials( - admin: boolean, - appId: string, - limit: number, - offset: number, - searchTerm: string, - ) { - let url = `${Env.MODULE}/api/auth/`; - - if (admin) { - url += 'admin/'; - } - - url += 'project/getProjectUsersNoCredentials'; - - // get the response - const response = await axios - .get< - { - id: string; - email: string; - name: string; - type: string; - username: string; - }[] - >(url, { - params: { - projectId: appId, - limit: limit, - offset: offset, - searchTerm: searchTerm, - }, - }) - .catch((error) => { - throw Error(error); - }); - - // there was no response, that is an error - if (!response) { - throw Error('No Response to get non credentialed users'); - } - - return response; - } - - /** - * @name approveProjectUserAccessRequest - * @param admin - * @param appId - * @param requests - * @returns - */ - async approveProjectUserAccessRequest( - admin: boolean, - appId: string, - requests: any[], - ) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - url += 'project/approveProjectUserAccessRequest'; - - postData += 'projectId=' + encodeURIComponent(appId); - postData += '&requests=' + encodeURIComponent(JSON.stringify(requests)); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - - // figure out whether we want to do .catch here - } - - /** - * @name denyProjectUserAccessRequest - * @param admin - * @param projectId - * @param userIds - * @returns - */ - async denyProjectUserAccessRequest( - admin: boolean, - projectId: string, - userIds: string[], - ) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - url += 'project/denyProjectUserAccessRequest'; - - postData += 'projectId=' + encodeURIComponent(projectId); - postData += - '&requestids=' + encodeURIComponent(JSON.stringify(userIds)); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - return response; - - // figure out whether we want to do .catch here - } - - /** - * @name addProjectUserPermissions - * @param admin - * @param appId - * @param users - * @returns - */ - async addProjectUserPermissions( - admin: boolean, - appId: string, - users: any[], - ) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - url += 'project/addProjectUserPermissions'; - - postData += 'projectId=' + encodeURIComponent(appId); - postData += - '&userpermissions=' + encodeURIComponent(JSON.stringify(users)); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - - // figure out whether we want to do .catch here - } - - /** - * @name editProjectUserPermissions - * @param admin - * @param appId - * @param users - * @returns - */ - async editProjectUserPermissions( - admin: boolean, - appId: string, - users: any[], - ) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - url += 'project/editProjectUserPermissions'; - - postData += 'projectId=' + encodeURIComponent(appId); - postData += - '&userpermissions=' + encodeURIComponent(JSON.stringify(users)); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - - // figure out whether we want to do .catch here - } - - /** - * @name removeProjectUserPermissions - * @param admin - * @param appId - * @param users - * @returns - */ - async removeProjectUserPermissions( - admin: boolean, - appId: string, - users: any[], - ) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - url += 'project/removeProjectUserPermissions'; - - postData += 'projectId=' + encodeURIComponent(appId); - postData += '&ids=' + encodeURIComponent(JSON.stringify(users)); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - - // figure out whether we want to do .catch here - } - // ----- Users End ----- - // ----- Properties Start ----- - - /** - * @name setProjectGlobal - * @param admin - * @param appId - * @param global - */ - async setProjectGlobal(admin, appId, global: boolean) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - - url += 'project/setProjectGlobal'; - - postData += 'projectId=' + encodeURIComponent(appId); - postData += '&public=' + encodeURIComponent(global); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - /** - * @name setProjectVisiblity - * @param admin - * @param appId - * @param visible - */ - async setProjectVisiblity(admin, appId, visible) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - - url += 'project/setProjectDiscoverable'; - - postData += 'projectId=' + encodeURIComponent(appId); - postData += '&discoverable=' + encodeURIComponent(visible); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - // ----- Properties End ----- - // ----- Portal Start ----- - - /** - * @name setProjectPortal - * @param projectId - * @param hasPortal - * @param portalName - */ - async setProjectPortal( - admin: boolean, - projectId: string, - hasPortal: boolean, - portalName?: string, - ) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - // if (admin) { - // url += 'admin/'; - // } - - url += 'project/setProjectPortal'; - - postData += 'projectId=' + encodeURIComponent(projectId); - postData += '&hasPortal=' + encodeURIComponent(hasPortal); - - if (portalName) { - postData += '&projectId=' + encodeURIComponent(portalName); - } - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - // ----- Portal End ----- - - // ---------------------------------------------------------------------- - // Insight Level - // ---------------------------------------------------------------------- - - async getInsights() { - console.error('needs to be added on BE'); - } - - async getInsightUsers( - admin: boolean, - id: string, - user: string, - permission: string, - offset?: number, - limit?: number, - projectid?: string, - ) { - // /api/auth/insight/getInsightUsers? - // insightId=feb4c485-0aa8-4ff6-b355-e894dc74589a&projectId=2e2534db-fffa-4054-b9e9-dbf44183ab3b - - let url = `${Env.MODULE}/api/auth/`; - - if (admin) { - url += 'admin/'; - } - - url += 'insight/getInsightUsers'; - - if (!projectid) { - throw Error('no project id'); - } - - // get the response - const response = await axios - .get< - { - id: string; - name: string; - permission: string; - }[] - >(url, { - params: { - insightId: id, - projectId: projectid, - offset: offset, - limit: limit, - userId: user, - - // projectId: projectId, - // permission: permission, - }, - }) - .catch((error) => { - throw Error(error); - }); - - if (!response) { - throw Error('Unsuccessful attempt at retrieving Insight Users'); - } - - return response.data; - } - - /** - * @name getInsightUsersNoCredentials - * @param admin if admin initiated the call - * @param projectId the id of app - * @desc get the existing users and their permissions for this app - */ - async getInsightUsersNoCredentials( - admin: boolean, - insightId: string, - projectId: string, - ) { - let url = `${Env.MODULE}/api/auth/`; - - if (admin) { - url += 'admin/'; - } - - url += 'insight/getInsightUsersNoCredentials'; - - // get the response - const response = await axios - .get(url, { - params: { projectId: projectId, insightId: insightId }, - }) - .catch((error) => { - throw Error(error); - }); - - // there was no response, that is an error - if (!response) { - throw Error('No Response to get non credentialed users'); - } - - return response.data; - } - - // Verified Project Member actions - - /** - * @name addInsightUserPermissions - * @param admin - * @param appId - * @param users - * @returns - */ - async addInsightUserPermissions( - admin: boolean, - id: string, - users: any[], - projectId: string, - ) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - url += 'insight/addInsightUserPermissions'; - - postData += 'projectId=' + encodeURIComponent(projectId); - postData += '&insightId=' + encodeURIComponent(id); - postData += - '&userpermissions=' + encodeURIComponent(JSON.stringify(users)); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - - // figure out whether we want to do .catch here - } - - /** - * @name removeInsightUserPermissions - * @param admin - * @param appId - * @param users - * @returns - */ - async removeInsightUserPermissions( - admin: boolean, - id: string, - users: any[], - projectId, - ) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - url += 'project/removeProjectUserPermissions'; - - postData += 'projectId=' + encodeURIComponent(projectId); - postData += '&insightId=' + encodeURIComponent(id); - postData += '&ids=' + encodeURIComponent(JSON.stringify(users)); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - - // figure out whether we want to do .catch here - } - - /** - * @name editInsightUserPermissions - * @param admin - * @param appId - * @param users - * @returns - */ - async editInsightUserPermissions( - admin: boolean, - id: string, - users: any[], - projectId: string, - ) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - url += 'insight/editInsightUserPermissions'; - - postData += 'projectId=' + encodeURIComponent(projectId); - postData += '&insightId=' + encodeURIComponent(id); - postData += - '&userpermissions=' + encodeURIComponent(JSON.stringify(users)); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - - // figure out whether we want to do .catch here - } - - // Being used but need to be taken out below ------------------ - /** - * This will end up being taken out - * @param admin - * @param projectId - * @param id - * @param permission - * @returns - */ - async editProjectUserPermission( - admin: boolean, - projectId: string, - id: string, - permission: string, - ) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - - url += 'project/editProjectUserPermission'; - - postData += 'projectId=' + encodeURIComponent(projectId); - postData += '&id=' + encodeURIComponent(id); - postData += '&permission=' + encodeURIComponent(permission); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - /** - * This will end up being taken out - * @desc this call will edit access permissions for a user - * @param admin admin true or false - * @param appId id of app - * @param id id of user - * @param permission permission to give - */ - async editAppUserPermission( - admin: boolean, - appId: string, - id: string, - permission: string, - ) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - - url += 'app/editAppUserPermission'; - - postData += 'appId=' + encodeURIComponent(appId); - postData += '&id=' + encodeURIComponent(id); - postData += '&permission=' + encodeURIComponent(permission); - - const response = await axios.post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - async uploadFile( - files: File[], - insightId: string | null, - projectId?: string | null, - path?: string | null, - ) { - let param = ''; - if (insightId || projectId || path) { - if (insightId) { - if (param.length > 0) { - param += '&'; - } - param += `insightId=${insightId}`; - } - - if (projectId) { - if (param.length > 0) { - param += '&'; - } - param += `projectId=${projectId}`; - } - - if (path) { - if (param.length > 0) { - param += '&'; - } - param += `path=${path}`; - } - - param = `?${param}`; - } - - const url = `${Env.MODULE}/api/uploadFile/baseUpload${param}`, - fd: FormData = new FormData(); - - if (Array.isArray(files)) { - for (let i = 0; i < files.length; i++) { - fd.append('file', files[i]); - } - } else { - // pasted data - fd.append('file', files); - } - - const response = await axios.post< - { - fileName: string; - fileLocation: string; - }[] - >(url, fd, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response.data; - } - - async uploadImage( - files: File[], - projectId: string | null, - insightId?: string | null, - ) { - const url = `${Env.MODULE}/api/images/projectImage/upload`, - fd: FormData = new FormData(); - - if (Array.isArray(files)) { - for (let i = 0; i < files.length; i++) { - fd.append('file', files[i]); - } - } else { - // pasted data - fd.append('file', files); - } - - if (insightId) { - fd.append('insightId', insightId); - } else { - const { configStore } = this._root; - fd.append('insightId', configStore.store.insightID); - } - - if (projectId) { - fd.append('projectId', projectId); - } - - const response = await axios.post< - { - app_id: string; - app_name: string; - message: string; - }[] - >(url, fd, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response.data; - } - - async getApps(databaseId: string) { - const url = `${Env.MODULE}/api/auth/admin/app/getApps?databaseId=${databaseId}`; - const response = await axios.get(url).catch((error) => { - throw Error(error); - }); - - return response.data; - } - - /** - * @name getDBUsers - * @param admin if admin initiated the call - * @param appId the id of app - * @desc get the existing users and their permissions for this db - * @returns $http promise - */ - async getDBUsers(admin: boolean, appId: string) { - let url = `${Env.MODULE}/api/auth/`; - if (admin) url += 'admin/'; - - url += 'app/getAppUsers'; - const response = await axios - .get(url, { - params: { appId: appId }, - }) - .catch((error) => { - throw Error(error); - }); - - // there was no response, that is an error - if (!response) { - throw Error('No Response to get non credentialed users'); - } - - return response; - } - /** - * @name removeAppUserPermissions - * @param admin if admin initiated the call - * @param appId the id of app - * @desc get the existing users and their permissions for this db - * @returns $http promise - */ - async removeAppUserPermissions(admin: boolean, appId: string, id: string) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - - url += 'app/removeAppUserPermission'; - - postData += 'appId=' + encodeURIComponent(appId); - postData += '&id=' + encodeURIComponent(id); - - const response = await axios - .post<{ success: boolean }>(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }) - .catch((error) => { - throw Error(error); - }); - - return response; - } - - // ---------------------------------------------------------------------- - // Member Level - // ---------------------------------------------------------------------- - - /** - * @name getAllUsers - * @param admin - is admin user - * @returns MemberInterface[] - */ - async getAllUsers( - admin: boolean, - searchTerm?: string, - offset?: number, - limit?: number, - ) { - let getAllUsersURL = `${Env.MODULE}/api/auth/`; - let getNumUsersURL = `${Env.MODULE}/api/auth/`; - - if (admin) { - getAllUsersURL += 'admin/'; - getNumUsersURL += 'admin/'; - } else { - return; - } - - getAllUsersURL += 'user/getAllUsers'; - // get the response - const response = await axios - .get< - { - id: string; - type: string; - name?: string; - admin?: boolean; - publisher?: boolean; - exporter?: boolean; - email?: string; - phone?: string; - phoneextension?: string; - countrycode?: string; - username?: string; - model_usage_restriction?: string; - model_usage_frequency?: string; - model_max_tokens?: number; - model_max_response_time?: number; - }[] - >(getAllUsersURL, { - params: { - filterWord: searchTerm, - offset: offset, - limit: limit, - }, - }) - .catch((error) => { - throw Error(error); - }); - getNumUsersURL += 'user/getNumUsers'; - const count = await axios.get(getNumUsersURL).catch((error) => { - throw Error(error); - }); - - // there was no response, that is an error - if (!response || !count) { - throw Error('No Response to get Members'); - } - - const finalResponse = { - users: response.data, - totalUsers: searchTerm !== '' ? response.data.length : count.data, - }; - - return finalResponse; - } - - /** - * @name editMemberInfo - * @param admin - * @param user - * @returns - */ - async editMemberInfo(admin: boolean, user: any) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - url += 'user/editUser'; - - postData += 'user=' + encodeURIComponent(JSON.stringify(user)); - - const response = await axios - .post(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }) - .catch((e) => { - throw Error(e); - }); - - return response; - } - - /** - * @name deleteMember - * @param admin - * @param userId - * @param userType - * @returns - */ - async deleteMember(admin: boolean, userId: string, userType: string) { - let url = `${Env.MODULE}/api/auth/`, - postData = ''; - - if (admin) { - url += 'admin/'; - } - url += 'user/deleteUser'; - - postData += 'userId=' + encodeURIComponent(userId); - postData += '&type=' + encodeURIComponent(userType); - - const response = await axios.post(url, postData, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - /** - * @name createUser - * @param admin - * @param user - * @returns - */ - async createUser(admin: boolean, user: any) { - let url = `${Env.MODULE}/api/auth/`; - - if (admin) { - url += 'admin/'; - } - url += 'user/registerUser'; - - let newUserInfo = ''; - - if (user.id) { - newUserInfo += 'userId=' + encodeURIComponent(user.id); - } - if (user.type) { - newUserInfo += '&type=' + encodeURIComponent(user.type); - } - if (user.type === 'NATIVE') { - newUserInfo += '&username=' + encodeURIComponent(user.id); - } else if (user.username) { - newUserInfo += '&username=' + encodeURIComponent(user.username); - } - if (user.password) { - newUserInfo += '&password=' + encodeURIComponent(user.password); - } - if (user.admin) { - newUserInfo += '&admin=' + encodeURIComponent(user.admin); - } - if (user.publisher) { - newUserInfo += '&publisher=' + encodeURIComponent(user.publisher); - } - if (user.exporter) { - newUserInfo += '&exporter=' + encodeURIComponent(user.exporter); - } - if (user.name) { - newUserInfo += '&name=' + encodeURIComponent(user.name); - } - if (user.email) { - newUserInfo += '&email=' + encodeURIComponent(user.email); - } - if (user.phone) { - newUserInfo += '&phone=' + encodeURIComponent(user.phone); - } - if (user.phoneextension) { - newUserInfo += - '&phoneextension=' + encodeURIComponent(user.phoneextension); - } - - if (user.model_usage_restriction) { - if (user.model_usage_restriction === 'null') { - user.model_usage_restriction = null; - } - newUserInfo += - '&modelUsageRestriction=' + - encodeURIComponent(user.model_usage_restriction); - } - if (user.model_usage_frequency) { - newUserInfo += - '&modelUsageFrequency=' + - encodeURIComponent(user.model_usage_frequency); - } - if (user.model_max_tokens) { - newUserInfo += - '&modelMaxTokens=' + encodeURIComponent(user.model_max_tokens); - } - if (user.model_max_response_time) { - newUserInfo += - '&modelMaxResponseTime=' + - encodeURIComponent(user.model_max_response_time); - } - - const response = await axios.post(url, newUserInfo, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }); - - return response; - } - - // api/auth/user/getUserAccessKeys - - /** - * Get access keys related to a user - */ - async getUserAccessKeys() { - const url = `${Env.MODULE}/api/auth/user/getUserAccessKeys`; - - const response = await axios - .get< - { - ACCESSKEY: string; - DATECREATED: string; - TOKENNAME: string; - LASTUSED?: string; - TOKENDESCRIPTION?: string; - }[] - >(url) - .catch((error) => { - throw Error(error); - }); - - return response.data; - } - - /** - * Get access keys related to a user - */ - async createUserAccessKey(tokenName: string, tokenDescription = '') { - const url = `${Env.MODULE}/api/auth/user/createUserAccessKey`; - let body = 'tokenName=' + encodeURIComponent(tokenName); - if (tokenDescription) { - body += '&tokenDescription=' + encodeURIComponent(tokenDescription); - } - - const response = await axios - .post<{ - ACCESSKEY: string; - SECRETKEY: string; - DATECREATED: string; - LASTUSED: string; - TOKENNAME: string; - TOKENDESCRIPTION?: string; - }>(url, body, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }) - .catch((error) => { - throw Error(error); - }); - - return response.data; - } - - /** - * Get access keys related to a user - */ - async deleteUserAccessKeys(accessKey: string) { - const url = `${Env.MODULE}/api/auth/user/deleteUserAccessKey`; - - const body = 'accessKey=' + encodeURIComponent(accessKey); - - const response = await axios - .post(url, body, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }) - .catch((error) => { - throw Error(error); - }); - - return response.data; - } + private _root: RootStore; + + constructor(root: RootStore) { + // register the root + this._root = root; + + // make it observable + makeAutoObservable(this); + } + + // ********************************************************* + // Actions + // ********************************************************* + /** + * Get the config + */ + async config() { + // get the response + const response = await axios + .get<{ + logins: { [key: string]: unknown }; + /** + * List of available providers (logins) that are available + */ + availableProviders: { + provider: string; + name: string; + isOauth: boolean; + }[]; + [key: string]: unknown; + }>(`${Env.MODULE}/api/config`) + .catch((error) => { + throw Error(error); + }); + + // there was an error, no response + if (!response) { + throw Error("No Config Response"); + } + + // save the config data + return response.data; + } + + /** + * Run a pixel string + * + * @param insightID - insightID to execute the pixel against + * @param pixel - pixel to execute + */ + async run(insightID: string, pixel: string) { + // build the expression + let postData = ""; + + postData += "expression=" + encodeURIComponent(pixel); + if (insightID) { + postData += "&insightId=" + encodeURIComponent(insightID); + } + + const response = await axios + .post<{ + insightID: string; + pixelReturn: { + isMeta: boolean; + operationType: string[]; + additionalOutput: { output: string }[]; + output: O[number]; + pixelExpression: string; + pixelId: string; + }[]; + }>(`${Env.MODULE}/api/engine/runPixel`, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }) + .catch((error) => { + throw Error(error); + }); + + // there was no response, that is an error + if (!response) { + throw Error("No Pixel Response"); + } + + // collect the errors + const errors: string[] = []; + for (const p of response.data.pixelReturn) { + const { output, operationType } = p; + + if (operationType.indexOf("ERROR") > -1) { + errors.push(output as string); + } + } + + return { + errors: errors, + insightId: response.data.insightID, + pixelReturn: response.data.pixelReturn, + }; + } + + /** + * Run a pixel off of the query insight + * + * @param pixel - pixel to execute + */ + //TODO: switch to extend unknown + async runQuery(pixel: string, insightId?: string) { + const { configStore } = this._root; + + return this.run(insightId ?? configStore.store.insightID, pixel); + } + + /** + * Download a file by using a unique key + * + * @param insightID - insightID to download the file + * @param fileKey - id for the file to download + */ + async download(insightID: string, fileKey: string) { + return new Promise((resolve) => { + // create the download url + const url = `${ + Env.MODULE + }/api/engine/downloadFile?insightId=${insightID}&fileKey=${encodeURIComponent( + fileKey, + )}`; + + // fake clicking a link + const link: HTMLAnchorElement = document.createElement("a"); + + link.href = url; + link.target = "_blank"; + document.body.appendChild(link); + link.click(); + + document.body.removeChild(link); + + // resolve the promise + resolve(); + }); + } + + /** + * Run a download a file off of the query insight + * + * @param fileKey - id for the file to download + */ + async downloadQuery(fileKey: string) { + const { configStore } = this._root; + + return this.download(configStore.store.insightID, fileKey); + } + + /** + * Allow the user to login + * + * @param username - username to login with + * @param password - password to login with + * @returns true if successful + */ + async login(username: string, password: string): Promise { + const postData = `username=${encodeURIComponent( + username, + )}&password=${encodeURIComponent(password)}&disableRedirect=true`; + + try { + const response = await axios.post( + `${Env.MODULE}/api/auth/login`, + postData, + { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + validateStatus: () => true, + }, + ); + + if (response?.data?.errorMessage) { + throw new Error(response.data.errorMessage); + } + + return true; + } catch (error) { + throw new Error(error.message); + } + } + + /** + * Allow the user to login with lin otp + * + * @param username - username to login with + * @param password - password to login with + * @returns true if successful + */ + async loginOTP( + username: string, + password: string, + ): Promise<"success" | "change-password"> { + const postData = `username=${encodeURIComponent( + username, + )}&pin=${encodeURIComponent(password)}&disableRedirect=true`; + + // track the status + let status: "success" | "change-password" = "success"; + + await axios + .post(`${Env.MODULE}/api/auth/loginLinOTP`, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }) + .catch((error) => { + if ( + error.response && + error.response.status === 401 && + error.response.data && + error.response.data.requirePwdChange + ) { + status = "change-password"; + return; + } + + // throw the message + throw Error(error); + }); + + return status; + } + + /** + * Confirm the OTP from LinOTP + * + * @param otp - otp to login with + * @returns true if successful + */ + async confirmOTP(otp: string): Promise { + const postData = `otp=${encodeURIComponent(otp)}&disableRedirect=true`; + + await axios + .post(`${Env.MODULE}/api/auth/loginLinOTP`, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }) + .catch((error) => { + // throw the message + throw Error(error.response.data.errorMessage); + }); + + return true; + } + + /** + * Allow the user to login with lin otp + * + * @param username - username to login with + * @param password - password to login with + * @returns true if successful + */ + async loginLDAP( + username: string, + password: string, + ): Promise<"success" | "change-password"> { + const postData = `username=${encodeURIComponent( + username, + )}&pin=${encodeURIComponent(password)}&disableRedirect=true`; + + // track the status + let status: "success" | "change-password" = "success"; + + await axios + .post(`${Env.MODULE}/api/auth/loginLDAP`, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }) + .catch((error) => { + if ( + error.response && + error.response.status === 401 && + error.response.data && + error.response.data.requirePwdChange + ) { + status = "change-password"; + return; + } + + // throw the message + throw Error(error); + }); + + return status; + } + + /** + * @name createUser + * @desc this call will run createUser endpoint + * @param name, name of new user + * @param username, username of new user + * @param email, email of new user + * @param password, password of new user + * @param phone, phone of new user + * @param phoneextension, phoneextension of new user + * @param countrycode, countrycode of new user + * @returns $http promise + */ + async registerUser( + name: string, + username: string, + email: string, + password: string, + phone: string, + phoneextension: string, + countrycode: string, + ) { + const create: string = + "name=" + + encodeURIComponent(name) + + "&username=" + + encodeURIComponent(username) + + "&email=" + + encodeURIComponent(email) + + "&password=" + + encodeURIComponent(password) + + "&phone=" + + encodeURIComponent(phone) + + "&phoneextension=" + + encodeURIComponent(phoneextension) + + "&countrycode=" + + encodeURIComponent(countrycode); + try { + const response = await axios.post( + `${Env.MODULE}/api/auth/createUser`, + create, + { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + validateStatus: () => true, + }, + ); + + if (response.data?.errorMessage) { + throw new Error(response.data.errorMessage); + } + return response.data; + } catch (error) { + throw new Error(error.message); + } + } + + /** * + * @returns true if successful + */ + async logout(): Promise { + await axios + .get(`${Env.MODULE}/api/auth/logout/all`, { + validateStatus: (status) => true, + }) + .catch((err) => { + throw Error(err); + }); + + return true; + } + + /** + * Allow the user to login using oauth + * + * @param provider - provider to login with + * @returns true if successful + */ + async oauth(provider: string): Promise { + // check if the user is logged in + const response = await axios + .get<{ name: string }>( + `${Env.MODULE}/api/auth/userinfo/${provider}`, + ) + .catch((error) => { + throw Error(error); + }); + + //check if they are already logged in + if (response.data && response.data.name) { + return true; + } + + return new Promise((resolve) => { + const url = `${Env.MODULE}/api/auth/login/${provider}`; + const popUpWindow = window.top.open( + url, + "_blank", + "height=600,width=400,top=300,left=" + 600, + ); + + // setup an interval to see if the popup window is closed or successful + const interval = setInterval(async () => { + try { + if ( + !popUpWindow || + popUpWindow.closed || + popUpWindow.closed === undefined + ) { + clearInterval(interval); + } else if ( + popUpWindow.document.location.href.indexOf( + `${window.location.host}`, + ) > -1 + ) { + clearInterval(interval); + + // close it + popUpWindow.close(); + + // try to get the info again + const response = await this.oauth(provider); + + // close it + resolve(response); + } + } catch (err) { + // do nothing + // this is to work around the blocked frame error that comes up + } + }, 1000); + }); + } + + /** + * @name getLoginProperties + * @returns + */ + async getLoginProperties() { + const url = `${Env.MODULE}/api/auth/loginProperties`; + + const response = await axios.get(url).catch((error) => { + throw Error(error); + }); + + return response.data; + } + + async modifyLoginProperties(provider, properties) { + const url = `${Env.MODULE}/api/auth/modifyLoginProperties/` + provider; + let postData = ""; + + postData += "modifications=" + JSON.stringify(properties); + + const response = await axios + .post(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }) + .catch((error) => { + throw Error(error); + }); + + return response.data; + } + + /** + * @name isAdminUser + * @description Determines whether user is admin or + * @returns boolean + */ + async isAdminUser() { + const url = `${Env.MODULE}/api/auth/admin/user/isAdminUser`; + + const response = await axios.get(url).catch((error) => { + throw Error(error); + }); + + if (!response) { + throw Error("No Response to isAdminUSer"); + } + + return response.data; + } + + /** + * @name createAdminTheme + * @param data the data that will be sent to the BE to define a theme + * @desc this call will create a new theme defined by the admin + */ + async createAdminTheme(data: { + name: string; + json: any; + isActive: boolean; + }) { + const url = `${Env.MODULE}/api/themes/createAdminTheme`; + + let postData = ""; + + postData += "name=" + encodeURIComponent(data.name); + postData += "&json=" + encodeURIComponent(JSON.stringify(data.json)); + postData += "&isActive=" + encodeURIComponent(data.isActive); + + const response = await axios.post(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response.data; + + // Sets an Active theme with material ui properties + // const map = JSON.parse(data['theme']['THEME_MAP']); + // const material_map = { + // ...map, + // materialTheme: lightTheme, + // }; + + // console.log(JSON.stringify(material_map)); + // monolithStore.createAdminTheme({ + // name: 'SEMOSS-TEST-DARK', + // isActive: true, + // json: material_map, + // }); + } + + // ---------------------------------------------------------------------- + // Engine + // ---------------------------------------------------------------------- + /** + * @name getEngines + * @param admin - is admin user + * @returns AppInterface[] + */ + async getEngines( + admin: boolean, + search: string, + engineType: string, + offset?: number, + limit?: number, + ) { + let url = `${Env.MODULE}/api/auth/`; + + if (admin) { + url += "admin/"; + } + + url += "engine/getEngines"; + + const params = {}; + + params["engineTypes"] = engineType; + search && (params["filterWord"] = search); + + offset && (params["offset"] = offset); + + limit && (params["limit"] = limit); + + // get the response + const response = await axios + .get(url, { + params: params, + }) + .catch((error) => { + throw Error(error); + }); + + // there was no response, that is an error + if (!response) { + throw Error("No Response to get Apps"); + } + + return response.data; + } + + /** + * @name getUserEnginePermission + * @desc Get a user's role for the engine + * @param id - id of engine (db, storage, model) + */ + async getUserEnginePermission(id: string) { + const response = await axios + .get<{ permission: Role }>( + `${Env.MODULE}/api/auth/engine/getUserEnginePermission`, + { + params: { engineId: id }, + }, + ) + .catch((error) => { + throw Error(error); + }); + + // there was no response, that is an error + if (!response) { + throw Error("No roles for the app user"); + } + + return response.data; + } + + /** + * @name getEngineUsers + * @param admin + * @param appId + * @returns MemberInterface[] + */ + async getEngineUsers( + admin: boolean, + databaseId: string, + user: string, + permission: string, + offset?: number, + limit?: number, + projectId?, + ) { + let url = `${Env.MODULE}/api/auth/`; + + if (admin) { + url += "admin/"; + } + + url += "engine/getEngineUsers"; + + // get the response + const response = await axios + .get<{ + members: { + id: string; + name: string; + permission: string; + }[]; + totalMembers: number; + }>(url, { + params: { + engineId: databaseId, + searchTerm: user, + permission: permission, + offset: offset, + limit: limit, + }, + }) + .catch((error) => { + throw Error(error); + }); + + // there was no response, that is an error + if (!response) { + throw Error("No Response to get users associated with app"); + } + + console.warn( + "Project Id is not a necessary param, optional due to the similarity of usage for getInsightUsers", + projectId, + ); + + return response.data; + } + + /** + * @name getEngineUsersNoCredentials + * @param admin + * @param engineId + * @param limit + * @param offSet + * @param searchTerm + * @returns + */ + async getEngineUsersNoCredentials( + admin: boolean, + engineId: string, + limit: number, + offset: number, + searchTerm: string, + ) { + let url = `${Env.MODULE}/api/auth/`; + + // Currently no admin ENDPOINT; + if (admin) { + url += "admin/"; + } + + url += "engine/getEngineUsersNoCredentials"; + + // get the response + const response = await axios + .get< + { + id: string; + email: string; + name: string; + type: string; + username: string; + }[] + >(url, { + params: { + engineId: engineId, + limit: limit, + offset: offset, + searchTerm: searchTerm, + }, + }) + .catch((error) => { + throw Error(error); + }); + + // there was no response, that is an error + if (!response) { + throw Error("No Response to get non credentialed users"); + } + + return response; + } + + /** + * @name addEngineUserPermissions + * @param admin + * @param appId + * @param users + * @returns + */ + async addEngineUserPermissions( + admin: boolean, + appId: string, + users: any[], + ) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + // No Admin endpoint currently + if (admin) { + url += "admin/"; + } + + url += "engine/addEngineUserPermissions"; + + postData += "engineId=" + encodeURIComponent(appId); + postData += + "&userpermissions=" + encodeURIComponent(JSON.stringify(users)); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + + // figure out whether we want to do .catch here + } + + /** + * @name editEngineUserPermissions + * @param admin + * @param appId + * @param users + * @returns + */ + async editEngineUserPermissions( + admin: boolean, + appId: string, + users: any[], + ) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + + url += "engine/editEngineUserPermissions"; + + postData += "engineId=" + encodeURIComponent(appId); + postData += + "&userpermissions=" + encodeURIComponent(JSON.stringify(users)); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + + // figure out whether we want to do .catch here + } + + /** + * @name removeEngineUserPermissions + * @param admin + * @param appId + * @param users + * @returns + */ + async removeEngineUserPermissions( + admin: boolean, + appId: string, + users: any[], + ) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + + url += "engine/removeEngineUserPermissions"; + + postData += "engineId=" + encodeURIComponent(appId); + postData += "&ids=" + encodeURIComponent(JSON.stringify(users)); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + /** + * @name setEngineGlobal + * @param admin + * @param appId + * @param global + */ + async setEngineGlobal(admin: boolean, engineId: string, global: boolean) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + + // change to database + url += "engine/setEngineGlobal"; + + postData += "engineId=" + encodeURIComponent(engineId); + postData += "&public=" + encodeURIComponent(global); + + const response = await axios + .post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }) + .catch((error) => { + throw Error(error); + }); + + return response; + } + + /** + * @name setEngineVisiblity + * @param admin + * @param appId + * @param visible + */ + async setEngineVisiblity( + admin: boolean, + engineId: string, + visible: boolean, + ) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + + url += "engine/setEngineDiscoverable"; + + postData += "engineId=" + encodeURIComponent(engineId); + postData += "&discoverable=" + encodeURIComponent(visible); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + async setEngineFavorite(engineId: string, favorite: boolean) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + url += "engine/setEngineFavorite"; + postData += "engineId=" + encodeURIComponent(engineId); + postData += "&isFavorite=" + encodeURIComponent(favorite); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + /** + * @name setProjectFavorite + * @param projectId + * @param favorite + */ + async setProjectFavorite(projectId: string, favorite: boolean) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + url += "project/setProjectFavorite"; + postData += "projectId=" + encodeURIComponent(projectId); + postData += "&isFavorite=" + encodeURIComponent(favorite); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + /** + * @name approveEngineUserAccessRequest + * @param admin + * @param engineId + * @param requests + * @returns + */ + async approveEngineUserAccessRequest( + admin: boolean, + engineId: string, + requests: any[], + ) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + url += "engine/approveEngineUserAccessRequest"; + + postData += "engineId=" + encodeURIComponent(engineId); + postData += "&requests=" + encodeURIComponent(JSON.stringify(requests)); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + /** + * @name denyEngineUserAccessRequest + * @param admin + * @param appId + * @param userIds + * @returns + */ + async denyEngineUserAccessRequest( + admin: boolean, + engineId: string, + userIds: string[], + ) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + url += "engine/denyEngineUserAccessRequest"; + + postData += "engineId=" + encodeURIComponent(engineId); + postData += + "&requestIds=" + encodeURIComponent(JSON.stringify(userIds)); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + return response; + } + + // ---------------------------------------------------------------------- + // Database Level + // ---------------------------------------------------------------------- + /** + * @name getDatabases + * @param admin - is admin user + * @returns AppInterface[] + */ + async getDatabases(admin: boolean) { + let url = `${Env.MODULE}/api/auth/`; + + if (admin) { + url += "admin/"; + } + + url += "database/getDatabases"; + // get the response + const response = await axios + .get< + { + app_global: boolean; + app_id: string; + app_name: string; + app_permission: string; + app_visibility: boolean; + }[] + >(url) + .catch((error) => { + throw Error(error); + }); + + // there was no response, that is an error + if (!response) { + throw Error("No Response to get Apps"); + } + + return response.data; + } + + // ----- Users Start ----- + + // ----- Users End ----- + + // ---------------------------------------------------------------------- + // Teams Start + // ---------------------------------------------------------------------- + + /** + * @name getTeams + * @param admin - is admin user + */ + async getTeams(admin: boolean) { + let url = `${Env.MODULE}/api/auth/`; + + if (admin) { + url += "admin/"; + } + + url += "group/getGroups"; + // get the response + const response = await axios.get(url).catch((error) => { + throw Error(error); + }); + + // there was no response, that is an error + if (!response) { + throw Error("No Response to get teams"); + } + + return response.data; + } + + /** + * @name addTeam + * @param groupId + * @param description + * @param type + * @returns + */ + async addTeam(groupId: string, description: string, type?: string) { + let url = `${Env.MODULE}/api/auth/admin/`, + postData = ""; + + url += "group/addGroup"; + + postData += "groupId=" + encodeURIComponent(groupId); + postData += "&description=" + encodeURIComponent(description); + if (type) { + postData += "&type=" + encodeURIComponent(type); + } + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + /** + * @name editTeam + * @param groupId + * @param description + * @param type + * @returns + */ + async editTeam( + groupId: string, + description: string, + type?: string, + previousTeamName?: string, + previousType?: string, + ) { + let url = `${Env.MODULE}/api/auth/admin/`, + postData = ""; + + url += "group/editGroupDetails"; + + postData += "groupId=" + encodeURIComponent(previousTeamName); + postData += "&newGroupId=" + encodeURIComponent(groupId); + postData += "&newDescription=" + encodeURIComponent(description); + postData += "&type=" + encodeURIComponent(previousType); + postData += "&newType=" + encodeURIComponent(type); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + /** + * @name deleteTeam + * @param groupId + * @param description + * @param type + * @returns + */ + async deleteTeam(groupid: string, type?: string) { + let url = `${Env.MODULE}/api/auth/admin/`, + postData = ""; + + url += "group/deleteGroup"; + + postData += "groupId=" + encodeURIComponent(groupid); + + if (type) { + postData += "&type=" + encodeURIComponent(type); + } + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + /** + * @name getTeamUsers + * @param groupId + * @param limit + * @param offSet + * @param searchTerm + */ + async getTeamUsers( + groupId: string, + limit: number, + offset: number, + searchTerm: string, + ) { + let url = `${Env.MODULE}/api/auth/admin/`; + + url += "group/getGroupMembers"; + + const params = {}; + + groupId && (params["groupId"] = groupId); + limit && (params["limit"] = limit); + offset && (params["offset"] = offset); + searchTerm && (params["searchTerm"] = searchTerm); + + const response = await axios + .get(url, { + params: params, + }) + .catch((error) => { + throw Error(error); + }); + + // there was no response, that is an error + if (!response) { + throw Error("No Response to get group members"); + } + + return response.data; + } + + /** + * @name getTeamUsersCount + * @param groupId + */ + async getTeamUsersCount(groupId: string) { + let url = `${Env.MODULE}/api/auth/admin/`; + + url += "group/getNumMembersInGroup"; + + const params = {}; + + groupId && (params["groupId"] = groupId); + const response = await axios + .get(url, { + params: params, + }) + .catch((error) => { + throw Error(error); + }); + + // there was no response, that is an error + if (!response) { + throw Error("No Response to get group member count"); + } + + return response.data; + } + + /** + * @name getNonTeamUsers + * @param groupId + */ + async getNonTeamUsers( + groupId: string, + limit: number, + offset: number, + searchTerm: string, + ) { + let url = `${Env.MODULE}/api/auth/admin/`; + + url += "group/getNonGroupMembers"; + + const params = {}; + + groupId && (params["groupId"] = groupId); + limit && (params["limit"] = limit); + offset && (params["offset"] = offset); + searchTerm && (params["searchTerm"] = searchTerm); + + const response = await axios + .get(url, { + params: params, + }) + .catch((error) => { + throw Error(error); + }); + + // there was no response, that is an error + if (!response) { + throw Error("No Response to get non group members"); + } + + return response.data; + } + + /** + * @name addTeamUser + * @param groupId + * @param type + * @param userId + * @param admin + * @param endDate + * @returns + */ + async addTeamUser( + groupId: string, + type: string, + userId: string, + admin: boolean, + endDate?: string, + ) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + + url += "group/addGroupMember"; + + postData += "groupId=" + encodeURIComponent(groupId); + postData += "&type=" + encodeURIComponent(type); + postData += "&userId=" + encodeURIComponent(userId); + + if (endDate) { + postData += "&endDate=" + encodeURIComponent(endDate); + } + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + /** + * @name deleteTeamUser + * @param groupId + * @param type + * @param userId + * @returns + */ + async deleteTeamUser(user: { + groupid: string; + type: string; + userid: string; + }) { + let url = `${Env.MODULE}/api/auth/admin/`, + postData = ""; + + url += "group/deleteGroupMember"; + + postData += "groupId=" + encodeURIComponent(user.groupid); + postData += "&userId=" + encodeURIComponent(user.userid); + postData += "&type=" + encodeURIComponent(user.type); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + /** + * @name addProjectPermission + * @param groupId + * @param type + * @param projectId + * @param permission + * @param endDate + * @returns + */ + async addProject( + groupId: string, + projectId: string, + permission: number, + type?: string, + endDate?: string, + ) { + let url = `${Env.MODULE}/api/auth/admin/`, + postData = ""; + + url += "group/addGroupProjectPermission"; + + postData += "groupId=" + encodeURIComponent(groupId); + postData += "&projectId=" + encodeURIComponent(projectId); + postData += "&permission=" + encodeURIComponent(permission); + + if (endDate) { + postData += "&endDate=" + encodeURIComponent(endDate); + } + + if (type) { + postData += "&type=" + encodeURIComponent(type); + } + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + /** + * @name editProjectPermission + * @param groupId + * @param type + * @param projectId + * @param permission + * @param endDate + * @returns + */ + async editProjectPermisison( + groupId: string, + groupType: string, + project: { + projectid: string; + permission: number; + project_type?: string; + endDate?: string; + }, + ) { + let url = `${Env.MODULE}/api/auth/admin/`, + postData = ""; + + url += "group/editGroupProjectPermission"; + + postData += "groupId=" + encodeURIComponent(groupId); + postData += "&projectId=" + encodeURIComponent(project.projectid); + postData += "&permission=" + encodeURIComponent(project.permission); + + if (groupType) { + postData += "&type=" + encodeURIComponent(groupType); + } + if (project.endDate) { + postData += "&endDate=" + encodeURIComponent(project.endDate); + } + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + /** + * @name deleteProjectPermission + * @param groupId + * @param type + * @param projectId + * @returns + */ + async deleteProjectPermission( + groupId, + groupType: string, + project: { + projectid: string; + group_type?: string; + }, + ) { + let url = `${Env.MODULE}/api/auth/admin/`, + postData = ""; + + url += "group/removeGroupProjectPermission"; + + postData += "groupId=" + encodeURIComponent(groupId); + postData += "&projectId=" + encodeURIComponent(project.projectid); + if (groupType) { + postData += "&type=" + encodeURIComponent(groupType); + } + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + /** + * @name getTeamProjects + * @param groupId + * @param limit + * @param offSet + * @param searchTerm + */ + async getTeamProjects( + groupId: string, + groupType: string, + limit: number, + offset: number, + searchTerm: string, + onlyApps: boolean, + type?: string, + ) { + let url = `${Env.MODULE}/api/auth/admin/`; + + url += "group/getProjectsForGroup"; + + const params = {}; + + groupId && (params["groupId"] = groupId); + groupType && (params["groupType"] = groupType); + limit && (params["limit"] = limit); + offset && (params["offset"] = offset); + searchTerm && (params["searchTerm"] = searchTerm); + + // searchTerm + // ? (params['searchTerm'] = searchTerm) + // : (params['searchTerm'] = ''); + onlyApps && (params["onlApps"] = onlyApps); + type ? (params["type"] = type) : (params["type"] = null); + + const response = await axios + .get(url, { + params: params, + }) + .catch((error) => { + throw Error(error); + }); + + // there was no response, that is an error + if (!response) { + throw Error("No Response to get group members"); + } + + return response.data; + } + + /** + * @name getUnassignedTeamProjects + * @param groupId + * @param limit + * @param offSet + * @param searchTerm + */ + async getUnassignedTeamProjects( + groupId: string, + groupType: string, + limit: number, + offset: number, + searchTerm: string, + ) { + let url = `${Env.MODULE}/api/auth/admin/`; + + url += "group/getAvailableProjectsForGroup"; + + const params = {}; + + groupId && (params["groupId"] = groupId); + groupType && (params["groupType"] = groupType); + limit && (params["limit"] = limit); + offset && (params["offset"] = offset); + searchTerm && (params["searchTerm"] = searchTerm); + + const response = await axios + .get(url, { + params: params, + }) + .catch((error) => { + throw Error(error); + }); + + // there was no response, that is an error + if (!response) { + throw Error("No Response to get group members"); + } + + return response.data; + } + + /** + * @name addEnginePermission + * @param groupId + * @param type + * @param projectId + * @param permission + * @param endDate + * @returns + */ + async addEnginePermission( + groupId: string, + engineId: string, + permission: number, + type?: string, + endDate?: string, + ) { + let url = `${Env.MODULE}/api/auth/admin/`, + postData = ""; + + url += "group/addGroupEnginePermission"; + + postData += "groupId=" + encodeURIComponent(groupId); + postData += "&engineId=" + encodeURIComponent(engineId); + postData += "&permission=" + encodeURIComponent(permission); + + if (type) { + postData += "&type=" + encodeURIComponent(type); + } + + if (endDate) { + postData += "&endDate=" + encodeURIComponent(endDate); + } + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + /** + * @name editEnginePermission + * @param groupId + * @param type + * @param projectId + * @param permission + * @param endDate + * @returns + */ + async editEnginePermission( + groupId: string, + engine: { + engineid: string; + permission: string; + type?: string; + endDate?: string; + }, + ) { + let url = `${Env.MODULE}/api/auth/admin/`, + postData = ""; + + url += "group/editGroupEnginePermission"; + + postData += "groupId=" + encodeURIComponent(groupId); + postData += "&engineId=" + encodeURIComponent(engine.engineid); + postData += "&permission=" + encodeURIComponent(engine.permission); + + if (engine.type) { + postData += "&type=" + encodeURIComponent(engine.type); + } + + if (engine.endDate) { + postData += "&endDate=" + encodeURIComponent(engine.endDate); + } + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + /** + * @name deleteEnginePermission + * @param groupId + * @param type + * @param projectId + * @returns + */ + async deleteEnginePermission( + groupId: string, + groupType: string, + engine: { + engineid: string; + type?: string; + }, + ) { + let url = `${Env.MODULE}/api/auth/admin/`, + postData = ""; + + url += "group/removeGroupEnginePermission"; + + postData += "groupId=" + encodeURIComponent(groupId); + postData += "&engineId=" + encodeURIComponent(engine.engineid); + + if (groupType) { + postData += "&type=" + encodeURIComponent(groupType); + } + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + /** + * @name getTeamEngines + * @param groupId + * @param limit + * @param offSet + * @param searchTerm + */ + async getTeamEngines( + groupId: string, + groupType: string, + limit: number, + offset: number, + searchTerm: string, + ) { + let url = `${Env.MODULE}/api/auth/admin/`; + + url += "group/getEnginesForGroup"; + + const params = {}; + + groupId && (params["groupId"] = groupId); + groupType && (params["groupType"] = groupType); + limit && (params["limit"] = limit); + offset && (params["offset"] = offset); + searchTerm && (params["searchTerm"] = searchTerm); + + const response = await axios + .get(url, { + params: params, + }) + .catch((error) => { + throw Error(error); + }); + + // there was no response, that is an error + if (!response) { + throw Error("No Response to get group members"); + } + + return response.data; + } + + /** + * @name getUnassignedTeamEngines + * @param groupId + * @param limit + * @param offSet + * @param searchTerm + */ + async getUnassignedTeamEngines( + groupId: string, + groupType: string, + limit: number, + offset: number, + searchTerm: string, + ) { + let url = `${Env.MODULE}/api/auth/admin/`; + + url += "group/getAvailableEnginesForGroup"; + + const params = {}; + + groupId && (params["groupId"] = groupId); + groupType && (params["groupType"] = groupType); + limit && (params["limit"] = limit); + offset && (params["offset"] = offset); + searchTerm && (params["searchTerm"] = searchTerm); + + const response = await axios + .get(url, { + params: params, + }) + .catch((error) => { + throw Error(error); + }); + + // there was no response, that is an error + if (!response) { + throw Error("No Response to get group members"); + } + + return response.data; + } + + // ---------- Teams End ----------------- + + // ----- Properties Start ----- + + /** + * @name updateDatabaseSmmsProperties + * @param databaseId + * @param smssProps + * @returns + */ + async updateDatabaseSmssProperties(databaseId: string, smssProps: string) { + const url = `${Env.MODULE}/api/e-${databaseId}/updateSmssFile`; + + let postData = ""; + postData += "engineId=" + encodeURIComponent(databaseId); + postData += "&smss=" + encodeURIComponent(smssProps); + + const response = await axios + .post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }) + .catch((error) => { + throw Error(error); + }); + + return response; + } + + /** + * @name setDatabaseDiscoverable + * @param admin + * @param appId + * @param discoverable + */ + async setDatabaseDiscoverable( + admin: boolean, + appId: string, + discoverable: boolean, + ) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + + // change to database + url += "app/setAppDiscoverable"; + + postData += "appId=" + encodeURIComponent(appId); + postData += "&discoverable=" + encodeURIComponent(discoverable); + + const response = await axios + .post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }) + .catch((error) => { + throw Error(error); + }); + + return response; + } + + // ----- Properties End ----- + + // ---------------------------------------------------------------------- + // Project Level + // ---------------------------------------------------------------------- + /** + * @name getProjects + * @param admin - is admin user + * @returns Projects retrieved from Promise + */ + async getProjects( + admin: boolean, + search?: string, + offset?: number, + limit?: number, + ) { + let url = `${Env.MODULE}/api/auth/`; + + if (admin) { + url += "admin/"; + } + + url += "project/getProjects"; + + const params = {}; + + search && (params["filterWord"] = search); + + offset && (params["offset"] = offset); + + limit && (params["limit"] = limit); + + const response = await axios + .get< + { + project_global: boolean; + project_id: string; + project_name: string; + project_permission: string; + project_visibility: boolean; + }[] + >(url, { + params: params, + }) + .catch((error) => { + throw Error(error); + }); + + // there was no response, that is an error + if (!response) { + throw Error("No Response to get Projects"); + } + + return response.data; + } + + /** + * @name getUserProjectPermission + * @param admin - is admin user + * @returns Projects retrieved from Promise + */ + async getUserProjectPermission( + projectId: string, + ): Promise<{ permission: Role }> { + let url = `${Env.MODULE}/api/auth/`; + + url += "project/getUserProjectPermission"; + + try { + const response = await axios.get(url, { + params: { + projectId: projectId, + }, + }); + + // there was no response, that is an error + if (!response) { + if (response.status === 401) { + throw Error("User does not have access to this project"); + } else { + throw Error("No Response to get permission"); + } + } + + return response.data; + } catch (error) { + throw Error(error); + } + } + + // ----- Users Start ----- + + /** + * @name getProjectUsers + * @param admin + * @param projectId + * @returns MemberInterface[] + */ + async getProjectUsers( + admin: boolean, + projectId: string, + user: string, + permission: string, + offset?: number, + limit?: number, + id?: string, + ) { + let url = `${Env.MODULE}/api/auth/`; + + if (admin) { + url += "admin/"; + } + + url += "project/getProjectUsers"; + // get the response + const response = await axios + .get<{ + members: { + id: string; + name: string; + permission: string; + }[]; + totalMembers: number; + }>(url, { + params: { + projectId: projectId, + userId: user, + permission: permission, + offset: offset, + limit: limit, + }, + }) + .catch((error) => { + throw Error(error); + }); + + // there was no response, that is an error + if (!response) { + throw Error("No Response to get users associated with app"); + } + + return response.data; + } + + /** + * @name getProjectUsersNoCredentials + * @param admin if admin initiated the call + * @param appId the id of app + * @param limit + * @param offSet + * @param searchTerm + * @desc get the existing users and their permissions for this app + */ + async getProjectUsersNoCredentials( + admin: boolean, + appId: string, + limit: number, + offset: number, + searchTerm: string, + ) { + let url = `${Env.MODULE}/api/auth/`; + + if (admin) { + url += "admin/"; + } + + url += "project/getProjectUsersNoCredentials"; + + // get the response + const response = await axios + .get< + { + id: string; + email: string; + name: string; + type: string; + username: string; + }[] + >(url, { + params: { + projectId: appId, + limit: limit, + offset: offset, + searchTerm: searchTerm, + }, + }) + .catch((error) => { + throw Error(error); + }); + + // there was no response, that is an error + if (!response) { + throw Error("No Response to get non credentialed users"); + } + + return response; + } + + /** + * @name approveProjectUserAccessRequest + * @param admin + * @param appId + * @param requests + * @returns + */ + async approveProjectUserAccessRequest( + admin: boolean, + appId: string, + requests: any[], + ) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + url += "project/approveProjectUserAccessRequest"; + + postData += "projectId=" + encodeURIComponent(appId); + postData += "&requests=" + encodeURIComponent(JSON.stringify(requests)); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + + // figure out whether we want to do .catch here + } + + /** + * @name denyProjectUserAccessRequest + * @param admin + * @param projectId + * @param userIds + * @returns + */ + async denyProjectUserAccessRequest( + admin: boolean, + projectId: string, + userIds: string[], + ) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + url += "project/denyProjectUserAccessRequest"; + + postData += "projectId=" + encodeURIComponent(projectId); + postData += + "&requestids=" + encodeURIComponent(JSON.stringify(userIds)); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + return response; + + // figure out whether we want to do .catch here + } + + /** + * @name addProjectUserPermissions + * @param admin + * @param appId + * @param users + * @returns + */ + async addProjectUserPermissions( + admin: boolean, + appId: string, + users: any[], + ) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + url += "project/addProjectUserPermissions"; + + postData += "projectId=" + encodeURIComponent(appId); + postData += + "&userpermissions=" + encodeURIComponent(JSON.stringify(users)); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + + // figure out whether we want to do .catch here + } + + /** + * @name editProjectUserPermissions + * @param admin + * @param appId + * @param users + * @returns + */ + async editProjectUserPermissions( + admin: boolean, + appId: string, + users: any[], + ) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + url += "project/editProjectUserPermissions"; + + postData += "projectId=" + encodeURIComponent(appId); + postData += + "&userpermissions=" + encodeURIComponent(JSON.stringify(users)); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + + // figure out whether we want to do .catch here + } + + /** + * @name removeProjectUserPermissions + * @param admin + * @param appId + * @param users + * @returns + */ + async removeProjectUserPermissions( + admin: boolean, + appId: string, + users: any[], + ) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + url += "project/removeProjectUserPermissions"; + + postData += "projectId=" + encodeURIComponent(appId); + postData += "&ids=" + encodeURIComponent(JSON.stringify(users)); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + + // figure out whether we want to do .catch here + } + // ----- Users End ----- + // ----- Properties Start ----- + + /** + * @name setProjectGlobal + * @param admin + * @param appId + * @param global + */ + async setProjectGlobal(admin, appId, global: boolean) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + + url += "project/setProjectGlobal"; + + postData += "projectId=" + encodeURIComponent(appId); + postData += "&public=" + encodeURIComponent(global); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + /** + * @name setProjectVisiblity + * @param admin + * @param appId + * @param visible + */ + async setProjectVisiblity(admin, appId, visible) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + + url += "project/setProjectDiscoverable"; + + postData += "projectId=" + encodeURIComponent(appId); + postData += "&discoverable=" + encodeURIComponent(visible); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + // ----- Properties End ----- + // ----- Portal Start ----- + + /** + * @name setProjectPortal + * @param projectId + * @param hasPortal + * @param portalName + */ + async setProjectPortal( + admin: boolean, + projectId: string, + hasPortal: boolean, + portalName?: string, + ) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + // if (admin) { + // url += 'admin/'; + // } + + url += "project/setProjectPortal"; + + postData += "projectId=" + encodeURIComponent(projectId); + postData += "&hasPortal=" + encodeURIComponent(hasPortal); + + if (portalName) { + postData += "&projectId=" + encodeURIComponent(portalName); + } + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + // ----- Portal End ----- + + // ---------------------------------------------------------------------- + // Insight Level + // ---------------------------------------------------------------------- + + async getInsights() { + console.error("needs to be added on BE"); + } + + async getInsightUsers( + admin: boolean, + id: string, + user: string, + permission: string, + offset?: number, + limit?: number, + projectid?: string, + ) { + // /api/auth/insight/getInsightUsers? + // insightId=feb4c485-0aa8-4ff6-b355-e894dc74589a&projectId=2e2534db-fffa-4054-b9e9-dbf44183ab3b + + let url = `${Env.MODULE}/api/auth/`; + + if (admin) { + url += "admin/"; + } + + url += "insight/getInsightUsers"; + + if (!projectid) { + throw Error("no project id"); + } + + // get the response + const response = await axios + .get< + { + id: string; + name: string; + permission: string; + }[] + >(url, { + params: { + insightId: id, + projectId: projectid, + offset: offset, + limit: limit, + userId: user, + + // projectId: projectId, + // permission: permission, + }, + }) + .catch((error) => { + throw Error(error); + }); + + if (!response) { + throw Error("Unsuccessful attempt at retrieving Insight Users"); + } + + return response.data; + } + + /** + * @name getInsightUsersNoCredentials + * @param admin if admin initiated the call + * @param projectId the id of app + * @desc get the existing users and their permissions for this app + */ + async getInsightUsersNoCredentials( + admin: boolean, + insightId: string, + projectId: string, + ) { + let url = `${Env.MODULE}/api/auth/`; + + if (admin) { + url += "admin/"; + } + + url += "insight/getInsightUsersNoCredentials"; + + // get the response + const response = await axios + .get(url, { + params: { projectId: projectId, insightId: insightId }, + }) + .catch((error) => { + throw Error(error); + }); + + // there was no response, that is an error + if (!response) { + throw Error("No Response to get non credentialed users"); + } + + return response.data; + } + + // Verified Project Member actions + + /** + * @name addInsightUserPermissions + * @param admin + * @param appId + * @param users + * @returns + */ + async addInsightUserPermissions( + admin: boolean, + id: string, + users: any[], + projectId: string, + ) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + url += "insight/addInsightUserPermissions"; + + postData += "projectId=" + encodeURIComponent(projectId); + postData += "&insightId=" + encodeURIComponent(id); + postData += + "&userpermissions=" + encodeURIComponent(JSON.stringify(users)); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + + // figure out whether we want to do .catch here + } + + /** + * @name removeInsightUserPermissions + * @param admin + * @param appId + * @param users + * @returns + */ + async removeInsightUserPermissions( + admin: boolean, + id: string, + users: any[], + projectId, + ) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + url += "project/removeProjectUserPermissions"; + + postData += "projectId=" + encodeURIComponent(projectId); + postData += "&insightId=" + encodeURIComponent(id); + postData += "&ids=" + encodeURIComponent(JSON.stringify(users)); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + + // figure out whether we want to do .catch here + } + + /** + * @name editInsightUserPermissions + * @param admin + * @param appId + * @param users + * @returns + */ + async editInsightUserPermissions( + admin: boolean, + id: string, + users: any[], + projectId: string, + ) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + url += "insight/editInsightUserPermissions"; + + postData += "projectId=" + encodeURIComponent(projectId); + postData += "&insightId=" + encodeURIComponent(id); + postData += + "&userpermissions=" + encodeURIComponent(JSON.stringify(users)); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + + // figure out whether we want to do .catch here + } + + // Being used but need to be taken out below ------------------ + /** + * This will end up being taken out + * @param admin + * @param projectId + * @param id + * @param permission + * @returns + */ + async editProjectUserPermission( + admin: boolean, + projectId: string, + id: string, + permission: string, + ) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + + url += "project/editProjectUserPermission"; + + postData += "projectId=" + encodeURIComponent(projectId); + postData += "&id=" + encodeURIComponent(id); + postData += "&permission=" + encodeURIComponent(permission); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + /** + * This will end up being taken out + * @desc this call will edit access permissions for a user + * @param admin admin true or false + * @param appId id of app + * @param id id of user + * @param permission permission to give + */ + async editAppUserPermission( + admin: boolean, + appId: string, + id: string, + permission: string, + ) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + + url += "app/editAppUserPermission"; + + postData += "appId=" + encodeURIComponent(appId); + postData += "&id=" + encodeURIComponent(id); + postData += "&permission=" + encodeURIComponent(permission); + + const response = await axios.post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + async uploadFile( + files: File[], + insightId: string | null, + projectId?: string | null, + path?: string | null, + ) { + let param = ""; + if (insightId || projectId || path) { + if (insightId) { + if (param.length > 0) { + param += "&"; + } + param += `insightId=${insightId}`; + } + + if (projectId) { + if (param.length > 0) { + param += "&"; + } + param += `projectId=${projectId}`; + } + + if (path) { + if (param.length > 0) { + param += "&"; + } + param += `path=${path}`; + } + + param = `?${param}`; + } + + const url = `${Env.MODULE}/api/uploadFile/baseUpload${param}`, + fd: FormData = new FormData(); + + if (Array.isArray(files)) { + for (let i = 0; i < files.length; i++) { + fd.append("file", files[i]); + } + } else { + // pasted data + fd.append("file", files); + } + + const response = await axios.post< + { + fileName: string; + fileLocation: string; + }[] + >(url, fd, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response.data; + } + + async uploadImage( + files: File[], + projectId: string | null, + insightId?: string | null, + ) { + const url = `${Env.MODULE}/api/images/projectImage/upload`, + fd: FormData = new FormData(); + + if (Array.isArray(files)) { + for (let i = 0; i < files.length; i++) { + fd.append("file", files[i]); + } + } else { + // pasted data + fd.append("file", files); + } + + if (insightId) { + fd.append("insightId", insightId); + } else { + const { configStore } = this._root; + fd.append("insightId", configStore.store.insightID); + } + + if (projectId) { + fd.append("projectId", projectId); + } + + const response = await axios.post< + { + app_id: string; + app_name: string; + message: string; + }[] + >(url, fd, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response.data; + } + + async getApps(databaseId: string) { + const url = `${Env.MODULE}/api/auth/admin/app/getApps?databaseId=${databaseId}`; + const response = await axios.get(url).catch((error) => { + throw Error(error); + }); + + return response.data; + } + + /** + * @name getDBUsers + * @param admin if admin initiated the call + * @param appId the id of app + * @desc get the existing users and their permissions for this db + * @returns $http promise + */ + async getDBUsers(admin: boolean, appId: string) { + let url = `${Env.MODULE}/api/auth/`; + if (admin) url += "admin/"; + + url += "app/getAppUsers"; + const response = await axios + .get(url, { + params: { appId: appId }, + }) + .catch((error) => { + throw Error(error); + }); + + // there was no response, that is an error + if (!response) { + throw Error("No Response to get non credentialed users"); + } + + return response; + } + /** + * @name removeAppUserPermissions + * @param admin if admin initiated the call + * @param appId the id of app + * @desc get the existing users and their permissions for this db + * @returns $http promise + */ + async removeAppUserPermissions(admin: boolean, appId: string, id: string) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + + url += "app/removeAppUserPermission"; + + postData += "appId=" + encodeURIComponent(appId); + postData += "&id=" + encodeURIComponent(id); + + const response = await axios + .post<{ success: boolean }>(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }) + .catch((error) => { + throw Error(error); + }); + + return response; + } + + // ---------------------------------------------------------------------- + // Member Level + // ---------------------------------------------------------------------- + + /** + * @name getAllUsers + * @param admin - is admin user + * @returns MemberInterface[] + */ + async getAllUsers( + admin: boolean, + searchTerm?: string, + offset?: number, + limit?: number, + ) { + let getAllUsersURL = `${Env.MODULE}/api/auth/`; + let getNumUsersURL = `${Env.MODULE}/api/auth/`; + + if (admin) { + getAllUsersURL += "admin/"; + getNumUsersURL += "admin/"; + } else { + return; + } + + getAllUsersURL += "user/getAllUsers"; + // get the response + const response = await axios + .get< + { + id: string; + type: string; + name?: string; + admin?: boolean; + publisher?: boolean; + exporter?: boolean; + email?: string; + phone?: string; + phoneextension?: string; + countrycode?: string; + username?: string; + model_usage_restriction?: string; + model_usage_frequency?: string; + model_max_tokens?: number; + model_max_response_time?: number; + }[] + >(getAllUsersURL, { + params: { + filterWord: searchTerm, + offset: offset, + limit: limit, + }, + }) + .catch((error) => { + throw Error(error); + }); + getNumUsersURL += "user/getNumUsers"; + const count = await axios.get(getNumUsersURL).catch((error) => { + throw Error(error); + }); + + // there was no response, that is an error + if (!response || !count) { + throw Error("No Response to get Members"); + } + + const finalResponse = { + users: response.data, + totalUsers: searchTerm !== "" ? response.data.length : count.data, + }; + + return finalResponse; + } + + /** + * @name editMemberInfo + * @param admin + * @param user + * @returns + */ + async editMemberInfo(admin: boolean, user: any) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + url += "user/editUser"; + + postData += "user=" + encodeURIComponent(JSON.stringify(user)); + + const response = await axios + .post(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }) + .catch((e) => { + throw Error(e); + }); + + return response; + } + + /** + * @name deleteMember + * @param admin + * @param userId + * @param userType + * @returns + */ + async deleteMember(admin: boolean, userId: string, userType: string) { + let url = `${Env.MODULE}/api/auth/`, + postData = ""; + + if (admin) { + url += "admin/"; + } + url += "user/deleteUser"; + + postData += "userId=" + encodeURIComponent(userId); + postData += "&type=" + encodeURIComponent(userType); + + const response = await axios.post(url, postData, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + /** + * @name createUser + * @param admin + * @param user + * @returns + */ + async createUser(admin: boolean, user: any) { + let url = `${Env.MODULE}/api/auth/`; + + if (admin) { + url += "admin/"; + } + url += "user/registerUser"; + + let newUserInfo = ""; + + if (user.id) { + newUserInfo += "userId=" + encodeURIComponent(user.id); + } + if (user.type) { + newUserInfo += "&type=" + encodeURIComponent(user.type); + } + if (user.type === "NATIVE") { + newUserInfo += "&username=" + encodeURIComponent(user.id); + } else if (user.username) { + newUserInfo += "&username=" + encodeURIComponent(user.username); + } + if (user.password) { + newUserInfo += "&password=" + encodeURIComponent(user.password); + } + if (user.admin) { + newUserInfo += "&admin=" + encodeURIComponent(user.admin); + } + if (user.publisher) { + newUserInfo += "&publisher=" + encodeURIComponent(user.publisher); + } + if (user.exporter) { + newUserInfo += "&exporter=" + encodeURIComponent(user.exporter); + } + if (user.name) { + newUserInfo += "&name=" + encodeURIComponent(user.name); + } + if (user.email) { + newUserInfo += "&email=" + encodeURIComponent(user.email); + } + if (user.phone) { + newUserInfo += "&phone=" + encodeURIComponent(user.phone); + } + if (user.phoneextension) { + newUserInfo += + "&phoneextension=" + encodeURIComponent(user.phoneextension); + } + + if (user.model_usage_restriction) { + if (user.model_usage_restriction === "null") { + user.model_usage_restriction = null; + } + newUserInfo += + "&modelUsageRestriction=" + + encodeURIComponent(user.model_usage_restriction); + } + if (user.model_usage_frequency) { + newUserInfo += + "&modelUsageFrequency=" + + encodeURIComponent(user.model_usage_frequency); + } + if (user.model_max_tokens) { + newUserInfo += + "&modelMaxTokens=" + encodeURIComponent(user.model_max_tokens); + } + if (user.model_max_response_time) { + newUserInfo += + "&modelMaxResponseTime=" + + encodeURIComponent(user.model_max_response_time); + } + + const response = await axios.post(url, newUserInfo, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }); + + return response; + } + + // api/auth/user/getUserAccessKeys + + /** + * Get access keys related to a user + */ + async getUserAccessKeys() { + const url = `${Env.MODULE}/api/auth/user/getUserAccessKeys`; + + const response = await axios + .get< + { + ACCESSKEY: string; + DATECREATED: string; + TOKENNAME: string; + LASTUSED?: string; + TOKENDESCRIPTION?: string; + }[] + >(url) + .catch((error) => { + throw Error(error); + }); + + return response.data; + } + + /** + * Get access keys related to a user + */ + async createUserAccessKey(tokenName: string, tokenDescription = "") { + const url = `${Env.MODULE}/api/auth/user/createUserAccessKey`; + let body = "tokenName=" + encodeURIComponent(tokenName); + if (tokenDescription) { + body += "&tokenDescription=" + encodeURIComponent(tokenDescription); + } + + const response = await axios + .post<{ + ACCESSKEY: string; + SECRETKEY: string; + DATECREATED: string; + LASTUSED: string; + TOKENNAME: string; + TOKENDESCRIPTION?: string; + }>(url, body, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }) + .catch((error) => { + throw Error(error); + }); + + return response.data; + } + + /** + * Get access keys related to a user + */ + async deleteUserAccessKeys(accessKey: string) { + const url = `${Env.MODULE}/api/auth/user/deleteUserAccessKey`; + + const body = "accessKey=" + encodeURIComponent(accessKey); + + const response = await axios + .post(url, body, { + headers: { + "content-type": "application/x-www-form-urlencoded", + }, + }) + .catch((error) => { + throw Error(error); + }); + + return response.data; + } } diff --git a/packages/client/src/stores/page/index.ts b/packages/client/src/stores/page/index.ts index 94760b9d14..94ffeeccf6 100644 --- a/packages/client/src/stores/page/index.ts +++ b/packages/client/src/stores/page/index.ts @@ -1,2 +1,2 @@ -export { PageStore } from './page.store'; -export type { PageStoreInterface } from './page.store'; +export type { PageStoreInterface } from "./page.store"; +export { PageStore } from "./page.store"; diff --git a/packages/client/src/stores/page/page.store.ts b/packages/client/src/stores/page/page.store.ts index ce62b7edd2..0f41117de2 100644 --- a/packages/client/src/stores/page/page.store.ts +++ b/packages/client/src/stores/page/page.store.ts @@ -1,171 +1,170 @@ -import { autorun, makeAutoObservable } from 'mobx'; - -import { PageCache } from './page.types'; +import { autorun, makeAutoObservable } from "mobx"; +import type { PageCache } from "./page.types"; const CACHE_KEY = `PAGE_STORE_CACHE--1`; export interface PageStoreInterface { - /** - * Navigation bar information - **/ - navbar: { - /** - * Save the element of the navbar - */ - element: HTMLElement; - - /** - * Show the logo - */ - logo: boolean; - - /** - * Show the search - */ - search: boolean; - }; - - /** - * Sidebar information - **/ - sidebar: { - /** - * Track if it is open or closed - */ - open: boolean; - - /** - * Track if it is pinned - */ - pinned: boolean; - }; + /** + * Navigation bar information + **/ + navbar: { + /** + * Save the element of the navbar + */ + element: HTMLElement; + + /** + * Show the logo + */ + logo: boolean; + + /** + * Show the search + */ + search: boolean; + }; + + /** + * Sidebar information + **/ + sidebar: { + /** + * Track if it is open or closed + */ + open: boolean; + + /** + * Track if it is pinned + */ + pinned: boolean; + }; } /** * Store that manages instances of the insights and handles applicaiton level querying */ export class PageStore { - private _store: PageStoreInterface = { - navbar: { - element: null, - logo: true, - search: true, - }, - sidebar: { - open: false, - pinned: false, - }, - }; - - constructor() { - // set from the catch - try { - const cached = JSON.parse( - localStorage.getItem(CACHE_KEY), - ) as PageCache; - - if (cached) { - this._store.sidebar.pinned = cached.sidebar.pinned; - } - } catch (e) { - // noop - } - - // make it observable - makeAutoObservable(this); - - // auto run and save to cache - autorun(() => { - try { - const item: PageCache = { - sidebar: { - pinned: this._store.sidebar.pinned, - }, - }; - - // save cache - localStorage.setItem(CACHE_KEY, JSON.stringify(item)); - } catch (e) { - // noop - } - }); - } - - /** - * Getters - */ - /** - * Get top navigation information - */ - get navbar() { - return this._store.navbar; - } - - /** - * Get sidebar information - */ - get sidebar() { - return this._store.sidebar; - } - - /** - * Actions - */ - /** - * Update the navbar logo - */ - setNavbarElement = (ele: HTMLElement) => { - this._store.navbar.element = ele; - }; - - /** - * Update the navbar logo - */ - updateNavbarLogo = (logo = true) => { - this._store.navbar.logo = logo; - }; - - /** - * Update the navbar search - */ - updateNavbarSearch = (search = true) => { - this._store.navbar.search = search; - }; - - /** - * Set the sidebar - */ - setSidebar = ( - content: PageStoreInterface['sidebar'] = { open: false, pinned: false }, - ) => { - this._store.sidebar = content; - }; - - /** - * Open the sidebar - */ - openSidebar = () => { - this._store.sidebar.open = true; - }; - - /** - * Close the sidebar - */ - closeSidebar = () => { - this._store.sidebar.open = false; - }; - - /** - * Pin the sidebar - */ - pinSidebar = () => { - this._store.sidebar.pinned = true; - }; - - /** - * Unpin the sidebar - */ - unpinSidebar = () => { - this._store.sidebar.pinned = false; - }; + private _store: PageStoreInterface = { + navbar: { + element: null, + logo: true, + search: true, + }, + sidebar: { + open: false, + pinned: false, + }, + }; + + constructor() { + // set from the catch + try { + const cached = JSON.parse( + localStorage.getItem(CACHE_KEY), + ) as PageCache; + + if (cached) { + this._store.sidebar.pinned = cached.sidebar.pinned; + } + } catch (e) { + // noop + } + + // make it observable + makeAutoObservable(this); + + // auto run and save to cache + autorun(() => { + try { + const item: PageCache = { + sidebar: { + pinned: this._store.sidebar.pinned, + }, + }; + + // save cache + localStorage.setItem(CACHE_KEY, JSON.stringify(item)); + } catch (e) { + // noop + } + }); + } + + /** + * Getters + */ + /** + * Get top navigation information + */ + get navbar() { + return this._store.navbar; + } + + /** + * Get sidebar information + */ + get sidebar() { + return this._store.sidebar; + } + + /** + * Actions + */ + /** + * Update the navbar logo + */ + setNavbarElement = (ele: HTMLElement) => { + this._store.navbar.element = ele; + }; + + /** + * Update the navbar logo + */ + updateNavbarLogo = (logo = true) => { + this._store.navbar.logo = logo; + }; + + /** + * Update the navbar search + */ + updateNavbarSearch = (search = true) => { + this._store.navbar.search = search; + }; + + /** + * Set the sidebar + */ + setSidebar = ( + content: PageStoreInterface["sidebar"] = { open: false, pinned: false }, + ) => { + this._store.sidebar = content; + }; + + /** + * Open the sidebar + */ + openSidebar = () => { + this._store.sidebar.open = true; + }; + + /** + * Close the sidebar + */ + closeSidebar = () => { + this._store.sidebar.open = false; + }; + + /** + * Pin the sidebar + */ + pinSidebar = () => { + this._store.sidebar.pinned = true; + }; + + /** + * Unpin the sidebar + */ + unpinSidebar = () => { + this._store.sidebar.pinned = false; + }; } diff --git a/packages/client/src/stores/page/page.types.ts b/packages/client/src/stores/page/page.types.ts index 5f94b972ce..1e8f7d2f00 100644 --- a/packages/client/src/stores/page/page.types.ts +++ b/packages/client/src/stores/page/page.types.ts @@ -1,5 +1,5 @@ export type PageCache = { - sidebar: { - pinned: boolean; - }; + sidebar: { + pinned: boolean; + }; }; diff --git a/packages/client/src/stores/root/index.ts b/packages/client/src/stores/root/index.ts index 7e33c862c6..ec1583283e 100644 --- a/packages/client/src/stores/root/index.ts +++ b/packages/client/src/stores/root/index.ts @@ -1 +1 @@ -export { RootStore } from './root.store'; +export { RootStore } from "./root.store"; diff --git a/packages/client/src/stores/root/root.store.ts b/packages/client/src/stores/root/root.store.ts index 9207ba1637..00af7d18d2 100644 --- a/packages/client/src/stores/root/root.store.ts +++ b/packages/client/src/stores/root/root.store.ts @@ -1,6 +1,5 @@ import { configure } from "mobx"; - -import { MonolithStore, ConfigStore } from "@/stores"; +import { ConfigStore, MonolithStore } from "@/stores"; configure({ enforceActions: "always", diff --git a/packages/client/src/stores/workspace/index.ts b/packages/client/src/stores/workspace/index.ts index 0b2dcba006..c88cc6f045 100644 --- a/packages/client/src/stores/workspace/index.ts +++ b/packages/client/src/stores/workspace/index.ts @@ -1,7 +1,6 @@ -export * from './workspace.types'; - -export { WorkspaceStore } from './workspace.store'; export type { - WorkspaceConfigInterface, - WorkspaceStoreInterface, -} from './workspace.store'; + WorkspaceConfigInterface, + WorkspaceStoreInterface, +} from "./workspace.store"; +export { WorkspaceStore } from "./workspace.store"; +export * from "./workspace.types"; diff --git a/packages/client/src/stores/workspace/workspace.store.ts b/packages/client/src/stores/workspace/workspace.store.ts index aa0b538faa..6676c2bb97 100644 --- a/packages/client/src/stores/workspace/workspace.store.ts +++ b/packages/client/src/stores/workspace/workspace.store.ts @@ -1,356 +1,354 @@ -import { makeAutoObservable, reaction } from 'mobx'; - -import { runPixel } from '@semoss/sdk/react'; - -import { Role } from '@/types'; -import { RootStore, WorkspaceOptions } from '@/stores'; -import { AppMetadata } from '@/components/app'; -import { IJsonModel, Model } from 'flexlayout-react'; +import { type IJsonModel, Model } from "flexlayout-react"; +import { makeAutoObservable, reaction } from "mobx"; +import { runPixel } from "@semoss/sdk/react"; +import type { AppMetadata } from "@/components/app"; +import type { RootStore, WorkspaceOptions } from "@/stores"; +import type { Role } from "@/types"; export interface WorkspaceStoreInterface { - /** - * ID of App - */ - appId: string; - - /** - * ID of Workspace Insight - */ - insightId: string; - - /** - * Show Loading or not - */ - isLoading: boolean; - - /** - * User's role relative to the app - */ - role: Role; - - /** - * Metadata associated with the loaded app - */ - metadata: AppMetadata; - - /** - * Optional Model Engine to use - */ - agentModelEngine: string; - - /** - * Type of the app - */ - type: 'BLOCKS' | 'CODE'; - - /** - * Model associated with the layout - **/ - model: Model | null; - - /** - * Overlay information - **/ - overlay: { - /** - * Track if the overlay is open or closed - */ - open: boolean; - - /** - * Options associated with the overlay - */ - options: { - /** - * Set the maxWidth of the overlay - */ - maxWidth: 'sm' | 'md' | 'lg' | 'xl' | null; - }; - - /** - * Content to display in the overlay - */ - content: () => JSX.Element; - }; + /** + * ID of App + */ + appId: string; + + /** + * ID of Workspace Insight + */ + insightId: string; + + /** + * Show Loading or not + */ + isLoading: boolean; + + /** + * User's role relative to the app + */ + role: Role; + + /** + * Metadata associated with the loaded app + */ + metadata: AppMetadata; + + /** + * Optional Model Engine to use + */ + agentModelEngine: string; + + /** + * Type of the app + */ + type: "BLOCKS" | "CODE"; + + /** + * Model associated with the layout + **/ + model: Model | null; + + /** + * Overlay information + **/ + overlay: { + /** + * Track if the overlay is open or closed + */ + open: boolean; + + /** + * Options associated with the overlay + */ + options: { + /** + * Set the maxWidth of the overlay + */ + maxWidth: "sm" | "md" | "lg" | "xl" | null; + }; + + /** + * Content to display in the overlay + */ + content: () => JSX.Element; + }; } export interface WorkspaceConfigInterface { - /** - * Get the ID of the connected app - */ - appId: string; - - /** - * Get the ID of the Insight tied to app workspace - */ - insightId: string; - - /** - * User's role relative to the app - */ - role: Role; - - /** - * Type of the app - */ - type: 'BLOCKS' | 'CODE'; - - /** - * Metadata associated with the loaded app - */ - metadata: AppMetadata; + /** + * Get the ID of the connected app + */ + appId: string; + + /** + * Get the ID of the Insight tied to app workspace + */ + insightId: string; + + /** + * User's role relative to the app + */ + role: Role; + + /** + * Type of the app + */ + type: "BLOCKS" | "CODE"; + + /** + * Metadata associated with the loaded app + */ + metadata: AppMetadata; } /** * Store that manages instances of the insights and handles applicaiton level querying */ export class WorkspaceStore { - private _root: RootStore; - private _store: WorkspaceStoreInterface = { - appId: '', - insightId: '', - isLoading: false, - role: 'READ_ONLY', - type: 'CODE', - agentModelEngine: '', - metadata: { - project_id: '', - project_name: '', - project_type: '', - project_cost: '', - project_global: '', - project_catalog_name: '', - project_created_by: '', - project_date_last_edited: '', - project_created_by_type: '', - project_date_created: '', - }, - model: null, - overlay: { - open: false, - options: { - maxWidth: 'sm', - }, - content: () => null, - }, - }; - - constructor(root: RootStore, config: WorkspaceConfigInterface) { - // register the root - this._root = root; - - // set the app and insight Id - this._store.appId = config.appId; - this._store.insightId = config.insightId; - this._store.type = config.type; - - // update the data - if (config.role) { - this._store.role = config.role; - } - - if (config.role) { - this._store.metadata = config.metadata; - } - - // make it observable - makeAutoObservable(this); - } - - /** - * Getters - */ - /** - * Get the ID of the connected app - */ - get appId() { - return this._store.appId; - } - - /** - * Get the ID of the workspace insight - */ - get insightId() { - return this._store.insightId; - } - - /** - * Get the agentModelEngine - */ - get agentModelEngine() { - return this._store.agentModelEngine; - } - - /** - * Get if the app is loading - */ - get isLoading() { - return this._store.isLoading; - } - - /** - * Get model - */ - get model() { - return this._store.model; - } - - /** - * Get the user's role in relation to the app - */ - get role() { - return this._store.role; - } - /** - * Type of the app - */ - get type() { - return this._store.type; - } - - /** - * Get metadata associated with the app - */ - get metadata() { - return this._store.metadata; - } - - /** - * The key for the local storage cache - */ - get cacheKey() { - return `smss-workspace--${this._store.appId}-v3`; - } - - /** - * Actions - */ - - /** - * runs pixel off of workspace insight - */ - runWorkspacePixel = async (command: string) => { - return await runPixel(command, this._store.insightId); - }; - - /** - * Load the workspace - * @param options - options to configure the workspace with - */ - load = (options: WorkspaceOptions): boolean => { - try { - // add the new layout - if (options.layout) { - this._store.model = Model.fromJson(options.layout); - } - return true; - } catch (e) { - console.error(e); - return false; - } - }; - - /** - * Load from the cache - */ - loadFromCache = (): boolean => { - // TODO::Version Check - - let isLoaded = false; - try { - const item = localStorage.getItem(this.cacheKey); - if (item) { - const options = JSON.parse(item) as WorkspaceOptions; - isLoaded = this.load(options); - } - } catch (e) { - console.error(e); - return false; - } - - return isLoaded; - }; - - /** - * Save the workspace to local storage - */ - saveToCache = (): void => { - try { - const options: WorkspaceOptions = { - version: '', - layout: this._store.model.toJson(), - }; - - // save cache - localStorage.setItem(this.cacheKey, JSON.stringify(options)); - } catch (e) { - console.error(e); - } - }; - - /** - * Set the loading screen for the app - * @param isLoading - true if loading screen is on - */ - setLoading = (isLoading: boolean) => { - this._store.isLoading = isLoading; - }; - - /** - * Update the layout - * - * @param id - id of the layout - * @param layout - layout that is being added - */ - updateLayout = (layout: IJsonModel) => { - this._store.model = Model.fromJson(layout); - - // trigger the save manually as the Model is recreated - this.saveToCache(); - }; - - /** - * Open the overlay - */ - openOverlay = ( - content: WorkspaceStoreInterface['overlay']['content'], - options: WorkspaceStoreInterface['overlay']['options'] = { - maxWidth: 'sm', - }, - ) => { - // open the overlay - this._store.overlay.open = true; - - // set the content - this._store.overlay.content = content; - this._store.overlay.options = options; - }; - - /** - * Close the overlay - */ - closeOverlay = () => { - // close the overlay - this._store.overlay.open = false; - - // clear the content - this._store.overlay.content = null; - }; - - /** - * Helpers - */ - /** - * Get overlay information associated with the workspace - */ - get overlay() { - return this._store.overlay; - } - - /** - * Set the agentModelEngine - */ - setAgentModelEngine = (id: string) => { - this._store.agentModelEngine = id; - }; + private _root: RootStore; + private _store: WorkspaceStoreInterface = { + appId: "", + insightId: "", + isLoading: false, + role: "READ_ONLY", + type: "CODE", + agentModelEngine: "", + metadata: { + project_id: "", + project_name: "", + project_type: "", + project_cost: "", + project_global: "", + project_catalog_name: "", + project_created_by: "", + project_date_last_edited: "", + project_created_by_type: "", + project_date_created: "", + }, + model: null, + overlay: { + open: false, + options: { + maxWidth: "sm", + }, + content: () => null, + }, + }; + + constructor(root: RootStore, config: WorkspaceConfigInterface) { + // register the root + this._root = root; + + // set the app and insight Id + this._store.appId = config.appId; + this._store.insightId = config.insightId; + this._store.type = config.type; + + // update the data + if (config.role) { + this._store.role = config.role; + } + + if (config.role) { + this._store.metadata = config.metadata; + } + + // make it observable + makeAutoObservable(this); + } + + /** + * Getters + */ + /** + * Get the ID of the connected app + */ + get appId() { + return this._store.appId; + } + + /** + * Get the ID of the workspace insight + */ + get insightId() { + return this._store.insightId; + } + + /** + * Get the agentModelEngine + */ + get agentModelEngine() { + return this._store.agentModelEngine; + } + + /** + * Get if the app is loading + */ + get isLoading() { + return this._store.isLoading; + } + + /** + * Get model + */ + get model() { + return this._store.model; + } + + /** + * Get the user's role in relation to the app + */ + get role() { + return this._store.role; + } + /** + * Type of the app + */ + get type() { + return this._store.type; + } + + /** + * Get metadata associated with the app + */ + get metadata() { + return this._store.metadata; + } + + /** + * The key for the local storage cache + */ + get cacheKey() { + return `smss-workspace--${this._store.appId}-v3`; + } + + /** + * Actions + */ + + /** + * runs pixel off of workspace insight + */ + runWorkspacePixel = async (command: string) => { + return await runPixel(command, this._store.insightId); + }; + + /** + * Load the workspace + * @param options - options to configure the workspace with + */ + load = (options: WorkspaceOptions): boolean => { + try { + // add the new layout + if (options.layout) { + this._store.model = Model.fromJson(options.layout); + } + return true; + } catch (e) { + console.error(e); + return false; + } + }; + + /** + * Load from the cache + */ + loadFromCache = (): boolean => { + // TODO::Version Check + + let isLoaded = false; + try { + const item = localStorage.getItem(this.cacheKey); + if (item) { + const options = JSON.parse(item) as WorkspaceOptions; + isLoaded = this.load(options); + } + } catch (e) { + console.error(e); + return false; + } + + return isLoaded; + }; + + /** + * Save the workspace to local storage + */ + saveToCache = (): void => { + try { + const options: WorkspaceOptions = { + version: "", + layout: this._store.model.toJson(), + }; + + // save cache + localStorage.setItem(this.cacheKey, JSON.stringify(options)); + } catch (e) { + console.error(e); + } + }; + + /** + * Set the loading screen for the app + * @param isLoading - true if loading screen is on + */ + setLoading = (isLoading: boolean) => { + this._store.isLoading = isLoading; + }; + + /** + * Update the layout + * + * @param id - id of the layout + * @param layout - layout that is being added + */ + updateLayout = (layout: IJsonModel) => { + this._store.model = Model.fromJson(layout); + + // trigger the save manually as the Model is recreated + this.saveToCache(); + }; + + /** + * Open the overlay + */ + openOverlay = ( + content: WorkspaceStoreInterface["overlay"]["content"], + options: WorkspaceStoreInterface["overlay"]["options"] = { + maxWidth: "sm", + }, + ) => { + // open the overlay + this._store.overlay.open = true; + + // set the content + this._store.overlay.content = content; + this._store.overlay.options = options; + }; + + /** + * Close the overlay + */ + closeOverlay = () => { + // close the overlay + this._store.overlay.open = false; + + // clear the content + this._store.overlay.content = null; + }; + + /** + * Helpers + */ + /** + * Get overlay information associated with the workspace + */ + get overlay() { + return this._store.overlay; + } + + /** + * Set the agentModelEngine + */ + setAgentModelEngine = (id: string) => { + this._store.agentModelEngine = id; + }; } diff --git a/packages/client/src/stores/workspace/workspace.types.ts b/packages/client/src/stores/workspace/workspace.types.ts index c5729d86a3..55206c905b 100644 --- a/packages/client/src/stores/workspace/workspace.types.ts +++ b/packages/client/src/stores/workspace/workspace.types.ts @@ -1,6 +1,6 @@ -import { IJsonModel } from 'flexlayout-react'; +import type { IJsonModel } from "flexlayout-react"; export interface WorkspaceOptions { - version: string; - layout: IJsonModel; + version: string; + layout: IJsonModel; } diff --git a/packages/client/src/testing/AppCards.spec.tsx b/packages/client/src/testing/AppCards.spec.tsx index 3c552ed514..d0b4cd8f43 100644 --- a/packages/client/src/testing/AppCards.spec.tsx +++ b/packages/client/src/testing/AppCards.spec.tsx @@ -1,12 +1,12 @@ -import { render, screen } from '@testing-library/react'; -import { expect, test } from 'vitest'; -import '@testing-library/jest-dom'; +import { render, screen } from "@testing-library/react"; +import { expect, test } from "vitest"; +import "@testing-library/jest-dom"; -import { ProjectTileCard } from '../components/app/AppCards'; +import { ProjectTileCard } from "../components/app/AppCards"; -test('app card display', async () => { - render(); +test("app card display", async () => { + render(); - const cardElement = await screen.getByText('app-card-title'); - expect(cardElement).toBeInTheDocument(); + const cardElement = await screen.getByText("app-card-title"); + expect(cardElement).toBeInTheDocument(); }); diff --git a/packages/client/src/testing/test.spec.ts b/packages/client/src/testing/test.spec.ts index b0b58e6b15..280fdee7b0 100644 --- a/packages/client/src/testing/test.spec.ts +++ b/packages/client/src/testing/test.spec.ts @@ -1,9 +1,9 @@ // Simple test to validate that vitest is working -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from "vitest"; -describe('vitest setup check', () => { - it('should run a basic test', () => { - //an easy passing test - expect(1 + 1).toBe(2); - }); +describe("vitest setup check", () => { + it("should run a basic test", () => { + //an easy passing test + expect(1 + 1).toBe(2); + }); }); diff --git a/packages/client/src/types/index.ts b/packages/client/src/types/index.ts index fcb073fefc..eea524d655 100644 --- a/packages/client/src/types/index.ts +++ b/packages/client/src/types/index.ts @@ -1 +1 @@ -export * from './types'; +export * from "./types"; diff --git a/packages/client/src/types/types.d.ts b/packages/client/src/types/types.d.ts index 6bd548f821..97e30d0bc3 100644 --- a/packages/client/src/types/types.d.ts +++ b/packages/client/src/types/types.d.ts @@ -1,88 +1,88 @@ export type Role = - | 'OWNER' - | 'EDIT' - | 'VIEWER' - | 'READ_ONLY' - | 'DISCOVERABLE' - | 'EDITOR'; + | "OWNER" + | "EDIT" + | "VIEWER" + | "READ_ONLY" + | "DISCOVERABLE" + | "EDITOR"; export interface PixelCommand { - type: string; - components: any[]; - terminal?: boolean; - meta?: boolean; + type: string; + components: any[]; + terminal?: boolean; + meta?: boolean; } /** * All types used in the app */ -export type ALL_TYPES = 'APP' | ENGINE_TYPES; +export type ALL_TYPES = "APP" | ENGINE_TYPES; /** * Engine types used in the app */ export type ENGINE_TYPES = - | 'DATABASE' - | 'STORAGE' - | 'MODEL' - | 'VECTOR' - | 'FUNCTION'; + | "DATABASE" + | "STORAGE" + | "MODEL" + | "VECTOR" + | "FUNCTION"; export type Join = K extends string | number - ? P extends string | number - ? `${K}${'' extends P ? '' : '.'}${P}` - : never - : never; + ? P extends string | number + ? `${K}${"" extends P ? "" : "."}${P}` + : never + : never; export type Idx = K extends keyof T - ? T[K] - : number extends keyof T - ? K extends `${number}` - ? T[number] - : never - : never; + ? T[K] + : number extends keyof T + ? K extends `${number}` + ? T[number] + : never + : never; export type Prev = [ - never, - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - ...0[], + never, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + ...0[], ]; export type Paths = [D] extends [never] - ? never - : T extends object - ? { - [K in keyof T]-?: K extends string | number - ? `${K}` | Join> - : never; - }[keyof T] - : ''; + ? never + : T extends object + ? { + [K in keyof T]-?: K extends string | number + ? `${K}` | Join> + : never; + }[keyof T] + : ""; export type PathValue< - T, - P extends Paths, + T, + P extends Paths, > = P extends `${infer Key}.${infer Rest}` - ? Rest extends Paths, 4> - ? PathValue, Rest> - : never - : Idx; + ? Rest extends Paths, 4> + ? PathValue, Rest> + : never + : Idx; diff --git a/packages/client/src/utility/general.ts b/packages/client/src/utility/general.ts index 9aa1d56ed3..0c060614de 100644 --- a/packages/client/src/utility/general.ts +++ b/packages/client/src/utility/general.ts @@ -1,47 +1,45 @@ -import { useEffect, useMemo, useRef } from 'react'; - -import { Env } from '@semoss/sdk/react'; - -import { Role } from '@/types'; +import { useEffect, useMemo, useRef } from "react"; +import { Env } from "@semoss/sdk/react"; +import type { Role } from "@/types"; /** * @desc splits a string at the period * Used in the UI Builder and notebook */ -export const splitAtPeriod = (str, side = 'left') => { - const indexOfPeriod = str.indexOf('.'); - if (indexOfPeriod === -1) { - return str; // No period found, return the entire string - } - - if (side === 'left') { - return str.substring(0, indexOfPeriod); - } else if (side === 'right') { - return str.substring(indexOfPeriod + 1); - } else { - throw new Error("Invalid side argument. Choose 'left' or 'right'"); - } +export const splitAtPeriod = (str, side = "left") => { + const indexOfPeriod = str.indexOf("."); + if (indexOfPeriod === -1) { + return str; // No period found, return the entire string + } + + if (side === "left") { + return str.substring(0, indexOfPeriod); + } else if (side === "right") { + return str.substring(indexOfPeriod + 1); + } else { + throw new Error("Invalid side argument. Choose 'left' or 'right'"); + } }; /** * @desc lowercases the whole string */ export const lowercase = (str) => { - if (str.length === 0 || str.length === 1) { - return str.toLowerCase(); - } - // Identify word boundaries using regular expression - const regex = /\b\w+\b/g; - const match = regex.exec(str); - if (!match) { - return str; - } - const word = match[0].toLowerCase(); - return str.replace(regex, word); + if (str.length === 0 || str.length === 1) { + return str.toLowerCase(); + } + // Identify word boundaries using regular expression + const regex = /\b\w+\b/g; + const match = regex.exec(str); + if (!match) { + return str; + } + const word = match[0].toLowerCase(); + return str.replace(regex, word); }; export const capitalizeFirstLetter = (str) => { - return str.replace(/\w{1}/, (match) => match.toUpperCase()); + return str.replace(/\w{1}/, (match) => match.toUpperCase()); }; /* @@ -49,9 +47,9 @@ export const capitalizeFirstLetter = (str) => { * "hello world" --> "Hello World" */ export const toTitleCase = (str) => { - return str.replace(/\w\S*/g, (txt) => { - return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); - }); + return str.replace(/\w\S*/g, (txt) => { + return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); + }); }; /** @@ -59,174 +57,174 @@ export const toTitleCase = (str) => { * "this_is_a_string" --> "This is a string" */ export const removeUnderscores = (str: string) => { - let i; - const frags = str.split('_'); - for (i = 0; i < frags.length; i++) { - frags[i] = frags[i].charAt(0).toUpperCase() + frags[i].slice(1); - } - return frags.join(' '); + let i; + const frags = str.split("_"); + for (i = 0; i < frags.length; i++) { + frags[i] = frags[i].charAt(0).toUpperCase() + frags[i].slice(1); + } + return frags.join(" "); }; -export const formatPermission = (permission: Role | ''): string => { - const errorString = 'No permission found'; - - if (!permission) { - return errorString; - } - - switch (permission) { - case 'OWNER': - return 'Author'; - case 'EDIT': - case 'EDITOR': - return 'Editor'; - case 'READ_ONLY': - case 'VIEWER': - return 'Read-Only'; - case 'DISCOVERABLE': - return 'Discoverable'; - default: - return errorString; - } +export const formatPermission = (permission: Role | ""): string => { + const errorString = "No permission found"; + + if (!permission) { + return errorString; + } + + switch (permission) { + case "OWNER": + return "Author"; + case "EDIT": + case "EDITOR": + return "Editor"; + case "READ_ONLY": + case "VIEWER": + return "Read-Only"; + case "DISCOVERABLE": + return "Discoverable"; + default: + return errorString; + } }; /** * @desc Copies string to clipboard */ export const copyTextToClipboard = (text: string, notificationService) => { - try { - navigator.clipboard.writeText(text); - - notificationService.add({ - color: 'success', - message: 'Succesfully copied to clipboard', - }); - } catch (e) { - notificationService.add({ - color: 'error', - message: e.message, - }); - } + try { + navigator.clipboard.writeText(text); + + notificationService.add({ + color: "success", + message: "Succesfully copied to clipboard", + }); + } catch (e) { + notificationService.add({ + color: "error", + message: e.message, + }); + } }; export const getSDKSnippet = ( - type: 'py' | 'js', - accessKey?: string, - secretKey?: string, + type: "py" | "js", + accessKey?: string, + secretKey?: string, ) => { - if (type === 'py') { - return ` + if (type === "py") { + return ` # import the ai platform package import ai_server # pass in your access and secret keys to authenticate server_connection=ai_server.ServerClient( access_key="${ - accessKey ? accessKey : '' - }", # example: "d0033d40-ea83-4083-96ce-17a01451f831" + accessKey ? accessKey : "" + }", # example: "d0033d40-ea83-4083-96ce-17a01451f831" secret_key="${ - secretKey ? secretKey : '' - }", # example: "c2b3fae8-20d1-458c-8565-30ae935c4dfb" + secretKey ? secretKey : "" + }", # example: "c2b3fae8-20d1-458c-8565-30ae935c4dfb" base="${Env.MODULE}/api" ) `; - } else { - return ` + } else { + return ` # .env MODULE="${Env.MODULE}" #.env.local -ACCESS_KEY="${accessKey ? accessKey : ''}" -SECRET_KEY="${secretKey ? secretKey : ''}" +ACCESS_KEY="${accessKey ? accessKey : ""}" +SECRET_KEY="${secretKey ? secretKey : ""}" `; - } + } }; const debounce = (func, wait) => { - let timeout; + let timeout; - return function executedFunction(...args) { - const later = () => { - clearTimeout(timeout); - func(...args); - }; + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; }; /** * @desc useDebounce utility function returns a debounced function */ export const debounced = (callback, delay) => { - const ref = useRef(() => { - console.log('ref'); - }); + const ref = useRef(() => { + console.log("ref"); + }); - useEffect(() => { - ref.current = callback; - }, [callback]); + useEffect(() => { + ref.current = callback; + }, [callback]); - const debouncedCallback = useMemo(() => { - const func = () => { - ref.current?.(); - }; + const debouncedCallback = useMemo(() => { + const func = () => { + ref.current?.(); + }; - return debounce(func, delay); - }, []); + return debounce(func, delay); + }, []); - return debouncedCallback; + return debouncedCallback; }; /** * @desc Checks if output and verify if its a JSON object */ export const isOutputJSON = (output: unknown) => { - if (typeof output === 'object' && output !== null) { - return output; - } - if (typeof output === 'string') { - try { - return JSON.parse(output); - } catch (e) { - const validateJsonString = output.replace(/'/g, '"'); - try { - return JSON.parse(validateJsonString); - } catch (InnerError) { - return null; - } - } - } - return null; + if (typeof output === "object" && output !== null) { + return output; + } + if (typeof output === "string") { + try { + return JSON.parse(output); + } catch (e) { + const validateJsonString = output.replace(/'/g, '"'); + try { + return JSON.parse(validateJsonString); + } catch (InnerError) { + return null; + } + } + } + return null; }; export const permissionPriorityMapper = (permission: string | number) => { - if (!permission) { - console.warn('No permission'); - return; - } - - switch (permission) { - case 1: - case 'OWNER': - return { permission: 'Author', priority: 1 }; - case 'Author': - return { permission: 'OWNER', priority: 1 }; - - case 2: - case 'EDIT': - return { permission: 'Editor', priority: 2 }; - case 'Editor': - return { permission: 'EDIT', priority: 2 }; - - case 3: - case 'READ_ONLY': - return { permission: 'Read-Only', priority: 3 }; - case 'Read-Only': - return { permission: 'READ_ONLY', priority: 3 }; - - default: - return { permission: '', priority: 0 }; - } + if (!permission) { + console.warn("No permission"); + return; + } + + switch (permission) { + case 1: + case "OWNER": + return { permission: "Author", priority: 1 }; + case "Author": + return { permission: "OWNER", priority: 1 }; + + case 2: + case "EDIT": + return { permission: "Editor", priority: 2 }; + case "Editor": + return { permission: "EDIT", priority: 2 }; + + case 3: + case "READ_ONLY": + return { permission: "Read-Only", priority: 3 }; + case "Read-Only": + return { permission: "READ_ONLY", priority: 3 }; + + default: + return { permission: "", priority: 0 }; + } }; diff --git a/packages/client/src/utility/index.ts b/packages/client/src/utility/index.ts index 6980558c51..ab89ddc3eb 100644 --- a/packages/client/src/utility/index.ts +++ b/packages/client/src/utility/index.ts @@ -1,3 +1,3 @@ -export * from './object'; -export * from './promise'; -export * from './general'; +export * from "./general"; +export * from "./object"; +export * from "./promise"; diff --git a/packages/client/src/utility/object.ts b/packages/client/src/utility/object.ts index 5c74da11ae..9f9864c311 100644 --- a/packages/client/src/utility/object.ts +++ b/packages/client/src/utility/object.ts @@ -7,29 +7,26 @@ * @returns path to the attribute */ export const getValueByPath = (target: T, path: string) => { - if (!(target instanceof Object)) { - return target; - } - - if (path.length === 0) { - return target; - } - - const pathArr = path.split('.'); - for (const p of pathArr) { - // skip if it isn't an object or the property does not exist - if ( - !(target instanceof Object) || - !Object.prototype.hasOwnProperty.call(target, p) - ) { - return undefined; - } - - // move forward - target = target[p]; - } - - return target; + if (!(target instanceof Object)) { + return target; + } + + if (path.length === 0) { + return target; + } + + const pathArr = path.split("."); + for (const p of pathArr) { + // skip if it isn't an object or the property does not exist + if (!(target instanceof Object) || !Object.hasOwn(target, p)) { + return undefined; + } + + // move forward + target = target[p]; + } + + return target; }; /** @@ -40,38 +37,38 @@ export const getValueByPath = (target: T, path: string) => { * @param path - value to set */ export const setValueByPath = ( - target: T, - path: string, - value: unknown, + target: T, + path: string, + value: unknown, ) => { - // get the keys - const p = path.split('.'); - - // get the last key. If there is none, ignore it - const last = p.pop(); - if (!last) { - return; - } - - // traverse to the correct element - let current = target; - while (p.length) { - const key = p.shift(); - - if (!key) { - return; - } - - // create the object if the key doesn't exist. This will allow partials - if (!current[key]) { - current[key] = {}; - } - - current = current[key]; - } - - // set the value - current[last] = value; + // get the keys + const p = path.split("."); + + // get the last key. If there is none, ignore it + const last = p.pop(); + if (!last) { + return; + } + + // traverse to the correct element + let current = target; + while (p.length) { + const key = p.shift(); + + if (!key) { + return; + } + + // create the object if the key doesn't exist. This will allow partials + if (!current[key]) { + current[key] = {}; + } + + current = current[key]; + } + + // set the value + current[last] = value; }; /** @@ -83,37 +80,37 @@ export const setValueByPath = ( * @returns a copied object */ export const copy = ( - instance: T, - intercept: (instance: unknown) => unknown = (instance) => instance, + instance: T, + intercept: (instance: unknown) => unknown = (instance) => instance, ): T => { - // intercept the instance and update it if relevant - instance = intercept(instance) as T; - - if (!instance) { - return instance; - } - - if (instance instanceof Date) { - return new Date(instance.getTime()) as unknown as T; - } - - if (instance instanceof Array) { - return instance.map((c) => { - return copy(c, intercept); - }) as unknown as T; - } - - if (instance instanceof Object) { - const copied: { [key: string]: unknown } = {}; - for (const k in instance) { - copied[k] = copy( - (instance as Record)[k], - intercept, - ); - } - - return copied as unknown as T; - } - - return instance; + // intercept the instance and update it if relevant + instance = intercept(instance) as T; + + if (!instance) { + return instance; + } + + if (instance instanceof Date) { + return new Date(instance.getTime()) as unknown as T; + } + + if (instance instanceof Array) { + return instance.map((c) => { + return copy(c, intercept); + }) as unknown as T; + } + + if (instance instanceof Object) { + const copied: { [key: string]: unknown } = {}; + for (const k in instance) { + copied[k] = copy( + (instance as Record)[k], + intercept, + ); + } + + return copied as unknown as T; + } + + return instance; }; diff --git a/packages/client/src/utility/promise.ts b/packages/client/src/utility/promise.ts index b87fb3b52f..e829650166 100644 --- a/packages/client/src/utility/promise.ts +++ b/packages/client/src/utility/promise.ts @@ -4,43 +4,43 @@ * @returns */ export const cancellablePromise = ( - executor: () => Promise, + executor: () => Promise, ): { - promise: Promise; - cancel: () => void; + promise: Promise; + cancel: () => void; } => { - // track if it is cancelled or not - let cancelled = false; + // track if it is cancelled or not + let cancelled = false; - // track a timeout to delay execution - let timeout: ReturnType | null = null; + // track a timeout to delay execution + let timeout: ReturnType | null = null; - return { - promise: new Promise((resolve, reject) => { - // wrap in a timeout to execute after the current thread is done - timeout = setTimeout(async () => { - try { - const response = await executor(); + return { + promise: new Promise((resolve, reject) => { + // wrap in a timeout to execute after the current thread is done + timeout = setTimeout(async () => { + try { + const response = await executor(); - // ignore if cancelled - if (cancelled) { - return; - } + // ignore if cancelled + if (cancelled) { + return; + } - return resolve(response); - } catch (err) { - return reject(err); - } - }, 0); - }), - cancel: () => { - // clear the timeout if it's there - if (timeout) { - clearTimeout(timeout); - } + return resolve(response); + } catch (err) { + return reject(err); + } + }, 0); + }), + cancel: () => { + // clear the timeout if it's there + if (timeout) { + clearTimeout(timeout); + } - // mark as cancelled - cancelled = true; - }, - }; + // mark as cancelled + cancelled = true; + }, + }; }; diff --git a/packages/client/tsconfig.json b/packages/client/tsconfig.json index 6eeaa10e83..a54a8c3300 100644 --- a/packages/client/tsconfig.json +++ b/packages/client/tsconfig.json @@ -1,28 +1,32 @@ { - "compilerOptions": { - /* Lang and Env */ - "lib": ["ES2022", "dom"], - "target": "es6", - "jsx": "react-jsx", - "types": ["vite/client", "vitest/globals", "@testing-library/jest-dom/vitest"], + "compilerOptions": { + /* Lang and Env */ + "lib": ["ES2022", "dom"], + "target": "es6", + "jsx": "react-jsx", + "types": [ + "vite/client", + "vitest/globals", + "@testing-library/jest-dom/vitest" + ], - /* Modules */ - "module": "esnext", - "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true, - "resolveJsonModule": true, + /* Modules */ + "module": "esnext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true, - /* Skip */ - "skipLibCheck": true, - "allowJs": true, - "esModuleInterop": true, - "isolatedModules": true, + /* Skip */ + "skipLibCheck": true, + "allowJs": true, + "esModuleInterop": true, + "isolatedModules": true, - /* Lang and Env */ - "paths": { - "@/*": ["./src/*"], - } - }, - "include": ["src"], - "exclude": ["dist", "node_modules", "**/*.spec.ts*"] + /* Lang and Env */ + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"], + "exclude": ["dist", "node_modules", "**/*.spec.ts*"] } diff --git a/packages/client/vite.config.ts b/packages/client/vite.config.ts index a8b09bc54d..4b4e633db5 100644 --- a/packages/client/vite.config.ts +++ b/packages/client/vite.config.ts @@ -1,42 +1,42 @@ -import { defineConfig, loadEnv } from 'vite'; -import react from '@vitejs/plugin-react'; -import { resolve } from 'node:path'; +import react from "@vitejs/plugin-react"; +import { defineConfig, loadEnv } from "vite"; +import { resolve } from "node:path"; export default defineConfig(({ mode }) => { - const env = loadEnv(mode, process.cwd(), ''); + const env = loadEnv(mode, process.cwd(), ""); - const isProduction = mode === 'production'; + const isProduction = mode === "production"; - const MODULE = env.MODULE; - const ENDPOINT = env.ENDPOINT; + const MODULE = env.MODULE; + const ENDPOINT = env.ENDPOINT; - return { - base: './', - plugins: [react({ include: /\.(js|jsx|ts|tsx)$/ })], - resolve: { - alias: [{ find: '@', replacement: resolve(__dirname, './src') }], - }, - define: { - 'import.meta.env.MODULE': JSON.stringify(MODULE), - }, - build: { - minify: isProduction, - commonjsOptions: { transformMixedEsModules: true }, - }, - server: { - proxy: { - [MODULE]: { - target: ENDPOINT, - changeOrigin: true, - secure: false, - preserveHeaderKeyCase: true, - }, - }, - }, - test: { - environment: 'jsdom', - globals: true, - setupFiles: ['./vitest.setup.ts'], - }, - }; + return { + base: "./", + plugins: [react({ include: /\.(js|jsx|ts|tsx)$/ })], + resolve: { + alias: [{ find: "@", replacement: resolve(__dirname, "./src") }], + }, + define: { + "import.meta.env.MODULE": JSON.stringify(MODULE), + }, + build: { + minify: isProduction, + commonjsOptions: { transformMixedEsModules: true }, + }, + server: { + proxy: { + [MODULE]: { + target: ENDPOINT, + changeOrigin: true, + secure: false, + preserveHeaderKeyCase: true, + }, + }, + }, + test: { + environment: "jsdom", + globals: true, + setupFiles: ["./vitest.setup.ts"], + }, + }; }); diff --git a/packages/client/vitest.setup.ts b/packages/client/vitest.setup.ts index 56d063b1df..89f026f54a 100644 --- a/packages/client/vitest.setup.ts +++ b/packages/client/vitest.setup.ts @@ -1,32 +1,32 @@ // src/test-setup.ts -import { vi } from 'vitest'; +import { vi } from "vitest"; // Mock canvas getContext HTMLCanvasElement.prototype.getContext = vi.fn(() => ({ - fillRect: vi.fn(), - clearRect: vi.fn(), - getImageData: vi.fn(() => ({ - data: new Array(4), - })), - putImageData: vi.fn(), - createImageData: vi.fn(() => ({})), - setTransform: vi.fn(), - drawImage: vi.fn(), - save: vi.fn(), - fillText: vi.fn(), - restore: vi.fn(), - beginPath: vi.fn(), - moveTo: vi.fn(), - lineTo: vi.fn(), - closePath: vi.fn(), - stroke: vi.fn(), - translate: vi.fn(), - scale: vi.fn(), - rotate: vi.fn(), - arc: vi.fn(), - fill: vi.fn(), - measureText: vi.fn(() => ({ width: 0 })), - transform: vi.fn(), - rect: vi.fn(), - clip: vi.fn(), + fillRect: vi.fn(), + clearRect: vi.fn(), + getImageData: vi.fn(() => ({ + data: new Array(4), + })), + putImageData: vi.fn(), + createImageData: vi.fn(() => ({})), + setTransform: vi.fn(), + drawImage: vi.fn(), + save: vi.fn(), + fillText: vi.fn(), + restore: vi.fn(), + beginPath: vi.fn(), + moveTo: vi.fn(), + lineTo: vi.fn(), + closePath: vi.fn(), + stroke: vi.fn(), + translate: vi.fn(), + scale: vi.fn(), + rotate: vi.fn(), + arc: vi.fn(), + fill: vi.fn(), + measureText: vi.fn(() => ({ width: 0 })), + transform: vi.fn(), + rect: vi.fn(), + clip: vi.fn(), })) as any; diff --git a/packages/playground/src/App.tsx b/packages/playground/src/App.tsx index 52059593ba..2ccb8cdeee 100644 --- a/packages/playground/src/App.tsx +++ b/packages/playground/src/App.tsx @@ -1,29 +1,28 @@ -import { Env, InsightProvider } from '@semoss/sdk/react'; - -import { Notification, styled, ThemeProvider } from '@semoss/ui'; -import { Router } from '@/pages'; +import { Env, InsightProvider } from "@semoss/sdk/react"; +import { Notification, styled, ThemeProvider } from "@semoss/ui"; +import { Router } from "@/pages"; // use the environment variable to set the module Env.update({ - MODULE: import.meta.env.MODULE || '/Monolith', + MODULE: import.meta.env.MODULE || "/Monolith", }); -const StyledMain = styled('div')(({ theme }) => ({ - position: 'absolute', - inset: 0, - background: theme.palette.background.default, +const StyledMain = styled("div")(({ theme }) => ({ + position: "absolute", + inset: 0, + background: theme.palette.background.default, })); export const App = () => { - return ( - - - - - - - - - - ); + return ( + + + + + + + + + + ); }; diff --git a/packages/playground/src/components/common/RightMenu/RightMenu.tsx b/packages/playground/src/components/common/RightMenu/RightMenu.tsx index edf40178f0..03947dc618 100644 --- a/packages/playground/src/components/common/RightMenu/RightMenu.tsx +++ b/packages/playground/src/components/common/RightMenu/RightMenu.tsx @@ -1,78 +1,78 @@ -import { styled, Stack, IconButton } from '@semoss/ui'; -import { Close } from '@mui/icons-material'; +import { Close } from "@mui/icons-material"; +import { IconButton, Stack, styled } from "@semoss/ui"; -const StyledRightMenu = styled('div')(({ theme }) => ({ - display: 'flex', - flexDirection: 'column', - position: 'relative', - height: '100%', - width: '100%', - borderRadius: theme.shape.borderRadius, - overflow: 'hidden', +const StyledRightMenu = styled("div")(({ theme }) => ({ + display: "flex", + flexDirection: "column", + position: "relative", + height: "100%", + width: "100%", + borderRadius: theme.shape.borderRadius, + overflow: "hidden", })); export const StyledRightMenuHeader = styled(Stack)(({ theme }) => ({ - position: 'sticky', - top: 0, - height: theme.spacing(9), - width: '100%', - padding: theme.spacing(2), - background: theme.palette.background.default, - zIndex: 1, + position: "sticky", + top: 0, + height: theme.spacing(9), + width: "100%", + padding: theme.spacing(2), + background: theme.palette.background.default, + zIndex: 1, })); -export const StyledRightMenuContent = styled('div', { - shouldForwardProp: (prop) => prop !== 'mode', -})<{ mode: RightMenuProps['mode'] }>(({ theme, mode }) => ({ - flex: mode === 'fixed' ? 1 : 'initial', - width: '100%', - paddingRight: theme.spacing(2), - paddingLeft: theme.spacing(2), - paddingBottom: theme.spacing(2), - display: 'flex', - flexDirection: 'column', - gap: theme.spacing(2), - background: theme.palette.background.default, - overflowX: 'hidden', - overflowY: 'auto', +export const StyledRightMenuContent = styled("div", { + shouldForwardProp: (prop) => prop !== "mode", +})<{ mode: RightMenuProps["mode"] }>(({ theme, mode }) => ({ + flex: mode === "fixed" ? 1 : "initial", + width: "100%", + paddingRight: theme.spacing(2), + paddingLeft: theme.spacing(2), + paddingBottom: theme.spacing(2), + display: "flex", + flexDirection: "column", + gap: theme.spacing(2), + background: theme.palette.background.default, + overflowX: "hidden", + overflowY: "auto", })); interface RightMenuProps { - /** Mode */ - mode?: 'fluid' | 'fixed'; + /** Mode */ + mode?: "fluid" | "fixed"; - /** Header in the menu */ - header: React.ReactNode; + /** Header in the menu */ + header: React.ReactNode; - /** Content */ - children: React.ReactNode; + /** Content */ + children: React.ReactNode; - /** Close the Menu */ - onClose?: () => void; + /** Close the Menu */ + onClose?: () => void; } export const RightMenu = (props: RightMenuProps) => { - const { children, mode = 'fluid', header, onClose } = props; - return ( - - - {header ? header : null} - { - onClose(); - }} - > - - - - - {children} - - - ); + const { children, mode = "fluid", header, onClose } = props; + return ( + + + {header ? header : null} + { + onClose(); + }} + > + + + + + {children} + + + ); }; diff --git a/packages/playground/src/components/common/RightMenu/index.ts b/packages/playground/src/components/common/RightMenu/index.ts index 0c1ff6dc2c..37d5eb1411 100644 --- a/packages/playground/src/components/common/RightMenu/index.ts +++ b/packages/playground/src/components/common/RightMenu/index.ts @@ -1,3 +1,3 @@ -import { RightMenu } from './RightMenu'; +import { RightMenu } from "./RightMenu"; export { RightMenu }; diff --git a/packages/playground/src/components/common/Sidebar/Sidebar.tsx b/packages/playground/src/components/common/Sidebar/Sidebar.tsx index 4d2c6a0eb8..6ff9cc45df 100644 --- a/packages/playground/src/components/common/Sidebar/Sidebar.tsx +++ b/packages/playground/src/components/common/Sidebar/Sidebar.tsx @@ -1,310 +1,313 @@ import { - Add, - MenuOpenRounded, - MenuRounded, - MoreVertOutlined, - PublicOutlined, -} from '@mui/icons-material'; -import { useInsight } from '@semoss/sdk/react'; + Add, + MenuOpenRounded, + MenuRounded, + MoreVertOutlined, + PublicOutlined, +} from "@mui/icons-material"; +import { observer } from "mobx-react-lite"; +import React, { useState } from "react"; +import { Link } from "react-router-dom"; +import { useInsight } from "@semoss/sdk/react"; import { - Avatar, - Button, - Drawer, - IconButton, - List, - Menu, - MenuItem, - Stack, - styled, - Typography, -} from '@semoss/ui'; -import { observer } from 'mobx-react-lite'; -import React, { useState } from 'react'; -import { Link } from 'react-router-dom'; -import LOGO from '@/assets/img/logo.svg'; -import LOGO_FULL from '@/assets/img/logo_full.svg'; -import { useCacheState, useChat } from '@/hooks'; -import { SidebarItem } from './SidebarItem'; + Avatar, + Button, + Drawer, + IconButton, + List, + Menu, + MenuItem, + Stack, + styled, + Typography, +} from "@semoss/ui"; +import LOGO from "@/assets/img/logo.svg"; +import LOGO_FULL from "@/assets/img/logo_full.svg"; +import { useCacheState, useChat } from "@/hooks"; +import { SidebarItem } from "./SidebarItem"; -const APP_NAME = import.meta.env.VITE_APP_NAME ? import.meta.env.VITE_APP_NAME : ''; -const LOGO_PATH = import.meta.env.VITE_LOGO_PATH ? import.meta.env.VITE_LOGO_PATH : ''; +const APP_NAME = import.meta.env.VITE_APP_NAME + ? import.meta.env.VITE_APP_NAME + : ""; +const LOGO_PATH = import.meta.env.VITE_LOGO_PATH + ? import.meta.env.VITE_LOGO_PATH + : ""; const LOGO_FULL_PATH = import.meta.env.VITE_LOGO_FULL_PATH - ? import.meta.env.VITE_LOGO_FULL_PATH - : ''; + ? import.meta.env.VITE_LOGO_FULL_PATH + : ""; const DRAWER_OPEN_WIDTH = 320; const StyledAvatar = styled(Avatar)(({ theme }) => ({ - fontSize: '14px', - fontWeight: 400, - letterSpacing: '.1px', - lineHeight: '48px', - height: theme.spacing(4), - width: theme.spacing(4), - background: theme.palette.primary.main, + fontSize: "14px", + fontWeight: 400, + letterSpacing: ".1px", + lineHeight: "48px", + height: theme.spacing(4), + width: theme.spacing(4), + background: theme.palette.primary.main, })); const StyledButton = styled(Button)(({ theme }) => ({ - height: theme.spacing(6), - color: theme.palette.text.primary, - background: theme.palette.background.paper, - borderWidth: '1px', - borderStyle: 'solid', - borderColor: theme.palette.secondary.border, - borderRadius: theme.shape.borderRadiusLg, + height: theme.spacing(6), + color: theme.palette.text.primary, + background: theme.palette.background.paper, + borderWidth: "1px", + borderStyle: "solid", + borderColor: theme.palette.secondary.border, + borderRadius: theme.shape.borderRadiusLg, })) as unknown as typeof Button; const StyledActions = styled(Stack)(({ theme }) => ({ - height: '100%', - position: 'relative', - background: 'transparent', - paddingTop: theme.spacing(3), - paddingRight: theme.spacing(2), - paddingBottom: theme.spacing(3), - paddingLeft: theme.spacing(3), - zIndex: 0, + height: "100%", + position: "relative", + background: "transparent", + paddingTop: theme.spacing(3), + paddingRight: theme.spacing(2), + paddingBottom: theme.spacing(3), + paddingLeft: theme.spacing(3), + zIndex: 0, })); const StyledSidebar = styled(Drawer)(() => ({ - flexShrink: 0, - whiteSpace: 'nowrap', - boxSizing: 'border-box', - '& .MuiDrawer-paper': { - width: DRAWER_OPEN_WIDTH, - borderRadius: '0px', - boxShadow: 'none', - border: 'none', - }, - variants: [ - { - props: ({ variant }) => variant === 'permanent', - style: { - width: DRAWER_OPEN_WIDTH, - '& .MuiDrawer-paper': { - backgroundColor: 'transparent', - }, - }, - }, - ], + flexShrink: 0, + whiteSpace: "nowrap", + boxSizing: "border-box", + "& .MuiDrawer-paper": { + width: DRAWER_OPEN_WIDTH, + borderRadius: "0px", + boxShadow: "none", + border: "none", + }, + variants: [ + { + props: ({ variant }) => variant === "permanent", + style: { + width: DRAWER_OPEN_WIDTH, + "& .MuiDrawer-paper": { + backgroundColor: "transparent", + }, + }, + }, + ], })); const StyledNavHeaderLink = styled(Link)(({ theme }) => ({ - flex: 1, - display: 'flex', - alignItems: 'center', - color: 'inherit', - textDecoration: 'none', - cursor: 'pointer', - gap: theme.spacing(1), - '&:hover': { - background: theme.palette.action.hover, - }, + flex: 1, + display: "flex", + alignItems: "center", + color: "inherit", + textDecoration: "none", + cursor: "pointer", + gap: theme.spacing(1), + "&:hover": { + background: theme.palette.action.hover, + }, })); const StyledSidebarHeader = styled(Stack)(({ theme }) => ({ - paddingTop: theme.spacing(3), - paddingRight: theme.spacing(2), - paddingLeft: theme.spacing(2), + paddingTop: theme.spacing(3), + paddingRight: theme.spacing(2), + paddingLeft: theme.spacing(2), })); const StyledMenuOpenRounded = styled(MenuOpenRounded)(({ theme }) => ({ - color: theme.palette.text.primary, + color: theme.palette.text.primary, })); const StyledSidebarContent = styled(Stack)(({ theme }) => ({ - height: '100%', - width: '100%', - flex: 1, - paddingTop: theme.spacing(2), - paddingRight: theme.spacing(2), - paddingBottom: theme.spacing(3), - paddingLeft: theme.spacing(2), + height: "100%", + width: "100%", + flex: 1, + paddingTop: theme.spacing(2), + paddingRight: theme.spacing(2), + paddingBottom: theme.spacing(3), + paddingLeft: theme.spacing(2), })); const StyledList = styled(List)(() => ({ - flex: '1', - height: '100%', - overflowY: 'auto', - overflowX: 'hidden', - padding: 0, + flex: "1", + height: "100%", + overflowY: "auto", + overflowX: "hidden", + padding: 0, })); const StyledListItem = styled(List.Item)(({ theme }) => ({ - gap: theme.spacing(1), - padding: theme.spacing(1), + gap: theme.spacing(1), + padding: theme.spacing(1), })); const _StyledListItemButton = styled(List.ItemButton)(({ theme }) => ({ - flexGrow: '0', - gap: theme.spacing(1), - padding: theme.spacing(1), + flexGrow: "0", + gap: theme.spacing(1), + padding: theme.spacing(1), })) as unknown as typeof List.ItemButton; const _StyledListItemIcon = styled(List.Icon)(() => ({ - width: '28px', - minWidth: 'auto', + width: "28px", + minWidth: "auto", })); const StyledLink = styled(Link)(({ theme }) => ({ - color: 'inherit', - textDecoration: 'none', - cursor: 'pointer', + color: "inherit", + textDecoration: "none", + cursor: "pointer", })); const _StyledPublicOutlined = styled(PublicOutlined)(({ theme }) => ({ - color: theme.palette.text.primary, + color: theme.palette.text.primary, })); const StyledMoreVertOutlined = styled(MoreVertOutlined)(({ theme }) => ({ - color: theme.palette.text.primary, + color: theme.palette.text.primary, })); export const Sidebar = observer(() => { - const { chat } = useChat(); - const { system, actions } = useInsight(); + const { chat } = useChat(); + const { system, actions } = useInsight(); - const [isOpen, setIsOpen] = useState(false); - const [isPinned, setIsPinned] = useCacheState( - false, - 'sidebar--isPinned', - ); - const [settingsMenuAnchorEle, setSettingsMenuAnchorEle] = - React.useState(null); - const isSettingsMenuOpen = Boolean(settingsMenuAnchorEle); + const [isOpen, setIsOpen] = useState(false); + const [isPinned, setIsPinned] = useCacheState( + false, + "sidebar--isPinned", + ); + const [settingsMenuAnchorEle, setSettingsMenuAnchorEle] = + React.useState(null); + const isSettingsMenuOpen = Boolean(settingsMenuAnchorEle); - const loginType = Object.keys(system.config.logins)[0]; - const userName: string = - typeof system.config.logins[loginType] === 'string' - ? (system.config.logins[loginType] as unknown as string) - : ''; + const loginType = Object.keys(system.config.logins)[0]; + const userName: string = + typeof system.config.logins[loginType] === "string" + ? (system.config.logins[loginType] as unknown as string) + : ""; - const initials: string = userName - .match(/(\b\S)?/g) - .join('') - .match(/(^\S|\S$)?/g) - .join('') - .toUpperCase(); + const initials: string = userName + .match(/(\b\S)?/g) + .join("") + .match(/(^\S|\S$)?/g) + .join("") + .toUpperCase(); - /** - * Logout of the application - */ - const logout = async () => { - try { - await actions.logout(); + /** + * Logout of the application + */ + const logout = async () => { + try { + await actions.logout(); - setSettingsMenuAnchorEle(null); - } catch (_e) { - } - }; + setSettingsMenuAnchorEle(null); + } catch (_e) {} + }; - return ( - <> - {!isPinned && ( - setIsOpen(true)} - spacing={2} - > - {LOGO_PATH ? ( - - ) : ( - - )} -   - {initials} - setIsOpen(true)} size="medium"> - - - - )} + return ( + <> + {!isPinned && ( + setIsOpen(true)} + spacing={2} + > + {LOGO_PATH ? ( + + ) : ( + + )} +   + {initials} + setIsOpen(true)} size="medium"> + + + + )} - setIsOpen(false)} - PaperProps={{ - onMouseLeave: () => { - // closes if it is not pinned - if (isPinned) { - return; - } + setIsOpen(false)} + PaperProps={{ + onMouseLeave: () => { + // closes if it is not pinned + if (isPinned) { + return; + } - setIsOpen(false); - }, - }} - > - - - {LOGO_FULL_PATH ? ( - - ) : ( - - )} - - { - if (!isPinned) { - // if it is open and not pinned, pin it - setIsPinned(true); - } else if (isPinned) { - // if it is open, and pinned, close and unpin - setIsPinned(false); - setIsOpen(false); - } else { - // noop - } - }} - > - - - - - - } - > - New Chat - - - - - - Today - - {chat.todayRooms.map((roomId) => { - return ( - - ); - })} - - Previous - - {chat.previousRooms.map((roomId) => { - return ( - - ); - })} - - - {/* + setIsOpen(false); + }, + }} + > + + + {LOGO_FULL_PATH ? ( + + ) : ( + + )} + + { + if (!isPinned) { + // if it is open and not pinned, pin it + setIsPinned(true); + } else if (isPinned) { + // if it is open, and pinned, close and unpin + setIsPinned(false); + setIsOpen(false); + } else { + // noop + } + }} + > + + + + + + } + > + New Chat + + + + + + Today + + {chat.todayRooms.map((roomId) => { + return ( + + ); + })} + + Previous + + {chat.previousRooms.map((roomId) => { + return ( + + ); + })} + + + {/* @@ -314,67 +317,67 @@ export const Sidebar = observer(() => { */} - - - {initials} - - {userName} - - - { - setSettingsMenuAnchorEle(e.currentTarget); - }} - > - - - { - setSettingsMenuAnchorEle(null); - }} - > - { - logout(); - }} - > - Log Out - - - - - - - ); + + + {initials} + + {userName} + + + { + setSettingsMenuAnchorEle(e.currentTarget); + }} + > + + + { + setSettingsMenuAnchorEle(null); + }} + > + { + logout(); + }} + > + Log Out + + + + + + + ); }); diff --git a/packages/playground/src/components/common/Sidebar/SidebarItem.tsx b/packages/playground/src/components/common/Sidebar/SidebarItem.tsx index 6b8d67657a..5cde644cad 100644 --- a/packages/playground/src/components/common/Sidebar/SidebarItem.tsx +++ b/packages/playground/src/components/common/Sidebar/SidebarItem.tsx @@ -1,167 +1,172 @@ -import React from 'react'; -import { observer } from 'mobx-react-lite'; -import { styled, List, CircularProgress, Menu, MenuItem } from '@semoss/ui'; -import { useNotification } from '@semoss/ui'; import { - ChatBubbleOutlineOutlined, - MoreVertOutlined, -} from '@mui/icons-material'; -import { useParams, Link, useNavigate } from 'react-router-dom'; - -import { useChat } from '@/hooks'; + ChatBubbleOutlineOutlined, + MoreVertOutlined, +} from "@mui/icons-material"; +import { observer } from "mobx-react-lite"; +import React from "react"; +import { Link, useNavigate, useParams } from "react-router-dom"; +import { + CircularProgress, + List, + Menu, + MenuItem, + styled, + useNotification, +} from "@semoss/ui"; +import { useChat } from "@/hooks"; const StyledLink = styled(Link)(({ theme }) => ({ - color: 'inherit', - textDecoration: 'none', - cursor: 'pointer', + color: "inherit", + textDecoration: "none", + cursor: "pointer", })); const StyledListItemButton = styled(List.ItemButton, { - shouldForwardProp: (prop) => prop !== 'selected', + shouldForwardProp: (prop) => prop !== "selected", })<{ selected: boolean }>(({ theme, selected }) => ({ - gap: theme.spacing(1), - padding: theme.spacing(1), - backgroundColor: selected ? theme.palette.secondary.selected : undefined, + gap: theme.spacing(1), + padding: theme.spacing(1), + backgroundColor: selected ? theme.palette.secondary.selected : undefined, })) as unknown as typeof List.ItemButton; const StyledListItemIcon = styled(List.Icon)(() => ({ - width: '28px', - minWidth: 'auto', + width: "28px", + minWidth: "auto", })); const StyledChatBubbleOutlineOutlined = styled(ChatBubbleOutlineOutlined)( - ({ theme }) => ({ - color: theme.palette.text.primary, - }), + ({ theme }) => ({ + color: theme.palette.text.primary, + }), ); const StyledMoreVertOutlined = styled(MoreVertOutlined)(({ theme }) => ({ - color: theme.palette.text.primary, + color: theme.palette.text.primary, })); interface SidebarItemProps { - /** Id of the room */ - roomId: string; + /** Id of the room */ + roomId: string; } export const SidebarItem = observer((props: SidebarItemProps) => { - const { roomId } = props; - - const { chat } = useChat(); - const navigate = useNavigate(); - - const notification = useNotification(); - - const { roomId: activeRoomId } = useParams<{ roomId: string }>(); - - // get the room - const room = chat.getRoom(roomId); - - const [chatMenu, setChatMenu] = React.useState(null); - const isSettingsMenuOpen = Boolean(chatMenu); - - // set the name of the room - let name = 'Untitled'; - if (room.metadata && room.metadata.name) { - name = room.metadata.name; - } - - return ( - - - - - - - {room.isLoading && ( - - - - )} - { - setChatMenu(e.currentTarget); - }} - > - - - { - setChatMenu(null); - }} - > - { - try { - // stop the event propagation - e.stopPropagation(); - - room.downloadHistory(); - - // close it - setChatMenu(null); - } catch (e) { - notification.add({ - color: 'error', - message: e.message, - }); - } - }} - > - Download - - { - try { - // stop the event propagation - e.stopPropagation(); - - // close it - chat.closeRoom(roomId); - - // close it - setChatMenu(null); - - // navigate to new - navigate('new'); - } catch (e) { - notification.add({ - color: 'error', - message: e.message, - }); - } - }} - > - Delete - - - - - ); + const { roomId } = props; + + const { chat } = useChat(); + const navigate = useNavigate(); + + const notification = useNotification(); + + const { roomId: activeRoomId } = useParams<{ roomId: string }>(); + + // get the room + const room = chat.getRoom(roomId); + + const [chatMenu, setChatMenu] = React.useState(null); + const isSettingsMenuOpen = Boolean(chatMenu); + + // set the name of the room + let name = "Untitled"; + if (room.metadata && room.metadata.name) { + name = room.metadata.name; + } + + return ( + + + + + + + {room.isLoading && ( + + + + )} + { + setChatMenu(e.currentTarget); + }} + > + + + { + setChatMenu(null); + }} + > + { + try { + // stop the event propagation + e.stopPropagation(); + + room.downloadHistory(); + + // close it + setChatMenu(null); + } catch (e) { + notification.add({ + color: "error", + message: e.message, + }); + } + }} + > + Download + + { + try { + // stop the event propagation + e.stopPropagation(); + + // close it + chat.closeRoom(roomId); + + // close it + setChatMenu(null); + + // navigate to new + navigate("new"); + } catch (e) { + notification.add({ + color: "error", + message: e.message, + }); + } + }} + > + Delete + + + + + ); }); diff --git a/packages/playground/src/components/common/Sidebar/index.ts b/packages/playground/src/components/common/Sidebar/index.ts index c167c49f6f..d678998972 100644 --- a/packages/playground/src/components/common/Sidebar/index.ts +++ b/packages/playground/src/components/common/Sidebar/index.ts @@ -1 +1 @@ -export * from './Sidebar'; +export * from "./Sidebar"; diff --git a/packages/playground/src/components/common/index.ts b/packages/playground/src/components/common/index.ts index 1b6e1ce863..89442068ea 100644 --- a/packages/playground/src/components/common/index.ts +++ b/packages/playground/src/components/common/index.ts @@ -1,2 +1,2 @@ -export * from './Sidebar'; -export * from './RightMenu'; +export * from "./RightMenu"; +export * from "./Sidebar"; diff --git a/packages/playground/src/components/knowledge/ExistingKnowledge.tsx b/packages/playground/src/components/knowledge/ExistingKnowledge.tsx index 9581c2219f..7969ca078c 100644 --- a/packages/playground/src/components/knowledge/ExistingKnowledge.tsx +++ b/packages/playground/src/components/knowledge/ExistingKnowledge.tsx @@ -1,7 +1,7 @@ -import React from "react"; +import type React from "react"; import { usePixel } from "@semoss/sdk/react"; import { CircularProgress, Stack, styled, Table, Typography } from "@semoss/ui"; -import { Engine } from "@/types"; +import type { Engine } from "@/types"; const StyledTableHolder = styled(Stack)(({ theme }) => ({ height: "376px", diff --git a/packages/playground/src/components/knowledge/KnowledgeOverlay.tsx b/packages/playground/src/components/knowledge/KnowledgeOverlay.tsx index b831bb99ae..913728ab16 100644 --- a/packages/playground/src/components/knowledge/KnowledgeOverlay.tsx +++ b/packages/playground/src/components/knowledge/KnowledgeOverlay.tsx @@ -1,5 +1,6 @@ import { AddRounded, Close } from "@mui/icons-material"; -import React, { useEffect, useRef, useState } from "react"; +import type React from "react"; +import { useEffect, useRef, useState } from "react"; import { useInsight, usePixel } from "@semoss/sdk/react"; import { Button, @@ -12,9 +13,9 @@ import { Typography, useNotification, } from "@semoss/ui"; -import { Engine, Knowledge } from "@/types"; +import type { Engine, Knowledge } from "@/types"; import { ExistingKnowledge } from "./ExistingKnowledge"; -import { NewKnowledge, NewKnowledgeData } from "./NewKnowledge"; +import { NewKnowledge, type NewKnowledgeData } from "./NewKnowledge"; const EMBEDDING_MODEL = import.meta.env.VITE_EMBEDDING_MODEL || ""; const ENABLE_NEW_KNOWLEDGE = diff --git a/packages/playground/src/components/options/OptionsMenu.tsx b/packages/playground/src/components/options/OptionsMenu.tsx index f2d6039692..bc1df0e32a 100644 --- a/packages/playground/src/components/options/OptionsMenu.tsx +++ b/packages/playground/src/components/options/OptionsMenu.tsx @@ -13,7 +13,7 @@ import { Typography, } from "@semoss/ui"; import { KnowledgeOverlay, RightMenu, ToolsOverlay } from "@/components"; -import { ChatRoom } from "@/stores"; +import type { ChatRoom } from "@/stores"; const ENABLE_KNOWLEDGE = import.meta.env.VITE_ENABLE_KNOWLEDGE === "true"; const ENABLE_TOOLS = import.meta.env.VITE_ENABLE_TOOLS === "true"; diff --git a/packages/playground/src/components/options/OptionsPicker.tsx b/packages/playground/src/components/options/OptionsPicker.tsx index 9ff918b2be..c5f4fce4b4 100644 --- a/packages/playground/src/components/options/OptionsPicker.tsx +++ b/packages/playground/src/components/options/OptionsPicker.tsx @@ -11,7 +11,7 @@ import { Tooltip, Typography, } from "@semoss/ui"; -import { ChatRoom } from "@/stores"; +import type { ChatRoom } from "@/stores"; const StyledPopover = styled(Popover)(({ theme }) => ({ "& .MuiPaper-root": { diff --git a/packages/playground/src/components/prompt/PromptLibrary.tsx b/packages/playground/src/components/prompt/PromptLibrary.tsx index 7acf3408ef..3949e92d14 100644 --- a/packages/playground/src/components/prompt/PromptLibrary.tsx +++ b/packages/playground/src/components/prompt/PromptLibrary.tsx @@ -15,7 +15,7 @@ import { Typography, } from "@semoss/ui"; import { useDebounceValue } from "@/hooks"; -import { Prompt } from "@/types"; +import type { Prompt } from "@/types"; const StyledHolder = styled("div")(({ theme }) => ({ display: "flex", diff --git a/packages/playground/src/components/room/RoomApp.tsx b/packages/playground/src/components/room/RoomApp.tsx index 9547f6a5ff..0525321ed3 100644 --- a/packages/playground/src/components/room/RoomApp.tsx +++ b/packages/playground/src/components/room/RoomApp.tsx @@ -7,7 +7,7 @@ import { useNotification, } from "@semoss/ui"; import { RightMenu } from "@/components"; -import { ChatRoom } from "@/stores"; +import type { ChatRoom } from "@/stores"; interface RoomAppProps { /** Room to render */ diff --git a/packages/playground/src/components/room/RoomControls.tsx b/packages/playground/src/components/room/RoomControls.tsx index 95c405646a..0c86006ddf 100644 --- a/packages/playground/src/components/room/RoomControls.tsx +++ b/packages/playground/src/components/room/RoomControls.tsx @@ -1,6 +1,6 @@ import { observer } from "mobx-react-lite"; import { OptionsMenu } from "@/components"; -import { ChatRoom } from "@/stores"; +import type { ChatRoom } from "@/stores"; interface RoomControlsProps { /** Room to render */ diff --git a/packages/playground/src/components/room/RoomInput.tsx b/packages/playground/src/components/room/RoomInput.tsx index 02c4adc4e4..d2834cfc1f 100644 --- a/packages/playground/src/components/room/RoomInput.tsx +++ b/packages/playground/src/components/room/RoomInput.tsx @@ -9,7 +9,8 @@ import { VideoFileOutlined, } from "@mui/icons-material"; import { observer } from "mobx-react-lite"; -import React, { useEffect, useRef, useState } from "react"; +import type React from "react"; +import { useEffect, useRef, useState } from "react"; import { Badge, CircularProgress, diff --git a/packages/playground/src/components/room/RoomMessage.tsx b/packages/playground/src/components/room/RoomMessage.tsx index 181ae47544..beb837c02e 100644 --- a/packages/playground/src/components/room/RoomMessage.tsx +++ b/packages/playground/src/components/room/RoomMessage.tsx @@ -20,7 +20,7 @@ import { Typography, useNotification, } from "@semoss/ui"; -import { ChatMessage, ChatRoom } from "@/stores"; +import type { ChatMessage, ChatRoom } from "@/stores"; const StyledUserMessage = styled(Stack)(({ theme }) => ({ padding: theme.spacing(2), diff --git a/packages/playground/src/components/tools/ToolsOverlay.tsx b/packages/playground/src/components/tools/ToolsOverlay.tsx index 6b6f990f09..69e59bb4ed 100644 --- a/packages/playground/src/components/tools/ToolsOverlay.tsx +++ b/packages/playground/src/components/tools/ToolsOverlay.tsx @@ -1,5 +1,6 @@ import { Close } from "@mui/icons-material"; -import React, { useEffect, useMemo, useState } from "react"; +import type React from "react"; +import { useEffect, useMemo, useState } from "react"; import { usePixel } from "@semoss/sdk/react"; import { Button, @@ -19,7 +20,7 @@ import { } from "@semoss/ui"; import LOGO from "@/assets/img/logo.svg"; import { useDebounceValue } from "@/hooks"; -import { App, Engine, Tool } from "@/types"; +import type { App, Engine, Tool } from "@/types"; const ENDPOINT = import.meta.env.ENDPOINT; const MODULE = import.meta.env.MODULE; @@ -203,7 +204,7 @@ export const ToolsOverlay: React.FC = (props) => { */ const IsToolSelected = (t: AvailbleTools): boolean => { const toolKey = getToolKey(t); - return Object.prototype.hasOwnProperty.call(updatedTools, toolKey); + return Object.hasOwn(updatedTools, toolKey); }; /** diff --git a/packages/playground/src/contexts/ChatContext.tsx b/packages/playground/src/contexts/ChatContext.tsx index 429154caf2..56fc0b577a 100644 --- a/packages/playground/src/contexts/ChatContext.tsx +++ b/packages/playground/src/contexts/ChatContext.tsx @@ -1,18 +1,17 @@ -import { createContext } from 'react'; - -import { ChatStore } from '@/stores'; +import { createContext } from "react"; +import type { ChatStore } from "@/stores"; /** * Value */ type ChatContextProps = { - /** chat store */ - chat: ChatStore; + /** chat store */ + chat: ChatStore; }; /** * Context */ export const ChatContext = createContext( - undefined, + undefined, ); diff --git a/packages/playground/src/hooks/useCacheState.ts b/packages/playground/src/hooks/useCacheState.ts index 636475f255..377790176b 100644 --- a/packages/playground/src/hooks/useCacheState.ts +++ b/packages/playground/src/hooks/useCacheState.ts @@ -1,43 +1,43 @@ -import { useEffect, useState } from 'react'; +import { useEffect, useState } from "react"; /** * Access state from the cache */ export const useCacheState = (initialState: T, name: string) => { - const key = `smss--${name}`; + const key = `smss--${name}`; - // set the data - const [state, setState] = useState(initialState); + // set the data + const [state, setState] = useState(initialState); - // load from cache whenever the key changes - useEffect(() => { - try { - const item = localStorage.getItem(key); - if (item) { - // try to get the state - const data = JSON.parse(item); - setState(data.state); - } - } catch (e) { - console.error(e); - } - }, [key]); + // load from cache whenever the key changes + useEffect(() => { + try { + const item = localStorage.getItem(key); + if (item) { + // try to get the state + const data = JSON.parse(item); + setState(data.state); + } + } catch (e) { + console.error(e); + } + }, [key]); - /** - * Handle changing of the data - */ - const onChange = (data: T) => { - // save cache - localStorage.setItem( - key, - JSON.stringify({ - state: data, - }), - ); + /** + * Handle changing of the data + */ + const onChange = (data: T) => { + // save cache + localStorage.setItem( + key, + JSON.stringify({ + state: data, + }), + ); - // update the state - setState(data); - }; + // update the state + setState(data); + }; - return [state, onChange] as const; + return [state, onChange] as const; }; diff --git a/packages/playground/src/hooks/useChat.ts b/packages/playground/src/hooks/useChat.ts index 0633a80161..4db6de620a 100644 --- a/packages/playground/src/hooks/useChat.ts +++ b/packages/playground/src/hooks/useChat.ts @@ -1,16 +1,15 @@ -import { useContext } from 'react'; - -import { ChatContext } from '@/contexts'; +import { useContext } from "react"; +import { ChatContext } from "@/contexts"; /** * Access the current ChatStore * @returns the ChatStore */ export const useChat = () => { - const context = useContext(ChatContext); - if (context === undefined) { - throw new Error('useChat must be used within Chat'); - } + const context = useContext(ChatContext); + if (context === undefined) { + throw new Error("useChat must be used within Chat"); + } - return context; + return context; }; diff --git a/packages/playground/src/hooks/useDebounceValue.ts b/packages/playground/src/hooks/useDebounceValue.ts index 0ec17da460..0e4dea575e 100644 --- a/packages/playground/src/hooks/useDebounceValue.ts +++ b/packages/playground/src/hooks/useDebounceValue.ts @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState } from 'react'; +import { useEffect, useRef, useState } from "react"; /** * Debouncea @@ -7,19 +7,19 @@ import { useEffect, useRef, useState } from 'react'; * @returns debounced value */ export const useDebounceValue = (value: T, delay = 500) => { - const [debouncedValue, setDebouncedValue] = useState(); - const timerRef = useRef>(); + const [debouncedValue, setDebouncedValue] = useState(); + const timerRef = useRef>(); - useEffect(() => { - // waittill it is set - timerRef.current = setTimeout(() => { - setDebouncedValue(value); - }, delay); + useEffect(() => { + // waittill it is set + timerRef.current = setTimeout(() => { + setDebouncedValue(value); + }, delay); - return () => { - clearTimeout(timerRef.current); - }; - }, [value, delay]); + return () => { + clearTimeout(timerRef.current); + }; + }, [value, delay]); - return debouncedValue; + return debouncedValue; }; diff --git a/packages/playground/src/main.tsx b/packages/playground/src/main.tsx index 5928fd6e8b..19dda52fd8 100644 --- a/packages/playground/src/main.tsx +++ b/packages/playground/src/main.tsx @@ -1,9 +1,6 @@ -import { createRoot } from 'react-dom/client'; +import { createRoot } from "react-dom/client"; +import { App } from "./App"; -import { App } from './App'; - -const container = document.getElementById('root'); +const container = document.getElementById("root"); const root = createRoot(container); // createRoot(container!) if you use TypeScript -root.render( - , -); +root.render(); diff --git a/packages/playground/src/pages/AuthenticatedLayout.tsx b/packages/playground/src/pages/AuthenticatedLayout.tsx index ea0bb52a34..d0df79b2e7 100644 --- a/packages/playground/src/pages/AuthenticatedLayout.tsx +++ b/packages/playground/src/pages/AuthenticatedLayout.tsx @@ -1,19 +1,18 @@ -import { Outlet, Navigate, useLocation } from 'react-router-dom'; - -import { useInsight } from '@semoss/sdk/react'; +import { Navigate, Outlet, useLocation } from "react-router-dom"; +import { useInsight } from "@semoss/sdk/react"; /** * Wrap the database routes and add additional funcitonality */ export const AuthenticatedLayout = () => { - const { isAuthorized } = useInsight(); + const { isAuthorized } = useInsight(); - // track the location - const location = useLocation(); + // track the location + const location = useLocation(); - if (!isAuthorized) { - return ; - } + if (!isAuthorized) { + return ; + } - return ; + return ; }; diff --git a/packages/playground/src/pages/DiscoverPage.tsx b/packages/playground/src/pages/DiscoverPage.tsx index 0591b5fe3f..5a58a7239b 100644 --- a/packages/playground/src/pages/DiscoverPage.tsx +++ b/packages/playground/src/pages/DiscoverPage.tsx @@ -1,219 +1,219 @@ -import { useState } from 'react'; +import { AccessTimeOutlined, Add } from "@mui/icons-material"; +import { observer } from "mobx-react-lite"; +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; import { - styled, - Typography, - Box, - TextField, - Stack, - Grid, - Button, -} from '@semoss/ui'; -import { observer } from 'mobx-react-lite'; -import { AccessTimeOutlined, Add } from '@mui/icons-material'; -import { useChat } from '@/hooks'; -import { useNavigate } from 'react-router-dom'; + Box, + Button, + Grid, + Stack, + styled, + TextField, + Typography, +} from "@semoss/ui"; +import { useChat } from "@/hooks"; const StyledCaption = styled(Typography)(({ theme }) => ({ - color: 'var(--Text-Primary, #212121)', - fontFeatureSettings: "'liga' off, 'clig' off", - fontFamily: 'Roboto', - fontSize: '14px', - fontStyle: 'normal', - fontWeight: 400, - lineHeight: '166%' /* 24px */, - letterSpacing: '0.4px', - display: '-webkit-box', - '-webkit-line-clamp': '2', - '-webkit-box-orient': 'vertical', - height: '40px', - overflow: 'hidden', + color: "var(--Text-Primary, #212121)", + fontFeatureSettings: "'liga' off, 'clig' off", + fontFamily: "Roboto", + fontSize: "14px", + fontStyle: "normal", + fontWeight: 400, + lineHeight: "166%" /* 24px */, + letterSpacing: "0.4px", + display: "-webkit-box", + "-webkit-line-clamp": "2", + "-webkit-box-orient": "vertical", + height: "40px", + overflow: "hidden", })); const StyledCardItem = styled(Stack)(({ theme }) => ({ - display: 'flex', - width: '100%', - backgroundColor: theme.palette.background.paper, - borderWidth: '1px', - borderStyle: 'solid', - borderColor: 'rgba(64, 160, 255, 0.50)', - borderRadius: theme.shape.borderRadius, - cursor: 'pointer', - padding: theme.spacing(3), - flexDirection: 'column', - alignItems: 'flex-start', - gap: theme.spacing(1), - minWidth: '0', + display: "flex", + width: "100%", + backgroundColor: theme.palette.background.paper, + borderWidth: "1px", + borderStyle: "solid", + borderColor: "rgba(64, 160, 255, 0.50)", + borderRadius: theme.shape.borderRadius, + cursor: "pointer", + padding: theme.spacing(3), + flexDirection: "column", + alignItems: "flex-start", + gap: theme.spacing(1), + minWidth: "0", })); const StyledGridCard = styled(Grid)(({ theme }) => ({ - background: theme.palette.background.paper, - paddingLeft: '0', - paddingTop: '0', + background: theme.palette.background.paper, + paddingLeft: "0", + paddingTop: "0", })); const StyledBox = styled(Box)(({ theme }) => ({ - maxHeight: '640px', - overflowY: 'scroll', + maxHeight: "640px", + overflowY: "scroll", })); const StyledTitle = styled(Typography)(({ theme }) => ({ - color: 'var(--Text-Primary, #212121)', - fontFeatureSettings: "'liga' off, 'clig' off", - /* Typography/H6 */ - fontFamily: 'Inter', - fontSize: '20px', - fontStyle: 'normal', - fontWeight: '700', - lineHeight: '160%' /* 32px */, - letterSpacing: '0.15px', + color: "var(--Text-Primary, #212121)", + fontFeatureSettings: "'liga' off, 'clig' off", + /* Typography/H6 */ + fontFamily: "Inter", + fontSize: "20px", + fontStyle: "normal", + fontWeight: "700", + lineHeight: "160%" /* 32px */, + letterSpacing: "0.15px", })); const StyledOuterContainer = styled(Stack)(({ theme }) => ({ - padding: theme.spacing(2), + padding: theme.spacing(2), })); // TODO: Pull from backend const ALL_AGENTS = [ - { - NAME: 'Weather Forecaster', - PUBLISH_DATE: 'Mar. 01, 2025', - }, - { - NAME: 'Create Meeting Minutes', - PUBLISH_DATE: 'Mar. 01, 2025', - }, - { - NAME: 'Plan Your Next Vacation', - PUBLISH_DATE: 'Mar. 01, 2025', - }, - { - NAME: 'Financial Analyst', - PUBLISH_DATE: 'Mar. 01, 2025', - }, - { - NAME: 'Weather Forecaster', - PUBLISH_DATE: 'Mar. 01, 2025', - }, - { - NAME: 'Create Meeting Minutes', - PUBLISH_DATE: 'Mar. 01, 2025', - }, - { - NAME: 'Plan Your Next Vacation', - PUBLISH_DATE: 'Mar. 01, 2025', - }, - { - NAME: 'Financial Analyst', - PUBLISH_DATE: 'Mar. 01, 2025', - }, + { + NAME: "Weather Forecaster", + PUBLISH_DATE: "Mar. 01, 2025", + }, + { + NAME: "Create Meeting Minutes", + PUBLISH_DATE: "Mar. 01, 2025", + }, + { + NAME: "Plan Your Next Vacation", + PUBLISH_DATE: "Mar. 01, 2025", + }, + { + NAME: "Financial Analyst", + PUBLISH_DATE: "Mar. 01, 2025", + }, + { + NAME: "Weather Forecaster", + PUBLISH_DATE: "Mar. 01, 2025", + }, + { + NAME: "Create Meeting Minutes", + PUBLISH_DATE: "Mar. 01, 2025", + }, + { + NAME: "Plan Your Next Vacation", + PUBLISH_DATE: "Mar. 01, 2025", + }, + { + NAME: "Financial Analyst", + PUBLISH_DATE: "Mar. 01, 2025", + }, ]; export const DiscoverPage = observer((props) => { - const { chat } = useChat(); - const navigate = useNavigate(); + const { chat } = useChat(); + const navigate = useNavigate(); - const [search, setSearch] = useState(''); - const [filter, setFilter] = useState(''); - const [allAgents, setAllAgents] = useState(ALL_AGENTS); + const [search, setSearch] = useState(""); + const [filter, setFilter] = useState(""); + const [allAgents, setAllAgents] = useState(ALL_AGENTS); - const filtered = (filter) => { - if (filter == null || filter.length == 0) { - return allAgents; - } + const filtered = (filter) => { + if (filter == null || filter.length == 0) { + return allAgents; + } - const searchText = filter ? filter.toLowerCase() : null; - const filtered = allAgents.filter((agent) => { - if (searchText) { - return true; - } else { - return false; - } - }); + const searchText = filter ? filter.toLowerCase() : null; + const filtered = allAgents.filter((agent) => { + if (searchText) { + return true; + } else { + return false; + } + }); - return filtered; - }; + return filtered; + }; - return ( - - - Discover - - - - setSearch(e.target.value)} - /> - - - - - {filtered(search).map((p) => { - return ( - { - //To Do - }} - > - - - {p.NAME} - - - - - {`Published: ${p.PUBLISH_DATE}`} - - - - - ); - })} - - - - ); + return ( + + + Discover + + + + setSearch(e.target.value)} + /> + + + + + {filtered(search).map((p) => { + return ( + { + //To Do + }} + > + + + {p.NAME} + + + + + {`Published: ${p.PUBLISH_DATE}`} + + + + + ); + })} + + + + ); }); diff --git a/packages/playground/src/pages/LoginPage.tsx b/packages/playground/src/pages/LoginPage.tsx index 7a6cc9ad50..2f7acdfddc 100644 --- a/packages/playground/src/pages/LoginPage.tsx +++ b/packages/playground/src/pages/LoginPage.tsx @@ -1,499 +1,497 @@ -import { useInsight } from '@semoss/sdk/react'; +import { observer } from "mobx-react-lite"; +import { useState } from "react"; +import { Controller, useForm } from "react-hook-form"; +import { type Location, Navigate, useLocation } from "react-router-dom"; +import { useInsight } from "@semoss/sdk/react"; import { - Alert, - Box, - Button, - Divider, - LinearProgress, - Modal, - Snackbar, - Stack, - styled, - TextField, - Typography, -} from '@semoss/ui'; -import { observer } from 'mobx-react-lite'; -import { useState } from 'react'; -import { Controller, useForm } from 'react-hook-form'; -import { Location, Navigate, useLocation } from 'react-router-dom'; - -import LOGO_FULL from '@/assets/img/logo_full.svg'; - -const APP_NAME = import.meta.env.VITE_APP_NAME ? import.meta.env.VITE_APP_NAME : ''; + Alert, + Box, + Button, + Divider, + LinearProgress, + Modal, + Snackbar, + Stack, + styled, + TextField, + Typography, +} from "@semoss/ui"; +import LOGO_FULL from "@/assets/img/logo_full.svg"; + +const APP_NAME = import.meta.env.VITE_APP_NAME + ? import.meta.env.VITE_APP_NAME + : ""; const LOGO_FULL_PATH = import.meta.env.VITE_LOGO_FULL_PATH - ? import.meta.env.VITE_LOGO_FULL_PATH - : ''; - -const StyledMain = styled('div')(({ theme }) => ({ - display: 'flex', - flexDirection: 'column', - height: '100vh', - width: '100vw', - background: theme.palette.background.paper, + ? import.meta.env.VITE_LOGO_FULL_PATH + : ""; + +const StyledMain = styled("div")(({ theme }) => ({ + display: "flex", + flexDirection: "column", + height: "100vh", + width: "100vw", + background: theme.palette.background.paper, })); -const StyledRow = styled('div')(() => ({ - flex: '1', - display: 'flex', - flexDirection: 'row', - position: 'relative', - width: '100%', - overflow: 'hidden', +const StyledRow = styled("div")(() => ({ + flex: "1", + display: "flex", + flexDirection: "row", + position: "relative", + width: "100%", + overflow: "hidden", })); const StyledProgress = styled(LinearProgress)(() => ({ - width: '100%', + width: "100%", })); -const StyledScroll = styled('div')(({ theme }) => ({ - flexShrink: 0, - position: 'relative', - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - zIndex: 1, - background: theme.palette.background.paper, - overflowY: 'auto', - overflowX: 'hidden', - [theme.breakpoints.down('md')]: { - height: '100%', - width: '100%', - }, +const StyledScroll = styled("div")(({ theme }) => ({ + flexShrink: 0, + position: "relative", + display: "flex", + flexDirection: "column", + alignItems: "center", + zIndex: 1, + background: theme.palette.background.paper, + overflowY: "auto", + overflowX: "hidden", + [theme.breakpoints.down("md")]: { + height: "100%", + width: "100%", + }, })); -const StyledContent = styled('div')(({ theme }) => ({ - display: 'flex', - flexDirection: 'column', - gap: theme.spacing(3), - width: '610px', - marginTop: theme.spacing(18), // 144px - marginBottom: theme.spacing(2), // 16px - marginLeft: theme.spacing(13.5), // 108px - marginRight: theme.spacing(13.5), // 108px - [theme.breakpoints.down('md')]: { - margin: 0, - padding: theme.spacing(4), - maxWidth: '610px', - width: '100%', - }, +const StyledContent = styled("div")(({ theme }) => ({ + display: "flex", + flexDirection: "column", + gap: theme.spacing(3), + width: "610px", + marginTop: theme.spacing(18), // 144px + marginBottom: theme.spacing(2), // 16px + marginLeft: theme.spacing(13.5), // 108px + marginRight: theme.spacing(13.5), // 108px + [theme.breakpoints.down("md")]: { + margin: 0, + padding: theme.spacing(4), + maxWidth: "610px", + width: "100%", + }, })); -const StyledGradient = styled('div')(({ theme }) => ({ - height: '100%', - width: theme.spacing(42), // 336px - background: - 'linear-gradient(90deg, #FFF 0%, rgba(255, 255, 255, 0.00) 100%)', - zIndex: 1, +const StyledGradient = styled("div")(({ theme }) => ({ + height: "100%", + width: theme.spacing(42), // 336px + background: + "linear-gradient(90deg, #FFF 0%, rgba(255, 255, 255, 0.00) 100%)", + zIndex: 1, })); -const StyledImageHolder = styled('div')(() => ({ - position: 'absolute', - top: '0px', - right: '0px', - bottom: '0px', - overflow: 'hidden', - zIndex: 0, +const StyledImageHolder = styled("div")(() => ({ + position: "absolute", + top: "0px", + right: "0px", + bottom: "0px", + overflow: "hidden", + zIndex: 0, })); -const _StyledImage = styled('img')(() => ({ - height: '100%', - // width: '100%', - objectFit: 'cover', +const _StyledImage = styled("img")(() => ({ + height: "100%", + // width: '100%', + objectFit: "cover", })); const StyledAction = styled(Button)({ - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - overflow: 'hidden', + display: "flex", + alignItems: "center", + justifyContent: "center", + overflow: "hidden", }); -const StyledActionBox = styled('div')({ - display: 'flex', - alignItems: 'center', - gap: '16px', - padding: '4px', +const StyledActionBox = styled("div")({ + display: "flex", + alignItems: "center", + gap: "16px", + padding: "4px", }); // const StyledActionImage = styled('img')(({ theme }) => ({ // height: theme.spacing(3), // })); -const StyledActionText = styled('span')(() => ({ - fontFamily: 'Inter', - fontSize: '14px', - fontStyle: 'normal', - fontWeight: 500, - lineHeight: '24px', - letterSpacing: '0.4px', - color: '#000', +const StyledActionText = styled("span")(() => ({ + fontFamily: "Inter", + fontSize: "14px", + fontStyle: "normal", + fontWeight: 500, + lineHeight: "24px", + letterSpacing: "0.4px", + color: "#000", })); const StyledDivider = styled(Divider)({ - background: 'transparent', + background: "transparent", }); const StyledDividerBox = styled(Box)({ - color: '#000', - fontFeatureSettings: '"clig" off, "liga" off', - fontFamily: 'Inter', - fontSize: '16px', - fontStyle: 'normal', - fontWeight: 700, - lineHeight: '150%' /* 24px */, - letterSpacing: ' 0.15px', + color: "#000", + fontFeatureSettings: '"clig" off, "liga" off', + fontFamily: "Inter", + fontSize: "16px", + fontStyle: "normal", + fontWeight: 700, + lineHeight: "150%" /* 24px */, + letterSpacing: " 0.15px", }); const StyledLogoContainer = styled(Stack)(({ theme }) => ({ - marginBottom: theme.spacing(1), + marginBottom: theme.spacing(1), })); const StyledTitle = styled(Typography)(({ theme }) => ({ - marginBottom: theme.spacing(1), + marginBottom: theme.spacing(1), })); const StyledInstructions = styled(Typography)(({ theme }) => ({ - marginBottom: theme.spacing(4), + marginBottom: theme.spacing(4), })); interface TypeUserLogin { - USERNAME: string; - PASSWORD: string; - REMEMBER_LOGIN: boolean; - OTP_CONFIRM: string; + USERNAME: string; + PASSWORD: string; + REMEMBER_LOGIN: boolean; + OTP_CONFIRM: string; } /** * LoginPage */ export const LoginPage = observer(() => { - const { system, actions, isAuthorized } = useInsight(); - const location = useLocation(); - - const [forgotPassword, setForgotPassword] = useState(false); - const [snackbar, setSnackbar] = useState<{ - open: boolean; - message: string; - color: 'success' | 'info' | 'warning' | 'error'; - }>({ - open: false, - message: '', - color: 'success', - }); - const [error, setError] = useState(''); - const [isLoading, setIsLoading] = useState(false); - - const { control, handleSubmit } = useForm({ - defaultValues: { - USERNAME: '', - PASSWORD: '', - REMEMBER_LOGIN: false, - OTP_CONFIRM: '', - }, - }); - - // get a map of all providers - const availableProvidersMap: Record< - string, - { - provider: string; - name: string; - isOauth: boolean; - } - > = system.config.availableProviders.reduce((acc, val) => { - acc[val.provider] = acc; - - return acc; - }, {}); - - // check if there is oAuth - const hasOAuth = system.config.availableProviders.some( - (val) => val.isOauth, - ); - - const isNative = Object.prototype.hasOwnProperty.call( - availableProvidersMap, - 'native', - ); - - // check if it requires username or password - const hasUsernamePassword = isNative; - - /** - * Allow the user to login - */ - const login = handleSubmit( - async (data: TypeUserLogin): Promise => { - // turn on loading - setIsLoading(true); - - if (!data.USERNAME || !data.PASSWORD) { - setError('Username and Password is Required'); - return; - } - - await actions - .login({ - type: 'native', - username: data.USERNAME, - password: data.PASSWORD, - }) - .then(() => { - // noop - }) - .catch((error) => { - setError(error.message); - }) - .finally(() => { - // turn off loading - setIsLoading(false); - }); - }, - ); - - /** - * Login with oauth - * @param provider - provider to oauth with - */ - const oauth = async (provider: string) => { - // turn on loading - setIsLoading(true); - - await actions - .login({ - type: 'oauth', - provider: provider, - }) - .then(() => { - // turn off loading - setIsLoading(false); - - // noop - // (handled by the configStore) - - setSnackbar({ - open: true, - message: `Successfully logged in`, - color: 'success', - }); - }) - .catch((error) => { - // turn off loading - setIsLoading(false); - - setError(error.message); - - setSnackbar({ - open: true, - message: error.message, - color: 'error', - }); - }); - }; - - // get the path the user is coming from - const path = (location.state as { from: Location })?.from?.pathname || '/'; - - // navigate if already logged in - if (isAuthorized) { - return ; - } - - return ( - <> - { - setSnackbar({ - open: false, - message: '', - color: 'success', - }); - }} - > - - {snackbar.message} - - - - - - -
    - - {LOGO_FULL_PATH ? ( - - ) : ( - - )} - - Welcome! - - Log in below - -
    - {error && {error}} -
    - - {hasUsernamePassword && ( - <> - { - return ( - - field.onChange( - e.target - .value, - ) - } - inputProps={{ - 'data-testid': - 'loginPage-textField-username', - }} - /> - ); - }} - /> - { - return ( - - field.onChange( - e.target - .value, - ) - } - inputProps={{ - 'data-testid': - 'loginPage-textField-password', - }} - /> - ); - }} - /> - - - )} - - {hasUsernamePassword && hasOAuth && ( - - - or - - - )} - {system.config.availableProviders.map( - (p) => { - // skip ones that aren't oauth - if (!p.isOauth) { - return null; - } - - return ( - { - oauth(p.provider); - }} - fullWidth - > - - {/* ({ + open: false, + message: "", + color: "success", + }); + const [error, setError] = useState(""); + const [isLoading, setIsLoading] = useState(false); + + const { control, handleSubmit } = useForm({ + defaultValues: { + USERNAME: "", + PASSWORD: "", + REMEMBER_LOGIN: false, + OTP_CONFIRM: "", + }, + }); + + // get a map of all providers + const availableProvidersMap: Record< + string, + { + provider: string; + name: string; + isOauth: boolean; + } + > = system.config.availableProviders.reduce((acc, val) => { + acc[val.provider] = acc; + + return acc; + }, {}); + + // check if there is oAuth + const hasOAuth = system.config.availableProviders.some( + (val) => val.isOauth, + ); + + const isNative = Object.hasOwn(availableProvidersMap, "native"); + + // check if it requires username or password + const hasUsernamePassword = isNative; + + /** + * Allow the user to login + */ + const login = handleSubmit( + async (data: TypeUserLogin): Promise => { + // turn on loading + setIsLoading(true); + + if (!data.USERNAME || !data.PASSWORD) { + setError("Username and Password is Required"); + return; + } + + await actions + .login({ + type: "native", + username: data.USERNAME, + password: data.PASSWORD, + }) + .then(() => { + // noop + }) + .catch((error) => { + setError(error.message); + }) + .finally(() => { + // turn off loading + setIsLoading(false); + }); + }, + ); + + /** + * Login with oauth + * @param provider - provider to oauth with + */ + const oauth = async (provider: string) => { + // turn on loading + setIsLoading(true); + + await actions + .login({ + type: "oauth", + provider: provider, + }) + .then(() => { + // turn off loading + setIsLoading(false); + + // noop + // (handled by the configStore) + + setSnackbar({ + open: true, + message: `Successfully logged in`, + color: "success", + }); + }) + .catch((error) => { + // turn off loading + setIsLoading(false); + + setError(error.message); + + setSnackbar({ + open: true, + message: error.message, + color: "error", + }); + }); + }; + + // get the path the user is coming from + const path = (location.state as { from: Location })?.from?.pathname || "/"; + + // navigate if already logged in + if (isAuthorized) { + return ; + } + + return ( + <> + { + setSnackbar({ + open: false, + message: "", + color: "success", + }); + }} + > + + {snackbar.message} + + + + + + +
    + + {LOGO_FULL_PATH ? ( + + ) : ( + + )} + + Welcome! + + Log in below + +
    + {error && {error}} + + + {hasUsernamePassword && ( + <> + { + return ( + + field.onChange( + e.target + .value, + ) + } + inputProps={{ + "data-testid": + "loginPage-textField-username", + }} + /> + ); + }} + /> + { + return ( + + field.onChange( + e.target + .value, + ) + } + inputProps={{ + "data-testid": + "loginPage-textField-password", + }} + /> + ); + }} + /> + + + )} + + {hasUsernamePassword && hasOAuth && ( + + + or + + + )} + {system.config.availableProviders.map( + (p) => { + // skip ones that aren't oauth + if (!p.isOauth) { + return null; + } + + return ( + { + oauth(p.provider); + }} + fullWidth + > + + {/* */} - - {p.name} - - - - ); - }, - )} - - -
    -
    - -   -
    - {isLoading && } -
    - { - setForgotPassword(false); - }} - > - Forgot your password? - - - Please contact your administrator to reset password. - - - - - - - - ); + + {p.name} + +
    +
    + ); + }, + )} +
    + +
    +
    + +   +
    + {isLoading && } +
    + { + setForgotPassword(false); + }} + > + Forgot your password? + + + Please contact your administrator to reset password. + + + + + + + + ); }); diff --git a/packages/playground/src/pages/MainLayout.tsx b/packages/playground/src/pages/MainLayout.tsx index 8b6461f9a4..ccb5a1cde9 100644 --- a/packages/playground/src/pages/MainLayout.tsx +++ b/packages/playground/src/pages/MainLayout.tsx @@ -1,67 +1,66 @@ -import { useMemo } from 'react'; -import { Outlet } from 'react-router-dom'; -import { styled, Stack } from '@semoss/ui'; -import { useInsight } from '@semoss/sdk/react'; - -import { ChatStore } from '@/stores'; -import { ChatContext } from '@/contexts'; -import { Sidebar } from '@/components'; +import { useMemo } from "react"; +import { Outlet } from "react-router-dom"; +import { useInsight } from "@semoss/sdk/react"; +import { Stack, styled } from "@semoss/ui"; +import { Sidebar } from "@/components"; +import { ChatContext } from "@/contexts"; +import { ChatStore } from "@/stores"; const StyledMain = styled(Stack)(() => ({ - position: 'relative', - height: '100%', - width: '100%', + position: "relative", + height: "100%", + width: "100%", })); -const StyledContent = styled('div')(({ theme }) => ({ - position: 'relative', - flex: '1', - height: '100%', - width: '100%', - overflow: 'hidden', - paddingTop: theme.spacing(3), - paddingRight: theme.spacing(3), - paddingBottom: theme.spacing(3), - paddingLeft: theme.spacing(1), +const StyledContent = styled("div")(({ theme }) => ({ + position: "relative", + flex: "1", + height: "100%", + width: "100%", + overflow: "hidden", + paddingTop: theme.spacing(3), + paddingRight: theme.spacing(3), + paddingBottom: theme.spacing(3), + paddingLeft: theme.spacing(1), })); -const StyledInner = styled('div')(({ theme }) => ({ - flex: '1', - height: '100%', - width: '100%', - background: theme.palette.background.paper, - borderRadius: theme.shape.borderRadius, - overflowX: 'hidden', - overflowY: 'auto', +const StyledInner = styled("div")(({ theme }) => ({ + flex: "1", + height: "100%", + width: "100%", + background: theme.palette.background.paper, + borderRadius: theme.shape.borderRadius, + overflowX: "hidden", + overflowY: "auto", })); export const MainLayout = () => { - const { actions } = useInsight(); + const { actions } = useInsight(); - // set up the store - const chatStore = useMemo(() => { - const store = new ChatStore(actions); + // set up the store + const chatStore = useMemo(() => { + const store = new ChatStore(actions); - // initialize it - store.initialize(); + // initialize it + store.initialize(); - return store; - }, [actions]); + return store; + }, [actions]); - return ( - - - - - - - - - - - ); + return ( + + + + + + + + + + + ); }; diff --git a/packages/playground/src/pages/NewRoomPage.tsx b/packages/playground/src/pages/NewRoomPage.tsx index 6f46ef3be7..594fc56ca6 100644 --- a/packages/playground/src/pages/NewRoomPage.tsx +++ b/packages/playground/src/pages/NewRoomPage.tsx @@ -36,8 +36,8 @@ import { } from "@/components"; import { TEMPERATURE, TOKEN_LENGTH } from "@/constants"; import { useChat } from "@/hooks"; -import { ChatRoom } from "@/stores"; -import { Prompt } from "@/types"; +import type { ChatRoom } from "@/stores"; +import type { Prompt } from "@/types"; const APP_DESCRIPTION = import.meta.env.VITE_APP_DESCRIPTION ? import.meta.env.VITE_APP_DESCRIPTION diff --git a/packages/playground/src/pages/Router.tsx b/packages/playground/src/pages/Router.tsx index 7dd33bfaea..dc3d29dbe2 100644 --- a/packages/playground/src/pages/Router.tsx +++ b/packages/playground/src/pages/Router.tsx @@ -1,68 +1,61 @@ - -import { useInsight } from '@semoss/sdk/react'; -import { CircularProgress, styled } from '@semoss/ui'; -import { - HashRouter, - Navigate, - Route, - Routes, -} from 'react-router-dom'; - -import { AuthenticatedLayout } from './AuthenticatedLayout'; -import { DiscoverPage } from './DiscoverPage'; -import { LoginPage } from './LoginPage'; -import { MainLayout } from './MainLayout'; -import { NewRoomPage } from './NewRoomPage'; -import { RoomPage } from './RoomPage'; - -const StyledContainer = styled('div')(() => ({ - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - position: 'absolute', - inset: '0', - height: '100%', - width: '100%', +import { HashRouter, Navigate, Route, Routes } from "react-router-dom"; +import { useInsight } from "@semoss/sdk/react"; +import { CircularProgress, styled } from "@semoss/ui"; +import { AuthenticatedLayout } from "./AuthenticatedLayout"; +import { DiscoverPage } from "./DiscoverPage"; +import { LoginPage } from "./LoginPage"; +import { MainLayout } from "./MainLayout"; +import { NewRoomPage } from "./NewRoomPage"; +import { RoomPage } from "./RoomPage"; + +const StyledContainer = styled("div")(() => ({ + display: "flex", + alignItems: "center", + justifyContent: "center", + position: "absolute", + inset: "0", + height: "100%", + width: "100%", })); - export const Router = () => { - const { isInitialized, error } = useInsight(); - - - // don't load anything if it is pending - if (!isInitialized) { - return ( - - - - ); - } - - if (error) { - return "Error"; - } - - return ( - - - }> - }> - } /> - } /> - } /> - } - /> - - - }> - } /> - - - ); + const { isInitialized, error } = useInsight(); + + // don't load anything if it is pending + if (!isInitialized) { + return ( + + + + ); + } + + if (error) { + return "Error"; + } + + return ( + + + }> + }> + } /> + } /> + } /> + } + /> + + + }> + } /> + + + ); }; diff --git a/packages/playground/src/stores/chat/chat.room.ts b/packages/playground/src/stores/chat/chat.room.ts index ce5b02ec9a..c2d543efb2 100644 --- a/packages/playground/src/stores/chat/chat.room.ts +++ b/packages/playground/src/stores/chat/chat.room.ts @@ -1,7 +1,7 @@ import { makeAutoObservable, runInAction } from "mobx"; import { download, runPixel, upload } from "@semoss/sdk/react"; import { TEMPERATURE, TOKEN_LENGTH } from "@/constants"; -import { Knowledge, PixelMessage, Tool } from "@/types"; +import type { Knowledge, PixelMessage, Tool } from "@/types"; import { ChatMessage } from "./chat.message"; const ROOT_MESSAGE_ID = "ROOT"; diff --git a/packages/playground/src/stores/chat/chat.store.ts b/packages/playground/src/stores/chat/chat.store.ts index fd96f1ecc5..6b80960adf 100644 --- a/packages/playground/src/stores/chat/chat.store.ts +++ b/packages/playground/src/stores/chat/chat.store.ts @@ -1,7 +1,7 @@ import { makeAutoObservable, runInAction } from "mobx"; -import { Insight } from "@semoss/sdk/react"; +import type { Insight } from "@semoss/sdk/react"; import { MODEL_KEY } from "@/constants"; -import { Engine } from "@/types"; +import type { Engine } from "@/types"; import { ChatRoom } from "./chat.room"; const DEFAUlT_MODEL = import.meta.env.VITE_DEFAUlT_MODEL || ""; diff --git a/packages/playground/src/stores/chat/index.ts b/packages/playground/src/stores/chat/index.ts index f875c1a280..39111f576a 100644 --- a/packages/playground/src/stores/chat/index.ts +++ b/packages/playground/src/stores/chat/index.ts @@ -1,5 +1,5 @@ -import { ChatStore } from './chat.store'; -import { ChatRoom } from './chat.room'; -import { ChatMessage } from './chat.message'; +import { ChatMessage } from "./chat.message"; +import { ChatRoom } from "./chat.room"; +import { ChatStore } from "./chat.store"; export { ChatStore, ChatRoom, ChatMessage }; diff --git a/packages/playground/src/stores/index.ts b/packages/playground/src/stores/index.ts index 043e5b3938..d27da0d970 100644 --- a/packages/playground/src/stores/index.ts +++ b/packages/playground/src/stores/index.ts @@ -1 +1 @@ -export * from './chat'; +export * from "./chat"; diff --git a/packages/playground/tsconfig.json b/packages/playground/tsconfig.json index eda580308b..8751fbfddb 100644 --- a/packages/playground/tsconfig.json +++ b/packages/playground/tsconfig.json @@ -1,37 +1,25 @@ { - "compilerOptions": { - /* Lang and Env */ - "lib": [ - "ES2022", - "dom" - ], - "target": "es6", - "jsx": "react-jsx", - "types": [ - "vite/client" - ], - /* Modules */ - "module": "esnext", - "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true, - "resolveJsonModule": true, - /* Skip */ - "skipLibCheck": true, - "allowJs": true, - "esModuleInterop": true, - "isolatedModules": true, - /* Lang and Env */ - "paths": { - "@/*": [ - "./src/*" - ], - } - }, - "include": [ - "src" - ], - "exclude": [ - "dist", - "node_modules" - ] -} \ No newline at end of file + "compilerOptions": { + /* Lang and Env */ + "lib": ["ES2022", "dom"], + "target": "es6", + "jsx": "react-jsx", + "types": ["vite/client"], + /* Modules */ + "module": "esnext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true, + /* Skip */ + "skipLibCheck": true, + "allowJs": true, + "esModuleInterop": true, + "isolatedModules": true, + /* Lang and Env */ + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"], + "exclude": ["dist", "node_modules"] +} diff --git a/packages/vscode-extension/.vscode/extensions.json b/packages/vscode-extension/.vscode/extensions.json index a8d7784992..e6cd98485e 100644 --- a/packages/vscode-extension/.vscode/extensions.json +++ b/packages/vscode-extension/.vscode/extensions.json @@ -1,5 +1,3 @@ { - "recommendations": [ - "dbaeumer.vscode-eslint" - ] -} \ No newline at end of file + "recommendations": ["dbaeumer.vscode-eslint"] +} diff --git a/packages/vscode-extension/.vscode/launch.json b/packages/vscode-extension/.vscode/launch.json index b8a13d37dc..259675417d 100644 --- a/packages/vscode-extension/.vscode/launch.json +++ b/packages/vscode-extension/.vscode/launch.json @@ -5,9 +5,7 @@ "name": "Run Extension", "type": "extensionHost", "request": "launch", - "args": [ - "--extensionDevelopmentPath=${workspaceFolder}" - ] + "args": ["--extensionDevelopmentPath=${workspaceFolder}"] }, { "name": "Extension Tests", diff --git a/packages/vscode-extension/extension.js b/packages/vscode-extension/extension.js index 8b873164cd..3520b12d1e 100644 --- a/packages/vscode-extension/extension.js +++ b/packages/vscode-extension/extension.js @@ -2,14 +2,25 @@ const vscode = require("vscode"); const fs = require("fs"); const path = require("path"); -const { storeSecrets, getSecrets, selectInstance, removeInstance, storeInstance, getStoredInstances } = require('./src/utils/secrets.js'); -const { setFolderPaths, getProjectId } = require('./src/utils/projectUtils.js'); -const { setDeployConfig, deployProject } = require('./src/utils/deploy.js'); -const { zipProject } = require('./src/utils/zip.js'); -const { createNewApp } = require('./src/utils/createApp.js'); -const { initStatusBar, updateStatusBar } = require('./src/utils/statusBar.js'); -const { handleChatbotAction } = require('./src/components/ChatbotWebview/ChatbotSeparateManager.js'); -const { registerChatbotWebview } = require('./src/components/ChatbotWebview/ChatbotWebview.js'); +const { + storeSecrets, + getSecrets, + selectInstance, + removeInstance, + storeInstance, + getStoredInstances, +} = require("./src/utils/secrets.js"); +const { setFolderPaths, getProjectId } = require("./src/utils/projectUtils.js"); +const { setDeployConfig, deployProject } = require("./src/utils/deploy.js"); +const { zipProject } = require("./src/utils/zip.js"); +const { createNewApp } = require("./src/utils/createApp.js"); +const { initStatusBar, updateStatusBar } = require("./src/utils/statusBar.js"); +const { + handleChatbotAction, +} = require("./src/components/ChatbotWebview/ChatbotSeparateManager.js"); +const { + registerChatbotWebview, +} = require("./src/components/ChatbotWebview/ChatbotWebview.js"); // This method is called when your extension is activated // Your extension is activated the very first time the command is executed @@ -18,362 +29,498 @@ const { registerChatbotWebview } = require('./src/components/ChatbotWebview/Chat * @param {vscode.ExtensionContext} context */ async function activate(context) { - // Initialize the status bar - initStatusBar(context); - await updateStatusBar(context); - - // Register the chatbot webview - registerChatbotWebview(context); - - // Register authorize command (add new instance) - const disposableAuthorize = vscode.commands.registerCommand( - "semoss.authorize", - async (args) => { - // If called from chatbot, use args; otherwise, prompt - if (args && args.alias && args.url && args.accessKey && args.privateKey) { - await storeInstance(context, args.alias, { - semossUrl: args.url, - accessKey: args.accessKey, - privateKey: args.privateKey - }); - await context.secrets.store('CURRENT_INSTANCE_ALIAS', args.alias); - await updateStatusBar(context); - vscode.window.showInformationMessage(`Instance "${args.alias}" saved successfully!`); - vscode.commands.executeCommand('workbench.action.reloadWindow'); - } else { - await storeSecrets(context); - vscode.commands.executeCommand('workbench.action.reloadWindow'); - } - } - ); - - // Register select instance command - const disposableSelectInstance = vscode.commands.registerCommand( - "semoss.selectInstance", - async (args) => { - if (args && args.alias) { - await context.secrets.store('CURRENT_INSTANCE_ALIAS', args.alias); - await updateStatusBar(context); - vscode.window.showInformationMessage(`Switched to instance: ${args.alias}`); - vscode.commands.executeCommand('workbench.action.reloadWindow'); - } else { - const selected = await selectInstance(context); - if (selected) { - await updateStatusBar(context); - vscode.commands.executeCommand('workbench.action.reloadWindow'); - } - } - } - ); - - // Register remove instance command - const disposableRemoveInstance = vscode.commands.registerCommand( - "semoss.removeInstance", - async (args) => { - if (args && args.alias) { - const instances = await getStoredInstances(context); - if (instances[args.alias]) { - delete instances[args.alias]; - await context.secrets.store('SEMOSS_INSTANCES', JSON.stringify(instances)); - const currentAlias = await context.secrets.get('CURRENT_INSTANCE_ALIAS'); - if (currentAlias === args.alias) { - await context.secrets.delete('CURRENT_INSTANCE_ALIAS'); - } - // Always update status bar after instance removal - await updateStatusBar(context); - vscode.window.showInformationMessage(`Instance "${args.alias}" removed successfully!`); - } else { - vscode.window.showWarningMessage(`Instance "${args.alias}" not found.`); - } - } else { - await removeInstance(context); - await updateStatusBar(context); - } - } - ); // Helper function to get secrets with error handling - const getSecretsWithValidation = async (context) => { - const secrets = await getSecrets(context); - if (!secrets || !secrets.semossUrl || !secrets.accessKey || !secrets.privateKey) { - vscode.window.showErrorMessage('No instance configured. Please authorize an instance first.'); - return null; - } - return secrets; - }; - - // Register create new project command - const disposableCreateApp = vscode.commands.registerCommand( - "semoss.createNewApp", - async (args) => { - try { - if (args && args.appName) { - await createNewApp(context, getSecretsWithValidation, args); - } else { - await createNewApp(context, getSecretsWithValidation); - } - } catch (error) { - vscode.window.showErrorMessage(`App creation failed: ${error.message}`); - console.error('Error in createNewApp:', error); - } - } - ); - context.subscriptions.push(disposableCreateApp); - - // Register zip and deploy command - const disposableZipDeploy = vscode.commands.registerCommand( - "semoss.zipanddeploy", - async (uri) => { - // If called from Chatbot UI, uri may be undefined. Use first workspace folder. - if (!uri || !uri.fsPath) { - if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) { - uri = vscode.workspace.workspaceFolders[0].uri; - } else { - vscode.window.showErrorMessage('No workspace folder found.'); - return; - } - } - try { - const secrets = await getSecretsWithValidation(context); - if (!secrets) return; - - setFolderPaths(uri); - - // Zip the project (json, smss, assets as assets.zip) - await zipProject(); - - // Find the zip file that was created (should be assets.zip, but let's be flexible) - const zipFiles = fs.readdirSync(uri.fsPath).filter(file => file.endsWith('.zip')); - let outputZip; - - if (zipFiles.includes('assets.zip')) { - // Prefer assets.zip if it exists (which it should after zipProject()) - outputZip = path.join(uri.fsPath, 'assets.zip'); - } else if (zipFiles.length > 0) { - // Use the first zip file found - outputZip = path.join(uri.fsPath, zipFiles[0]); - vscode.window.showInformationMessage(`Using zip file: ${zipFiles[0]}`); - } else { - vscode.window.showErrorMessage('No zip file was created during the zip process.'); - return; - } - - // Validate the zip file exists and is readable - if (!fs.existsSync(outputZip)) { - vscode.window.showErrorMessage(`Zip file does not exist: ${path.basename(outputZip)}`); - return; - } - - // Check if file is not empty - const stats = fs.statSync(outputZip); - if (stats.size === 0) { - vscode.window.showErrorMessage(`Zip file is empty: ${path.basename(outputZip)}`); - return; - } - - vscode.window.showInformationMessage(`Created and ready to deploy: ${path.basename(outputZip)} (${Math.round(stats.size / 1024)} KB)`); - - // Configure deployment to use the found zip file - const encoded = Buffer.from(secrets.accessKey + ':' + secrets.privateKey).toString('base64'); - const headers = { 'Authorization': 'Basic ' + encoded }; - - setDeployConfig({ - semossUrl: secrets.semossUrl, - authHeaders: headers, - base64Encoded: encoded, - outputPath: outputZip - }); - - // Retrieve and use the current project ID - const projectId = await getProjectId(context); - if (!projectId) { - vscode.window.showErrorMessage('Unable to find project id in the smss file'); - return; - } - await deployProject(projectId); - } catch (error) { - vscode.window.showErrorMessage(`Error in zip and deploy: ${error.message}`); - } - } - ); - - // Register zip only command - const disposableZip = vscode.commands.registerCommand( - "semoss.ziponly", - async (uri) => { - // If called from Chatbot UI, uri may be undefined. Use first workspace folder. - if (!uri || !uri.fsPath) { - if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) { - uri = vscode.workspace.workspaceFolders[0].uri; - } else { - vscode.window.showErrorMessage('No workspace folder found.'); - return; - } - } - try { - setFolderPaths(uri); - await zipProject(); - } catch (error) { - vscode.window.showErrorMessage(`Error in zip: ${error.message}`); - } - } - ); - - // Register deploy only command - const disposableDeploy = vscode.commands.registerCommand( - "semoss.deployonly", - async (uri) => { - // Always deploy assets.zip from the selected or first workspace folder - if (!uri || !uri.fsPath) { - if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) { - uri = vscode.workspace.workspaceFolders[0].uri; - } else { - vscode.window.showErrorMessage('No workspace folder found.'); - return; - } - } - try { - // Find zip files in the directory - const zipFiles = fs.readdirSync(uri.fsPath).filter(file => file.endsWith('.zip')); - let outputZip; - - if (zipFiles.length === 0) { - vscode.window.showErrorMessage('No zip files found in the selected folder. Please create a zip file first using "Zip Only" command or manually.'); - return; - } else if (zipFiles.includes('assets.zip')) { - // Prefer assets.zip if it exists - outputZip = path.join(uri.fsPath, 'assets.zip'); - vscode.window.showInformationMessage('Using preferred zip file: assets.zip'); - } else if (zipFiles.length === 1) { - // If only one zip file exists (and it's not assets.zip), use it - outputZip = path.join(uri.fsPath, zipFiles[0]); - vscode.window.showInformationMessage(`Using zip file: ${zipFiles[0]}`); - } else { - // Multiple zip files exist, let user choose - const selectedZip = await vscode.window.showQuickPick(zipFiles, { - placeHolder: 'Multiple zip files found. Select one to deploy:', - canPickMany: false - }); - if (!selectedZip) { - vscode.window.showInformationMessage('Deploy cancelled.'); - return; - } - outputZip = path.join(uri.fsPath, selectedZip); - vscode.window.showInformationMessage(`Selected zip file: ${selectedZip}`); - } - - // Validate the zip file exists and is readable - if (!fs.existsSync(outputZip)) { - vscode.window.showErrorMessage(`Selected zip file does not exist: ${path.basename(outputZip)}`); - return; - } - - // Check if file is not empty - const stats = fs.statSync(outputZip); - if (stats.size === 0) { - vscode.window.showErrorMessage(`Selected zip file is empty: ${path.basename(outputZip)}`); - return; - } - - vscode.window.showInformationMessage(`Ready to deploy: ${path.basename(outputZip)} (${Math.round(stats.size / 1024)} KB)`); - - const secrets = await getSecretsWithValidation(context); - if (!secrets) return; - - setFolderPaths(uri); - - // Retrieve and use the current project ID - const projectId = await getProjectId(context); - if (!projectId) { - vscode.window.showErrorMessage('Unable to find project id in the smss file'); - return; - } - - // Configure deployment to use assets.zip - const encoded = Buffer.from(secrets.accessKey + ':' + secrets.privateKey).toString('base64'); - const headers = { 'Authorization': 'Basic ' + encoded }; - - setDeployConfig({ - semossUrl: secrets.semossUrl, - authHeaders: headers, - base64Encoded: encoded, - outputPath: outputZip - }); - - await deployProject(projectId); - } catch (error) { - vscode.window.showErrorMessage(`Error in deploy: ${error.message}`); - } - } - ); - - // Register chatbot action command for programmatic use - const disposableChatbot = vscode.commands.registerCommand( - "semoss.chatbotAction", - async (action, options = {}) => { - if (action === 'removeInstance') { - // Using the already imported getStoredInstances from the top of the file - const instances = await getStoredInstances(context); - const aliases = Object.keys(instances); - if (aliases.length === 0) { - vscode.window.showWarningMessage('No stored instances found.'); - return; - } - const items = aliases.map(alias => ({ - label: alias, - description: instances[alias].semossUrl - })); - const selected = await vscode.window.showQuickPick(items, { - placeHolder: 'Select instance to remove' - }); - if (selected) { - const confirm = await vscode.window.showQuickPick(['Yes', 'No'], { - placeHolder: `Are you sure you want to remove "${selected.label}"?` - }); - if (confirm === 'Yes') { - delete instances[selected.label]; - await context.secrets.store('SEMOSS_INSTANCES', JSON.stringify(instances)); - // If this was the current instance, clear it - const currentAlias = await context.secrets.get('CURRENT_INSTANCE_ALIAS'); - if (currentAlias === selected.label) { - await context.secrets.delete('CURRENT_INSTANCE_ALIAS'); - } - // Always update status bar after instance removal - await updateStatusBar(context); - vscode.window.showInformationMessage(`Instance "${selected.label}" removed successfully!`); - } - } - return; - } - await handleChatbotAction(action, options, context); - } - ); - context.subscriptions.push(disposableChatbot); - - // Register command to open the chatbot sidebar - const disposableOpenChatbot = vscode.commands.registerCommand( - "semoss.openChatbot", - () => { - // Reveal the Semoss Chatbot sidebar container - vscode.commands.executeCommand('workbench.view.extension.semossChatbotContainer'); - // Reveal the chatbot view inside the container - vscode.commands.executeCommand('workbench.view.extension.semossChatbotView'); - } - ); - context.subscriptions.push(disposableOpenChatbot); - - // Check if credentials are available and show status - const secrets = await getSecrets(context); - - - if (secrets && secrets.semossUrl && secrets.accessKey && secrets.privateKey) { - vscode.window.showInformationMessage(`Semoss: Connected to "${secrets.alias || 'Default'}" (${secrets.semossUrl})`); - context.subscriptions.push(disposableAuthorize, disposableZipDeploy, disposableZip, disposableDeploy, disposableSelectInstance, disposableRemoveInstance); - } else { - vscode.window.showErrorMessage('Semoss: No instance configured. Use "Semoss: Authorize New Instance" to get started.'); - context.subscriptions.push(disposableAuthorize, disposableSelectInstance, disposableRemoveInstance); // Add instance management commands even if not authenticated - } + // Initialize the status bar + initStatusBar(context); + await updateStatusBar(context); + + // Register the chatbot webview + registerChatbotWebview(context); + + // Register authorize command (add new instance) + const disposableAuthorize = vscode.commands.registerCommand( + "semoss.authorize", + async (args) => { + // If called from chatbot, use args; otherwise, prompt + if ( + args && + args.alias && + args.url && + args.accessKey && + args.privateKey + ) { + await storeInstance(context, args.alias, { + semossUrl: args.url, + accessKey: args.accessKey, + privateKey: args.privateKey, + }); + await context.secrets.store( + "CURRENT_INSTANCE_ALIAS", + args.alias, + ); + await updateStatusBar(context); + vscode.window.showInformationMessage( + `Instance "${args.alias}" saved successfully!`, + ); + vscode.commands.executeCommand("workbench.action.reloadWindow"); + } else { + await storeSecrets(context); + vscode.commands.executeCommand("workbench.action.reloadWindow"); + } + }, + ); + + // Register select instance command + const disposableSelectInstance = vscode.commands.registerCommand( + "semoss.selectInstance", + async (args) => { + if (args && args.alias) { + await context.secrets.store( + "CURRENT_INSTANCE_ALIAS", + args.alias, + ); + await updateStatusBar(context); + vscode.window.showInformationMessage( + `Switched to instance: ${args.alias}`, + ); + vscode.commands.executeCommand("workbench.action.reloadWindow"); + } else { + const selected = await selectInstance(context); + if (selected) { + await updateStatusBar(context); + vscode.commands.executeCommand( + "workbench.action.reloadWindow", + ); + } + } + }, + ); + + // Register remove instance command + const disposableRemoveInstance = vscode.commands.registerCommand( + "semoss.removeInstance", + async (args) => { + if (args && args.alias) { + const instances = await getStoredInstances(context); + if (instances[args.alias]) { + delete instances[args.alias]; + await context.secrets.store( + "SEMOSS_INSTANCES", + JSON.stringify(instances), + ); + const currentAlias = await context.secrets.get( + "CURRENT_INSTANCE_ALIAS", + ); + if (currentAlias === args.alias) { + await context.secrets.delete("CURRENT_INSTANCE_ALIAS"); + } + // Always update status bar after instance removal + await updateStatusBar(context); + vscode.window.showInformationMessage( + `Instance "${args.alias}" removed successfully!`, + ); + } else { + vscode.window.showWarningMessage( + `Instance "${args.alias}" not found.`, + ); + } + } else { + await removeInstance(context); + await updateStatusBar(context); + } + }, + ); // Helper function to get secrets with error handling + const getSecretsWithValidation = async (context) => { + const secrets = await getSecrets(context); + if ( + !secrets || + !secrets.semossUrl || + !secrets.accessKey || + !secrets.privateKey + ) { + vscode.window.showErrorMessage( + "No instance configured. Please authorize an instance first.", + ); + return null; + } + return secrets; + }; + + // Register create new project command + const disposableCreateApp = vscode.commands.registerCommand( + "semoss.createNewApp", + async (args) => { + try { + if (args && args.appName) { + await createNewApp(context, getSecretsWithValidation, args); + } else { + await createNewApp(context, getSecretsWithValidation); + } + } catch (error) { + vscode.window.showErrorMessage( + `App creation failed: ${error.message}`, + ); + console.error("Error in createNewApp:", error); + } + }, + ); + context.subscriptions.push(disposableCreateApp); + + // Register zip and deploy command + const disposableZipDeploy = vscode.commands.registerCommand( + "semoss.zipanddeploy", + async (uri) => { + // If called from Chatbot UI, uri may be undefined. Use first workspace folder. + if (!uri || !uri.fsPath) { + if ( + vscode.workspace.workspaceFolders && + vscode.workspace.workspaceFolders.length > 0 + ) { + uri = vscode.workspace.workspaceFolders[0].uri; + } else { + vscode.window.showErrorMessage( + "No workspace folder found.", + ); + return; + } + } + try { + const secrets = await getSecretsWithValidation(context); + if (!secrets) return; + + setFolderPaths(uri); + + // Zip the project (json, smss, assets as assets.zip) + await zipProject(); + + // Find the zip file that was created (should be assets.zip, but let's be flexible) + const zipFiles = fs + .readdirSync(uri.fsPath) + .filter((file) => file.endsWith(".zip")); + let outputZip; + + if (zipFiles.includes("assets.zip")) { + // Prefer assets.zip if it exists (which it should after zipProject()) + outputZip = path.join(uri.fsPath, "assets.zip"); + } else if (zipFiles.length > 0) { + // Use the first zip file found + outputZip = path.join(uri.fsPath, zipFiles[0]); + vscode.window.showInformationMessage( + `Using zip file: ${zipFiles[0]}`, + ); + } else { + vscode.window.showErrorMessage( + "No zip file was created during the zip process.", + ); + return; + } + + // Validate the zip file exists and is readable + if (!fs.existsSync(outputZip)) { + vscode.window.showErrorMessage( + `Zip file does not exist: ${path.basename(outputZip)}`, + ); + return; + } + + // Check if file is not empty + const stats = fs.statSync(outputZip); + if (stats.size === 0) { + vscode.window.showErrorMessage( + `Zip file is empty: ${path.basename(outputZip)}`, + ); + return; + } + + vscode.window.showInformationMessage( + `Created and ready to deploy: ${path.basename(outputZip)} (${Math.round(stats.size / 1024)} KB)`, + ); + + // Configure deployment to use the found zip file + const encoded = Buffer.from( + secrets.accessKey + ":" + secrets.privateKey, + ).toString("base64"); + const headers = { Authorization: "Basic " + encoded }; + + setDeployConfig({ + semossUrl: secrets.semossUrl, + authHeaders: headers, + base64Encoded: encoded, + outputPath: outputZip, + }); + + // Retrieve and use the current project ID + const projectId = await getProjectId(context); + if (!projectId) { + vscode.window.showErrorMessage( + "Unable to find project id in the smss file", + ); + return; + } + await deployProject(projectId); + } catch (error) { + vscode.window.showErrorMessage( + `Error in zip and deploy: ${error.message}`, + ); + } + }, + ); + + // Register zip only command + const disposableZip = vscode.commands.registerCommand( + "semoss.ziponly", + async (uri) => { + // If called from Chatbot UI, uri may be undefined. Use first workspace folder. + if (!uri || !uri.fsPath) { + if ( + vscode.workspace.workspaceFolders && + vscode.workspace.workspaceFolders.length > 0 + ) { + uri = vscode.workspace.workspaceFolders[0].uri; + } else { + vscode.window.showErrorMessage( + "No workspace folder found.", + ); + return; + } + } + try { + setFolderPaths(uri); + await zipProject(); + } catch (error) { + vscode.window.showErrorMessage( + `Error in zip: ${error.message}`, + ); + } + }, + ); + + // Register deploy only command + const disposableDeploy = vscode.commands.registerCommand( + "semoss.deployonly", + async (uri) => { + // Always deploy assets.zip from the selected or first workspace folder + if (!uri || !uri.fsPath) { + if ( + vscode.workspace.workspaceFolders && + vscode.workspace.workspaceFolders.length > 0 + ) { + uri = vscode.workspace.workspaceFolders[0].uri; + } else { + vscode.window.showErrorMessage( + "No workspace folder found.", + ); + return; + } + } + try { + // Find zip files in the directory + const zipFiles = fs + .readdirSync(uri.fsPath) + .filter((file) => file.endsWith(".zip")); + let outputZip; + + if (zipFiles.length === 0) { + vscode.window.showErrorMessage( + 'No zip files found in the selected folder. Please create a zip file first using "Zip Only" command or manually.', + ); + return; + } else if (zipFiles.includes("assets.zip")) { + // Prefer assets.zip if it exists + outputZip = path.join(uri.fsPath, "assets.zip"); + vscode.window.showInformationMessage( + "Using preferred zip file: assets.zip", + ); + } else if (zipFiles.length === 1) { + // If only one zip file exists (and it's not assets.zip), use it + outputZip = path.join(uri.fsPath, zipFiles[0]); + vscode.window.showInformationMessage( + `Using zip file: ${zipFiles[0]}`, + ); + } else { + // Multiple zip files exist, let user choose + const selectedZip = await vscode.window.showQuickPick( + zipFiles, + { + placeHolder: + "Multiple zip files found. Select one to deploy:", + canPickMany: false, + }, + ); + if (!selectedZip) { + vscode.window.showInformationMessage( + "Deploy cancelled.", + ); + return; + } + outputZip = path.join(uri.fsPath, selectedZip); + vscode.window.showInformationMessage( + `Selected zip file: ${selectedZip}`, + ); + } + + // Validate the zip file exists and is readable + if (!fs.existsSync(outputZip)) { + vscode.window.showErrorMessage( + `Selected zip file does not exist: ${path.basename(outputZip)}`, + ); + return; + } + + // Check if file is not empty + const stats = fs.statSync(outputZip); + if (stats.size === 0) { + vscode.window.showErrorMessage( + `Selected zip file is empty: ${path.basename(outputZip)}`, + ); + return; + } + + vscode.window.showInformationMessage( + `Ready to deploy: ${path.basename(outputZip)} (${Math.round(stats.size / 1024)} KB)`, + ); + + const secrets = await getSecretsWithValidation(context); + if (!secrets) return; + + setFolderPaths(uri); + + // Retrieve and use the current project ID + const projectId = await getProjectId(context); + if (!projectId) { + vscode.window.showErrorMessage( + "Unable to find project id in the smss file", + ); + return; + } + + // Configure deployment to use assets.zip + const encoded = Buffer.from( + secrets.accessKey + ":" + secrets.privateKey, + ).toString("base64"); + const headers = { Authorization: "Basic " + encoded }; + + setDeployConfig({ + semossUrl: secrets.semossUrl, + authHeaders: headers, + base64Encoded: encoded, + outputPath: outputZip, + }); + + await deployProject(projectId); + } catch (error) { + vscode.window.showErrorMessage( + `Error in deploy: ${error.message}`, + ); + } + }, + ); + + // Register chatbot action command for programmatic use + const disposableChatbot = vscode.commands.registerCommand( + "semoss.chatbotAction", + async (action, options = {}) => { + if (action === "removeInstance") { + // Using the already imported getStoredInstances from the top of the file + const instances = await getStoredInstances(context); + const aliases = Object.keys(instances); + if (aliases.length === 0) { + vscode.window.showWarningMessage( + "No stored instances found.", + ); + return; + } + const items = aliases.map((alias) => ({ + label: alias, + description: instances[alias].semossUrl, + })); + const selected = await vscode.window.showQuickPick(items, { + placeHolder: "Select instance to remove", + }); + if (selected) { + const confirm = await vscode.window.showQuickPick( + ["Yes", "No"], + { + placeHolder: `Are you sure you want to remove "${selected.label}"?`, + }, + ); + if (confirm === "Yes") { + delete instances[selected.label]; + await context.secrets.store( + "SEMOSS_INSTANCES", + JSON.stringify(instances), + ); + // If this was the current instance, clear it + const currentAlias = await context.secrets.get( + "CURRENT_INSTANCE_ALIAS", + ); + if (currentAlias === selected.label) { + await context.secrets.delete( + "CURRENT_INSTANCE_ALIAS", + ); + } + // Always update status bar after instance removal + await updateStatusBar(context); + vscode.window.showInformationMessage( + `Instance "${selected.label}" removed successfully!`, + ); + } + } + return; + } + await handleChatbotAction(action, options, context); + }, + ); + context.subscriptions.push(disposableChatbot); + + // Register command to open the chatbot sidebar + const disposableOpenChatbot = vscode.commands.registerCommand( + "semoss.openChatbot", + () => { + // Reveal the Semoss Chatbot sidebar container + vscode.commands.executeCommand( + "workbench.view.extension.semossChatbotContainer", + ); + // Reveal the chatbot view inside the container + vscode.commands.executeCommand( + "workbench.view.extension.semossChatbotView", + ); + }, + ); + context.subscriptions.push(disposableOpenChatbot); + + // Check if credentials are available and show status + const secrets = await getSecrets(context); + + if ( + secrets && + secrets.semossUrl && + secrets.accessKey && + secrets.privateKey + ) { + vscode.window.showInformationMessage( + `Semoss: Connected to "${secrets.alias || "Default"}" (${secrets.semossUrl})`, + ); + context.subscriptions.push( + disposableAuthorize, + disposableZipDeploy, + disposableZip, + disposableDeploy, + disposableSelectInstance, + disposableRemoveInstance, + ); + } else { + vscode.window.showErrorMessage( + 'Semoss: No instance configured. Use "Semoss: Authorize New Instance" to get started.', + ); + context.subscriptions.push( + disposableAuthorize, + disposableSelectInstance, + disposableRemoveInstance, + ); // Add instance management commands even if not authenticated + } } // This method is called when your extension is deactivated -function deactivate() { } +function deactivate() {} module.exports = { activate, deactivate }; diff --git a/packages/vscode-extension/jsconfig.json b/packages/vscode-extension/jsconfig.json index 7998b4ed38..f4e4bbd81c 100644 --- a/packages/vscode-extension/jsconfig.json +++ b/packages/vscode-extension/jsconfig.json @@ -2,15 +2,11 @@ "compilerOptions": { "module": "ES2022", "target": "ES2022", - "checkJs": false, /* Typecheck .js files. */ - "lib": [ - "ES2022" - ], + "checkJs": false /* Typecheck .js files. */, + "lib": ["ES2022"], "moduleResolution": "node", "allowJs": true, "esModuleInterop": true }, - "exclude": [ - "node_modules" - ] -} \ No newline at end of file + "exclude": ["node_modules"] +} diff --git a/packages/vscode-extension/src/components/Chatbot-ui/script.js b/packages/vscode-extension/src/components/Chatbot-ui/script.js index 3774b360ea..cca384ecda 100644 --- a/packages/vscode-extension/src/components/Chatbot-ui/script.js +++ b/packages/vscode-extension/src/components/Chatbot-ui/script.js @@ -4,876 +4,1037 @@ */ class SemossChatbot { - constructor() { - this.vscode = acquireVsCodeApi(); - this.state = { - chatStarted: false, - currentState: 'start', - lastCommand: null, - chatHistory: [], - isLoading: false, - // Add viewport state - viewport: { - width: window.innerWidth, - height: window.innerHeight, - isSmallPhone: window.innerWidth <= 375, - isMobile: window.innerWidth <= 768, - isLandscape: window.innerWidth > window.innerHeight - } - }; - - // DOM elements - this.elements = { - chat: document.getElementById('chat'), - startArea: document.getElementById('start-area'), - startBtn: document.getElementById('start-btn'), - optionsArea: document.getElementById('options-area'), - inputArea: document.getElementById('input-area'), - clearChatBtn: document.getElementById('clear-chat-btn'), - downloadManualBtn: document.getElementById('download-manual-btn'), - chatContainer: document.getElementById('chat-container'), - chatHeader: document.getElementById('chat-header'), - loader: document.getElementById('loader'), - toastContainer: document.getElementById('toast-container') - }; - - this.init(); - } - - /** - * Initialize the chatbot - */ - init() { - this.bindEvents(); - this.requestHistoryRestore(); - this.updateChatHeaderVisibility(); - - // Initial viewport adjustment - this.handleViewportChange(); - - // Add viewport-aware class to body - document.body.classList.add(this.state.viewport.isMobile ? 'mobile-device' : 'desktop-device'); - if (this.state.viewport.isLandscape) { - document.body.classList.add('landscape'); - } else { - document.body.classList.add('portrait'); - } - } - - /** - * Bind event listeners - */ bindEvents() { - // Start button - if (this.elements.startBtn) { - this.elements.startBtn.addEventListener('click', () => this.showOptions()); - } - - // Clear chat button - if (this.elements.clearChatBtn) { - this.elements.clearChatBtn.addEventListener('click', () => this.clearChat()); - } - - // Download user manual button - if (this.elements.downloadManualBtn) { - this.elements.downloadManualBtn.addEventListener('click', () => this.downloadUserManual()); - } - - // Window message listener - window.addEventListener('message', (event) => this.handleMessage(event)); - - // Keyboard shortcuts - document.addEventListener('keydown', (event) => this.handleKeyboard(event)); - - // Handle visibility changes - document.addEventListener('visibilitychange', () => { - if (!document.hidden) { - this.requestHistoryRestore(); - } - }); - - // Handle viewport changes for responsive design - window.addEventListener('resize', () => this.handleViewportChange()); - window.addEventListener('orientationchange', () => this.handleViewportChange()); - } - - /** - * Handle keyboard shortcuts - */ - handleKeyboard(event) { - // Ctrl/Cmd + K to clear chat - if ((event.ctrlKey || event.metaKey) && event.key === 'k') { - event.preventDefault(); - this.clearChat(); - } - - // Escape to close dialogs - if (event.key === 'Escape') { - const dialog = document.querySelector('.input-dialog'); - if (dialog) { - dialog.remove(); - } - } - } - - /** - * Request history restoration from VS Code - */ - requestHistoryRestore() { - setTimeout(() => { - this.vscode.postMessage({ type: 'getHistory' }); - this.updateChatHeaderVisibility(); - }, 100); - } - - /** - * Handle messages from VS Code extension - */ - handleMessage(event) { - const message = event.data; - - switch (message.type) { - case 'restoreHistory': - this.restoreHistory(message.history); - this.state.currentState = message.state || 'start'; - if (this.state.currentState === 'options' && this.state.chatStarted) { - this.showOptions(); - } - break; - - case 'response': - this.handleResponse(message); - break; - - case 'smssFileCheckResult': - this.handleSmssFileCheck(message); - break; - - case 'instanceAuthorizedResult': - this.handleInstanceAuthorized(message); - break; - - case 'instanceAliases': - this.handleInstanceAliases(message); - break; - - case 'instanceAliasesWithUrls': - this.handleInstanceAliasesWithUrls(message); - break; - - case 'instanceAliasesForRemoval': - this.handleInstanceAliasesForRemoval(message); - break; - - default: - console.warn('Unknown message type:', message.type); - } - } - - /** - * Handle response messages - */ - handleResponse(message) { - // Hide loading for specific commands - if (this.shouldHideLoading(message)) { - this.hideLoading(); - } - - // Handle successful removal - if (message.status === 'success' && message.text && message.text.includes('removed successfully')) { - this.elements.optionsArea.innerHTML = ''; - this.showOptions(); - } - - const messageClass = message.status === 'error' ? 'error' : 'bot'; - this.appendMessage(message.text, messageClass); - - // Handle authorization success - if (message.status === 'success' && this.state.lastCommand === 'semoss.authorize') { - this.saveState('authorized'); - this.showOptions(); - } - } - - /** - * Check if loading should be hidden for this message - */ - shouldHideLoading(message) { - return (message.text && ( - message.text.includes('Project zipped as assets.zip successfully!') || - message.text.toLowerCase().includes('deployed successfully') || - message.text.toLowerCase().includes('zip and deploy') - )) || message.hideLoading; - } - - /** - * Handle SMSS file check result - */ - handleSmssFileCheck(message) { - this.elements.optionsArea.innerHTML = ''; - - const options = message.hasSmss ? [ - { label: 'Zip and Deploy', command: 'semoss.zipanddeploy', icon: '🚀' }, - { label: 'Zip Only', command: 'semoss.ziponly', icon: '📦' }, - { label: 'Deploy Only', command: 'semoss.deployonly', icon: '🌐' } - ] : [ - { label: 'Create New App', command: 'semoss.createNewApp', icon: '✨' }, - { label: 'Authorize New Instance', command: 'semoss.authorize', icon: '🔐' }, - { label: 'Select Instance', command: 'semoss.selectInstance', icon: '🔄' }, - { label: 'Remove Instance', command: 'semoss.removeInstance', icon: '🗑️' } - ]; - - this.renderOptions(options); - } - - /** - * Handle instance authorized result - */ - async handleInstanceAuthorized(message) { - if (message.authorized) { - const requiredInputs = this.getRequiredInputs('semoss.createNewApp'); - const inputs = await this.showInputDialog(requiredInputs); - if (!inputs) return; - - this.appendMessage('Create New App with details:', 'user'); - this.displayInputs(inputs, { - 'appName': 'App Name', - 'description': 'Description', - 'githubLink': 'GitHub Link', - 'isPrivateRepo': 'Private Repository', - 'accessToken': 'Access Token' - }); - - this.showLoading(); - this.state.lastCommand = 'semoss.createNewApp'; - this.vscode.postMessage({ type: 'chat', command: 'semoss.createNewApp', inputs }); - } else { - this.appendMessage('Please authorize an instance first.', 'bot'); - } - } - - /** - * Handle instance aliases - */ - handleInstanceAliases(message) { - this.hideLoading(); - if (Array.isArray(message.aliases) && message.aliases.length > 0) { - this.showInstanceSelection(message.aliases); - } else { - this.appendMessage('No stored instances found. Please authorize a new instance first.', 'bot'); - } - } - - /** - * Handle instance aliases with URLs - */ - handleInstanceAliasesWithUrls(message) { - this.hideLoading(); - window.semossInstanceUrls = message.urls; - window.currentInstance = message.currentInstance; - this.showInstanceSelection(message.aliases); - } - - /** - * Handle instance aliases for removal - */ - handleInstanceAliasesForRemoval(message) { - window.semossInstanceUrls = message.urls; - window.currentInstance = message.currentInstance; - - this.elements.optionsArea.innerHTML = ''; - this.appendMessage('Select an instance to remove:', 'bot'); - - // If there are multiple aliases, use grid layout - if (message.aliases.length > 1) { - this.elements.optionsArea.classList.add('options-grid'); - } else { - this.elements.optionsArea.classList.remove('options-grid'); - } - - message.aliases.forEach(alias => { - // Create label with URL if available - let label = alias; - if (window.semossInstanceUrls && window.semossInstanceUrls[alias]) { - label = `${alias} (${window.semossInstanceUrls[alias]})`; - } - - const btn = this.createOptionButton(label, () => { - this.showRemoveInstanceConfirmation(alias); - }); - - if (window.currentInstance === alias) { - btn.classList.add('selected-instance'); - } - - this.elements.optionsArea.appendChild(btn); - }); - - // Add back button - const backBtn = this.createBackButton(() => { - this.appendMessage('Instance removal cancelled. No instances were removed.', 'bot'); - this.showOptions(); - }); - this.elements.optionsArea.appendChild(backBtn); - - // Apply viewport-specific adjustments - this.adjustOptionsForViewport(); - } - - /** - * Append a message to the chat with enhanced responsive rendering - * @param {string} text - The message text - * @param {string} from - Who sent the message ('user' or 'bot') - * @param {boolean} saveToHistory - Whether to save to history - * @param {string} status - Message status for styling ('success', 'error', 'warning') - */ - appendMessage(text, from, saveToHistory = true, status = null) { - const { isMobile, isSmallPhone, isLandscape, width } = this.state.viewport; - - // Create message container with accessibility attributes - const msgDiv = document.createElement('div'); - msgDiv.className = `message ${from}${status ? ' ' + status : ''}`; - msgDiv.setAttribute('role', 'listitem'); - msgDiv.setAttribute('aria-label', `${from === 'user' ? 'You' : 'Bot'}: ${typeof text === 'string' ? text.replace(/<[^>]*>/g, '') : 'Message'}`); - - // Add timestamp as data attribute for potential display - msgDiv.dataset.timestamp = new Date().toISOString(); - - // Create message bubble - const bubble = document.createElement('div'); - bubble.className = 'bubble'; - - // Process text content for responsive display - if (typeof text === 'string') { - // Create a container for the processed content - let processedContent = this.escapeHtml(text); - - // Handle code blocks for better mobile display - const codeBlockRegex = /```([\s\S]*?)```/g; - processedContent = processedContent.replace(codeBlockRegex, (match, code) => { - // Apply special formatting for code blocks on mobile - if (isMobile && isSmallPhone) { - return `
    ${this.escapeHtml(code.trim())}
    `; - } else if (isMobile) { - return `
    ${this.escapeHtml(code.trim())}
    `; - } else { - return `
    ${this.escapeHtml(code.trim())}
    `; - } - }); - - // Handle inline code for better mobile display - const inlineCodeRegex = /`([^`]+)`/g; - processedContent = processedContent.replace(inlineCodeRegex, (match, code) => { - return `${this.escapeHtml(code)}`; - }); - - // Convert URLs to responsive clickable links/images - const urlRegex = /(https?:\/\/[^\s]+)/g; - processedContent = processedContent.replace(urlRegex, (url) => { - // Check if URL might be an image - const isImage = /\.(jpg|jpeg|png|gif|svg|webp)$/i.test(url); - - if (isImage) { - if (isMobile && isSmallPhone) { - // Tiny thumbnail for small phones - return `
    + constructor() { + this.vscode = acquireVsCodeApi(); + this.state = { + chatStarted: false, + currentState: "start", + lastCommand: null, + chatHistory: [], + isLoading: false, + // Add viewport state + viewport: { + width: window.innerWidth, + height: window.innerHeight, + isSmallPhone: window.innerWidth <= 375, + isMobile: window.innerWidth <= 768, + isLandscape: window.innerWidth > window.innerHeight, + }, + }; + + // DOM elements + this.elements = { + chat: document.getElementById("chat"), + startArea: document.getElementById("start-area"), + startBtn: document.getElementById("start-btn"), + optionsArea: document.getElementById("options-area"), + inputArea: document.getElementById("input-area"), + clearChatBtn: document.getElementById("clear-chat-btn"), + downloadManualBtn: document.getElementById("download-manual-btn"), + chatContainer: document.getElementById("chat-container"), + chatHeader: document.getElementById("chat-header"), + loader: document.getElementById("loader"), + toastContainer: document.getElementById("toast-container"), + }; + + this.init(); + } + + /** + * Initialize the chatbot + */ + init() { + this.bindEvents(); + this.requestHistoryRestore(); + this.updateChatHeaderVisibility(); + + // Initial viewport adjustment + this.handleViewportChange(); + + // Add viewport-aware class to body + document.body.classList.add( + this.state.viewport.isMobile ? "mobile-device" : "desktop-device", + ); + if (this.state.viewport.isLandscape) { + document.body.classList.add("landscape"); + } else { + document.body.classList.add("portrait"); + } + } + + /** + * Bind event listeners + */ bindEvents() { + // Start button + if (this.elements.startBtn) { + this.elements.startBtn.addEventListener("click", () => + this.showOptions(), + ); + } + + // Clear chat button + if (this.elements.clearChatBtn) { + this.elements.clearChatBtn.addEventListener("click", () => + this.clearChat(), + ); + } + + // Download user manual button + if (this.elements.downloadManualBtn) { + this.elements.downloadManualBtn.addEventListener("click", () => + this.downloadUserManual(), + ); + } + + // Window message listener + window.addEventListener("message", (event) => + this.handleMessage(event), + ); + + // Keyboard shortcuts + document.addEventListener("keydown", (event) => + this.handleKeyboard(event), + ); + + // Handle visibility changes + document.addEventListener("visibilitychange", () => { + if (!document.hidden) { + this.requestHistoryRestore(); + } + }); + + // Handle viewport changes for responsive design + window.addEventListener("resize", () => this.handleViewportChange()); + window.addEventListener("orientationchange", () => + this.handleViewportChange(), + ); + } + + /** + * Handle keyboard shortcuts + */ + handleKeyboard(event) { + // Ctrl/Cmd + K to clear chat + if ((event.ctrlKey || event.metaKey) && event.key === "k") { + event.preventDefault(); + this.clearChat(); + } + + // Escape to close dialogs + if (event.key === "Escape") { + const dialog = document.querySelector(".input-dialog"); + if (dialog) { + dialog.remove(); + } + } + } + + /** + * Request history restoration from VS Code + */ + requestHistoryRestore() { + setTimeout(() => { + this.vscode.postMessage({ type: "getHistory" }); + this.updateChatHeaderVisibility(); + }, 100); + } + + /** + * Handle messages from VS Code extension + */ + handleMessage(event) { + const message = event.data; + + switch (message.type) { + case "restoreHistory": + this.restoreHistory(message.history); + this.state.currentState = message.state || "start"; + if ( + this.state.currentState === "options" && + this.state.chatStarted + ) { + this.showOptions(); + } + break; + + case "response": + this.handleResponse(message); + break; + + case "smssFileCheckResult": + this.handleSmssFileCheck(message); + break; + + case "instanceAuthorizedResult": + this.handleInstanceAuthorized(message); + break; + + case "instanceAliases": + this.handleInstanceAliases(message); + break; + + case "instanceAliasesWithUrls": + this.handleInstanceAliasesWithUrls(message); + break; + + case "instanceAliasesForRemoval": + this.handleInstanceAliasesForRemoval(message); + break; + + default: + console.warn("Unknown message type:", message.type); + } + } + + /** + * Handle response messages + */ + handleResponse(message) { + // Hide loading for specific commands + if (this.shouldHideLoading(message)) { + this.hideLoading(); + } + + // Handle successful removal + if ( + message.status === "success" && + message.text && + message.text.includes("removed successfully") + ) { + this.elements.optionsArea.innerHTML = ""; + this.showOptions(); + } + + const messageClass = message.status === "error" ? "error" : "bot"; + this.appendMessage(message.text, messageClass); + + // Handle authorization success + if ( + message.status === "success" && + this.state.lastCommand === "semoss.authorize" + ) { + this.saveState("authorized"); + this.showOptions(); + } + } + + /** + * Check if loading should be hidden for this message + */ + shouldHideLoading(message) { + return ( + (message.text && + (message.text.includes( + "Project zipped as assets.zip successfully!", + ) || + message.text + .toLowerCase() + .includes("deployed successfully") || + message.text.toLowerCase().includes("zip and deploy"))) || + message.hideLoading + ); + } + + /** + * Handle SMSS file check result + */ + handleSmssFileCheck(message) { + this.elements.optionsArea.innerHTML = ""; + + const options = message.hasSmss + ? [ + { + label: "Zip and Deploy", + command: "semoss.zipanddeploy", + icon: "🚀", + }, + { + label: "Zip Only", + command: "semoss.ziponly", + icon: "📦", + }, + { + label: "Deploy Only", + command: "semoss.deployonly", + icon: "🌐", + }, + ] + : [ + { + label: "Create New App", + command: "semoss.createNewApp", + icon: "✨", + }, + { + label: "Authorize New Instance", + command: "semoss.authorize", + icon: "🔐", + }, + { + label: "Select Instance", + command: "semoss.selectInstance", + icon: "🔄", + }, + { + label: "Remove Instance", + command: "semoss.removeInstance", + icon: "🗑️", + }, + ]; + + this.renderOptions(options); + } + + /** + * Handle instance authorized result + */ + async handleInstanceAuthorized(message) { + if (message.authorized) { + const requiredInputs = this.getRequiredInputs( + "semoss.createNewApp", + ); + const inputs = await this.showInputDialog(requiredInputs); + if (!inputs) return; + + this.appendMessage("Create New App with details:", "user"); + this.displayInputs(inputs, { + appName: "App Name", + description: "Description", + githubLink: "GitHub Link", + isPrivateRepo: "Private Repository", + accessToken: "Access Token", + }); + + this.showLoading(); + this.state.lastCommand = "semoss.createNewApp"; + this.vscode.postMessage({ + type: "chat", + command: "semoss.createNewApp", + inputs, + }); + } else { + this.appendMessage("Please authorize an instance first.", "bot"); + } + } + + /** + * Handle instance aliases + */ + handleInstanceAliases(message) { + this.hideLoading(); + if (Array.isArray(message.aliases) && message.aliases.length > 0) { + this.showInstanceSelection(message.aliases); + } else { + this.appendMessage( + "No stored instances found. Please authorize a new instance first.", + "bot", + ); + } + } + + /** + * Handle instance aliases with URLs + */ + handleInstanceAliasesWithUrls(message) { + this.hideLoading(); + window.semossInstanceUrls = message.urls; + window.currentInstance = message.currentInstance; + this.showInstanceSelection(message.aliases); + } + + /** + * Handle instance aliases for removal + */ + handleInstanceAliasesForRemoval(message) { + window.semossInstanceUrls = message.urls; + window.currentInstance = message.currentInstance; + + this.elements.optionsArea.innerHTML = ""; + this.appendMessage("Select an instance to remove:", "bot"); + + // If there are multiple aliases, use grid layout + if (message.aliases.length > 1) { + this.elements.optionsArea.classList.add("options-grid"); + } else { + this.elements.optionsArea.classList.remove("options-grid"); + } + + message.aliases.forEach((alias) => { + // Create label with URL if available + let label = alias; + if (window.semossInstanceUrls && window.semossInstanceUrls[alias]) { + label = `${alias} (${window.semossInstanceUrls[alias]})`; + } + + const btn = this.createOptionButton(label, () => { + this.showRemoveInstanceConfirmation(alias); + }); + + if (window.currentInstance === alias) { + btn.classList.add("selected-instance"); + } + + this.elements.optionsArea.appendChild(btn); + }); + + // Add back button + const backBtn = this.createBackButton(() => { + this.appendMessage( + "Instance removal cancelled. No instances were removed.", + "bot", + ); + this.showOptions(); + }); + this.elements.optionsArea.appendChild(backBtn); + + // Apply viewport-specific adjustments + this.adjustOptionsForViewport(); + } + + /** + * Append a message to the chat with enhanced responsive rendering + * @param {string} text - The message text + * @param {string} from - Who sent the message ('user' or 'bot') + * @param {boolean} saveToHistory - Whether to save to history + * @param {string} status - Message status for styling ('success', 'error', 'warning') + */ + appendMessage(text, from, saveToHistory = true, status = null) { + const { isMobile, isSmallPhone, isLandscape, width } = + this.state.viewport; + + // Create message container with accessibility attributes + const msgDiv = document.createElement("div"); + msgDiv.className = `message ${from}${status ? " " + status : ""}`; + msgDiv.setAttribute("role", "listitem"); + msgDiv.setAttribute( + "aria-label", + `${from === "user" ? "You" : "Bot"}: ${typeof text === "string" ? text.replace(/<[^>]*>/g, "") : "Message"}`, + ); + + // Add timestamp as data attribute for potential display + msgDiv.dataset.timestamp = new Date().toISOString(); + + // Create message bubble + const bubble = document.createElement("div"); + bubble.className = "bubble"; + + // Process text content for responsive display + if (typeof text === "string") { + // Create a container for the processed content + let processedContent = this.escapeHtml(text); + + // Handle code blocks for better mobile display + const codeBlockRegex = /```([\s\S]*?)```/g; + processedContent = processedContent.replace( + codeBlockRegex, + (match, code) => { + // Apply special formatting for code blocks on mobile + if (isMobile && isSmallPhone) { + return `
    ${this.escapeHtml(code.trim())}
    `; + } else if (isMobile) { + return `
    ${this.escapeHtml(code.trim())}
    `; + } else { + return `
    ${this.escapeHtml(code.trim())}
    `; + } + }, + ); + + // Handle inline code for better mobile display + const inlineCodeRegex = /`([^`]+)`/g; + processedContent = processedContent.replace( + inlineCodeRegex, + (match, code) => { + return `${this.escapeHtml(code)}`; + }, + ); + + // Convert URLs to responsive clickable links/images + const urlRegex = /(https?:\/\/[^\s]+)/g; + processedContent = processedContent.replace(urlRegex, (url) => { + // Check if URL might be an image + const isImage = /\.(jpg|jpeg|png|gif|svg|webp)$/i.test(url); + + if (isImage) { + if (isMobile && isSmallPhone) { + // Tiny thumbnail for small phones + return `
    🖼️
    `; - } else if (isMobile) { - // Thumbnail with text for regular mobile - return ` + } else if (isMobile) { + // Thumbnail with text for regular mobile + return `
    🖼️ View Image
    `; - } else { - // Actual image for desktop with lazy loading and responsive sizing - return `Image`; - } - } else { - // Format links based on device - let domain = url.replace(/^https?:\/\//, '').split('/')[0]; - const displayText = isSmallPhone ? domain.split('.')[0] + '...' : domain; - - return ` + } + } else { + // Format links based on device + const domain = url + .replace(/^https?:\/\//, "") + .split("/")[0]; + const displayText = isSmallPhone + ? domain.split(".")[0] + "..." + : domain; + + return ` ${displayText} `; - } - }); - - // Process lists for better mobile display - const listRegex = /^([\s]*)[-*+] (.*)/gm; - processedContent = processedContent.replace(listRegex, (match, space, item) => { - const indentLevel = Math.floor(space.length / 2); - const indentClass = indentLevel > 0 ? ` indent-${Math.min(indentLevel, 3)}` : ''; - return `
    • ${item}
    `; - }); - - // Set processed HTML - bubble.innerHTML = processedContent; - - // Add long-text class for very long messages to improve readability - if (text.length > 300) { - bubble.classList.add('long-text'); - } - } else { - // Fallback for non-string content - bubble.textContent = String(text); - } - - // Add status indicator if provided - if (status) { - const statusIndicator = document.createElement('span'); - statusIndicator.className = `status-indicator ${status}`; - - // Use appropriate icon based on status - let icon = '•'; - if (status === 'success') icon = '✓'; - else if (status === 'error') icon = '✗'; - else if (status === 'warning') icon = '⚠'; - - statusIndicator.textContent = icon; - bubble.appendChild(statusIndicator); - } - - // Append elements to DOM - msgDiv.appendChild(bubble); - this.elements.chat.appendChild(msgDiv); - - // Optimize scrolling based on device - const scrollBehavior = (isMobile || isLandscape) ? 'auto' : 'smooth'; - - // Smooth scroll to bottom with device-appropriate behavior - this.elements.chat.scrollTo({ - top: this.elements.chat.scrollHeight, - behavior: scrollBehavior - }); - - // On mobile landscape, ensure we're showing the latest content when keyboard appears - if (isMobile && isLandscape) { - // Double scroll to ensure content is visible - setTimeout(() => { - this.elements.chat.scrollTop = this.elements.chat.scrollHeight; - }, 100); - } - - this.updateChatHeaderVisibility(); - - if (saveToHistory) { - this.vscode.postMessage({ - type: 'saveMessage', - message: { text, from, timestamp: Date.now() } - }); - } - } - - /** - * Restore chat history - */ - restoreHistory(history) { - this.elements.chat.innerHTML = ''; - - history.forEach(msg => { - this.appendMessage(msg.text, msg.from || 'bot', false); - }); - - if (history.length > 0) { - this.state.chatStarted = true; - this.elements.startArea.style.display = 'none'; - } - - this.updateChatHeaderVisibility(); - } - - /** - * Save state to extension - */ - saveState(state) { - this.state.currentState = state; - this.vscode.postMessage({ type: 'saveState', state }); - } - - /** - * Clear chat history and reset state - */ - clearChat() { - // Animate out existing messages - const messages = this.elements.chat.querySelectorAll('.message'); - messages.forEach((msg, index) => { - setTimeout(() => { - msg.style.opacity = '0'; - msg.style.transform = 'translateY(-10px)'; - }, index * 50); - }); - - setTimeout(() => { - this.elements.chat.innerHTML = ''; - this.state.chatStarted = false; - this.state.currentState = 'start'; - - this.elements.startArea.style.display = 'flex'; - this.elements.optionsArea.style.display = 'none'; - - this.vscode.postMessage({ type: 'clearHistory' }); - this.saveState('start'); - this.updateChatHeaderVisibility(); - - this.showToast('Chat cleared successfully', 'success'); - }, messages.length * 50 + 200); - } - - /** - * Update chat header visibility - */ - updateChatHeaderVisibility() { - const shouldShow = this.state.chatStarted || this.elements.chat.children.length > 0; - - if (shouldShow) { - this.elements.chatHeader.style.display = 'flex'; - this.elements.chatContainer.style.display = 'flex'; - this.elements.chatContainer.classList.add('visible'); - } else { - this.elements.chatHeader.style.display = 'none'; - this.elements.chatContainer.style.display = 'none'; - this.elements.chatContainer.classList.remove('visible'); - } - } - - /** - * Show options area with responsive layout - */ - showOptions() { - if (!this.state.chatStarted) { - this.state.chatStarted = true; - this.saveState('options'); - } - - this.elements.startArea.style.display = 'none'; - - // Reset options area completely - this.elements.optionsArea.style.display = 'flex'; - this.elements.optionsArea.innerHTML = ''; - this.elements.optionsArea.className = 'options-container'; - - // Add responsive classes based on viewport - if (this.state.viewport.isMobile) { - this.elements.optionsArea.classList.add('mobile-view'); - } - if (this.state.viewport.isSmallPhone) { - this.elements.optionsArea.classList.add('small-device'); - } - - this.updateChatHeaderVisibility(); - this.vscode.postMessage({ type: 'checkSmssFile' }); - } - - /** - * Render option buttons with responsive layout - */ - renderOptions(options) { - // Clear any existing options - this.elements.optionsArea.innerHTML = ''; - - // If there are multiple options, use grid layout for larger screens - if (options.length > 1) { - this.elements.optionsArea.classList.add('options-grid'); - } else { - this.elements.optionsArea.classList.remove('options-grid'); - } - - options.forEach(opt => { - const btn = this.createOptionButton(opt.label, async () => { - await this.handleOptionClick(opt); - }); - - // Add icon if provided - if (opt.icon) { - if (btn.firstChild && btn.firstChild.className === 'option-content') { - // If we have structured content, add icon to the label - const labelEl = btn.querySelector('.option-label'); - labelEl.innerHTML = `${opt.icon}${labelEl.textContent}`; - } else { - // Standard text content - btn.innerHTML = `${opt.icon}${opt.label}`; - } - } - - this.elements.optionsArea.appendChild(btn); - }); - - // Apply viewport-specific adjustments to the options - this.adjustOptionsForViewport(); - } - - /** - * Adjust options display based on current viewport - */ - adjustOptionsForViewport() { - const { isMobile, isSmallPhone, width } = this.state.viewport; - const options = this.elements.optionsArea; - const buttons = options.querySelectorAll('.option-btn'); - - // For very small screens, apply compact styling - if (isSmallPhone) { - buttons.forEach(btn => { - btn.classList.add('compact'); - - // Simplify content if it has URL parts - const sublabel = btn.querySelector('.option-sublabel'); - if (sublabel && sublabel.textContent.length > 20) { - const url = sublabel.textContent; - // Truncate URL display to save space - sublabel.textContent = url.substring(0, 20) + '...'; - sublabel.title = url; // Keep full URL as tooltip - } - }); - - // Force vertical layout on very small screens - options.classList.remove('options-grid'); - } - // For mobile but not tiny screens - else if (isMobile) { - buttons.forEach(btn => { - btn.classList.remove('compact'); - - // Truncate very long URLs but show more than on tiny screens - const sublabel = btn.querySelector('.option-sublabel'); - if (sublabel && sublabel.textContent.length > 40) { - const url = sublabel.textContent; - sublabel.textContent = url.substring(0, 40) + '...'; - sublabel.title = url; - } - }); - - // Use grid only if we have 3 or fewer options on mobile - if (buttons.length > 3) { - options.classList.remove('options-grid'); - } - } - // For tablets and desktops - else { - buttons.forEach(btn => btn.classList.remove('compact')); - - // Use grid for multiple options - if (buttons.length > 1) { - options.classList.add('options-grid'); - } - } - } - - /** - * Handle option button click - */ - async handleOptionClick(option) { - const { command, label } = option; - - // Special handling for specific commands - switch (command) { - case 'semoss.createNewApp': - this.vscode.postMessage({ type: 'checkInstanceAuthorized' }); - return; - - case 'semoss.authorize': - await this.handleAuthorizeCommand(); - return; - - case 'semoss.selectInstance': - this.showLoading(); - this.vscode.postMessage({ type: 'getInstanceAliases' }); - return; - - case 'semoss.removeInstance': - this.vscode.postMessage({ type: 'getInstanceAliasesForRemoval' }); - return; - } - - // Handle commands that require input - const requiredInputs = this.getRequiredInputs(command); - if (requiredInputs.length > 0) { - const inputs = await this.showInputDialog(requiredInputs); - if (!inputs) return; - - this.appendMessage(`${label} with details:`, 'user'); - Object.entries(inputs).forEach(([key, value]) => { - this.appendMessage(`${key}: ${value}`, 'user'); - }); - - this.showLoading(); - this.state.lastCommand = command; - this.vscode.postMessage({ type: 'chat', command, inputs }); - } else { - this.appendMessage(label, 'user'); - - // Don't show spinner for certain commands - if (!this.shouldSkipLoading(command)) { - this.showLoading(); - } - - this.state.lastCommand = command; - this.vscode.postMessage({ type: 'chat', command }); - } - } - - /** - * Handle authorize command - */ - async handleAuthorizeCommand() { - const requiredInputs = this.getRequiredInputs('semoss.authorize'); - const inputs = await this.showInputDialog(requiredInputs); - if (!inputs) return; - - this.appendMessage('Authorize New Instance with details:', 'user'); - this.displayInputs(inputs, { - 'alias': 'Instance Alias', - 'url': 'Semoss Instance URL', - 'accessKey': 'Access Key', - 'privateKey': 'Private Key' - }); - - this.showLoading(); - this.state.lastCommand = 'semoss.authorize'; - this.vscode.postMessage({ type: 'chat', command: 'semoss.authorize', inputs }); - } - - /** - * Display input values in chat - */ - displayInputs(inputs, fieldLabels) { - Object.entries(inputs).forEach(([key, value]) => { - const displayLabel = fieldLabels[key] || key; - let displayValue = value; - - if (typeof value === 'boolean') { - displayValue = value ? 'Yes' : 'No'; - } - - if (value !== '' && value !== null && value !== undefined) { - this.appendMessage(`${displayLabel}: ${displayValue}`, 'user'); - } - }); - } - - /** - * Check if loading should be skipped for command - */ - shouldSkipLoading(command) { - return ['semoss.ziponly', 'semoss.deployonly', 'semoss.zipanddeploy'].includes(command); - } - - /** - * Show instance selection - */ - showInstanceSelection(aliases) { - this.elements.optionsArea.innerHTML = ''; - this.appendMessage('Select an instance:', 'bot'); - - // If there are multiple aliases, use grid layout - if (aliases.length > 1) { - this.elements.optionsArea.classList.add('options-grid'); - } else { - this.elements.optionsArea.classList.remove('options-grid'); - } - - aliases.forEach(alias => { - // Create label with URL if available - let label = alias; - if (window.semossInstanceUrls && window.semossInstanceUrls[alias]) { - label = `${alias} (${window.semossInstanceUrls[alias]})`; - } - - const btn = this.createOptionButton(label, () => { - this.appendMessage(`Switch to instance: ${alias}`, 'user'); - this.showLoading(); - this.state.lastCommand = 'semoss.selectInstance'; - this.vscode.postMessage({ type: 'chat', command: 'semoss.selectInstance', inputs: { alias } }); - }); - - if (window.currentInstance === alias) { - btn.classList.add('selected-instance'); - } - - this.elements.optionsArea.appendChild(btn); - }); - - // Add back button - const backBtn = this.createBackButton(() => { - this.appendMessage('Instance selection cancelled. No changes were made.', 'bot'); - this.showOptions(); - }); - this.elements.optionsArea.appendChild(backBtn); - - // Apply viewport-specific adjustments - this.adjustOptionsForViewport(); - } - - /** - * Get required inputs for command - */ - getRequiredInputs(command) { - const inputConfigs = { - 'semoss.createNewApp': [ - { name: 'appName', label: 'App Name', placeholder: 'Enter app name', required: true }, - { name: 'description', label: 'Description (optional)', placeholder: 'Enter app description (optional)' }, - { name: 'githubLink', label: 'GitHub Link (optional)', placeholder: 'https://github.com/user/repo' }, - { name: 'isPrivateRepo', label: 'Private Repository', type: 'toggle', defaultValue: false, description: 'Toggle ON for private repositories (requires access token)' }, - { name: 'accessToken', label: 'GitHub Access Token (for private repos) ℹ️', placeholder: 'ghp_...', conditional: 'isPrivateRepo' } - ], - 'semoss.authorize': [ - { name: 'alias', label: 'Instance Alias', placeholder: 'e.g., Production, Development', required: true }, - { name: 'url', label: 'Semoss Instance URL', placeholder: 'Enter only the part before /semoss', required: true }, - { name: 'accessKey', label: 'Access Key', placeholder: 'Your access key', required: true }, - { name: 'privateKey', label: 'Private Key', placeholder: 'Your private key', required: true } - ] - }; - - return inputConfigs[command] || []; - } - - /** - * Show loading overlay - */ - showLoading() { - this.state.isLoading = true; - this.elements.loader.style.display = 'flex'; - this.elements.optionsArea.style.opacity = '0.5'; - } - - /** - * Hide loading overlay - */ - hideLoading() { - this.state.isLoading = false; - this.elements.loader.style.display = 'none'; - this.elements.optionsArea.style.opacity = '1'; - } - - /** - * Show input dialog - */ - async showInputDialog(inputs) { - return new Promise((resolve) => { - const dialog = document.createElement('div'); - dialog.className = 'input-dialog'; - dialog.setAttribute('role', 'dialog'); - dialog.setAttribute('aria-modal', 'true'); - - let formHTML = ` + } + }); + + // Process lists for better mobile display + const listRegex = /^([\s]*)[-*+] (.*)/gm; + processedContent = processedContent.replace( + listRegex, + (match, space, item) => { + const indentLevel = Math.floor(space.length / 2); + const indentClass = + indentLevel > 0 + ? ` indent-${Math.min(indentLevel, 3)}` + : ""; + return `
    • ${item}
    `; + }, + ); + + // Set processed HTML + bubble.innerHTML = processedContent; + + // Add long-text class for very long messages to improve readability + if (text.length > 300) { + bubble.classList.add("long-text"); + } + } else { + // Fallback for non-string content + bubble.textContent = String(text); + } + + // Add status indicator if provided + if (status) { + const statusIndicator = document.createElement("span"); + statusIndicator.className = `status-indicator ${status}`; + + // Use appropriate icon based on status + let icon = "•"; + if (status === "success") icon = "✓"; + else if (status === "error") icon = "✗"; + else if (status === "warning") icon = "⚠"; + + statusIndicator.textContent = icon; + bubble.appendChild(statusIndicator); + } + + // Append elements to DOM + msgDiv.appendChild(bubble); + this.elements.chat.appendChild(msgDiv); + + // Optimize scrolling based on device + const scrollBehavior = isMobile || isLandscape ? "auto" : "smooth"; + + // Smooth scroll to bottom with device-appropriate behavior + this.elements.chat.scrollTo({ + top: this.elements.chat.scrollHeight, + behavior: scrollBehavior, + }); + + // On mobile landscape, ensure we're showing the latest content when keyboard appears + if (isMobile && isLandscape) { + // Double scroll to ensure content is visible + setTimeout(() => { + this.elements.chat.scrollTop = this.elements.chat.scrollHeight; + }, 100); + } + + this.updateChatHeaderVisibility(); + + if (saveToHistory) { + this.vscode.postMessage({ + type: "saveMessage", + message: { text, from, timestamp: Date.now() }, + }); + } + } + + /** + * Restore chat history + */ + restoreHistory(history) { + this.elements.chat.innerHTML = ""; + + history.forEach((msg) => { + this.appendMessage(msg.text, msg.from || "bot", false); + }); + + if (history.length > 0) { + this.state.chatStarted = true; + this.elements.startArea.style.display = "none"; + } + + this.updateChatHeaderVisibility(); + } + + /** + * Save state to extension + */ + saveState(state) { + this.state.currentState = state; + this.vscode.postMessage({ type: "saveState", state }); + } + + /** + * Clear chat history and reset state + */ + clearChat() { + // Animate out existing messages + const messages = this.elements.chat.querySelectorAll(".message"); + messages.forEach((msg, index) => { + setTimeout(() => { + msg.style.opacity = "0"; + msg.style.transform = "translateY(-10px)"; + }, index * 50); + }); + + setTimeout( + () => { + this.elements.chat.innerHTML = ""; + this.state.chatStarted = false; + this.state.currentState = "start"; + + this.elements.startArea.style.display = "flex"; + this.elements.optionsArea.style.display = "none"; + + this.vscode.postMessage({ type: "clearHistory" }); + this.saveState("start"); + this.updateChatHeaderVisibility(); + + this.showToast("Chat cleared successfully", "success"); + }, + messages.length * 50 + 200, + ); + } + + /** + * Update chat header visibility + */ + updateChatHeaderVisibility() { + const shouldShow = + this.state.chatStarted || this.elements.chat.children.length > 0; + + if (shouldShow) { + this.elements.chatHeader.style.display = "flex"; + this.elements.chatContainer.style.display = "flex"; + this.elements.chatContainer.classList.add("visible"); + } else { + this.elements.chatHeader.style.display = "none"; + this.elements.chatContainer.style.display = "none"; + this.elements.chatContainer.classList.remove("visible"); + } + } + + /** + * Show options area with responsive layout + */ + showOptions() { + if (!this.state.chatStarted) { + this.state.chatStarted = true; + this.saveState("options"); + } + + this.elements.startArea.style.display = "none"; + + // Reset options area completely + this.elements.optionsArea.style.display = "flex"; + this.elements.optionsArea.innerHTML = ""; + this.elements.optionsArea.className = "options-container"; + + // Add responsive classes based on viewport + if (this.state.viewport.isMobile) { + this.elements.optionsArea.classList.add("mobile-view"); + } + if (this.state.viewport.isSmallPhone) { + this.elements.optionsArea.classList.add("small-device"); + } + + this.updateChatHeaderVisibility(); + this.vscode.postMessage({ type: "checkSmssFile" }); + } + + /** + * Render option buttons with responsive layout + */ + renderOptions(options) { + // Clear any existing options + this.elements.optionsArea.innerHTML = ""; + + // If there are multiple options, use grid layout for larger screens + if (options.length > 1) { + this.elements.optionsArea.classList.add("options-grid"); + } else { + this.elements.optionsArea.classList.remove("options-grid"); + } + + options.forEach((opt) => { + const btn = this.createOptionButton(opt.label, async () => { + await this.handleOptionClick(opt); + }); + + // Add icon if provided + if (opt.icon) { + if ( + btn.firstChild && + btn.firstChild.className === "option-content" + ) { + // If we have structured content, add icon to the label + const labelEl = btn.querySelector(".option-label"); + labelEl.innerHTML = `${opt.icon}${labelEl.textContent}`; + } else { + // Standard text content + btn.innerHTML = `${opt.icon}${opt.label}`; + } + } + + this.elements.optionsArea.appendChild(btn); + }); + + // Apply viewport-specific adjustments to the options + this.adjustOptionsForViewport(); + } + + /** + * Adjust options display based on current viewport + */ + adjustOptionsForViewport() { + const { isMobile, isSmallPhone, width } = this.state.viewport; + const options = this.elements.optionsArea; + const buttons = options.querySelectorAll(".option-btn"); + + // For very small screens, apply compact styling + if (isSmallPhone) { + buttons.forEach((btn) => { + btn.classList.add("compact"); + + // Simplify content if it has URL parts + const sublabel = btn.querySelector(".option-sublabel"); + if (sublabel && sublabel.textContent.length > 20) { + const url = sublabel.textContent; + // Truncate URL display to save space + sublabel.textContent = url.substring(0, 20) + "..."; + sublabel.title = url; // Keep full URL as tooltip + } + }); + + // Force vertical layout on very small screens + options.classList.remove("options-grid"); + } + // For mobile but not tiny screens + else if (isMobile) { + buttons.forEach((btn) => { + btn.classList.remove("compact"); + + // Truncate very long URLs but show more than on tiny screens + const sublabel = btn.querySelector(".option-sublabel"); + if (sublabel && sublabel.textContent.length > 40) { + const url = sublabel.textContent; + sublabel.textContent = url.substring(0, 40) + "..."; + sublabel.title = url; + } + }); + + // Use grid only if we have 3 or fewer options on mobile + if (buttons.length > 3) { + options.classList.remove("options-grid"); + } + } + // For tablets and desktops + else { + buttons.forEach((btn) => btn.classList.remove("compact")); + + // Use grid for multiple options + if (buttons.length > 1) { + options.classList.add("options-grid"); + } + } + } + + /** + * Handle option button click + */ + async handleOptionClick(option) { + const { command, label } = option; + + // Special handling for specific commands + switch (command) { + case "semoss.createNewApp": + this.vscode.postMessage({ type: "checkInstanceAuthorized" }); + return; + + case "semoss.authorize": + await this.handleAuthorizeCommand(); + return; + + case "semoss.selectInstance": + this.showLoading(); + this.vscode.postMessage({ type: "getInstanceAliases" }); + return; + + case "semoss.removeInstance": + this.vscode.postMessage({ + type: "getInstanceAliasesForRemoval", + }); + return; + } + + // Handle commands that require input + const requiredInputs = this.getRequiredInputs(command); + if (requiredInputs.length > 0) { + const inputs = await this.showInputDialog(requiredInputs); + if (!inputs) return; + + this.appendMessage(`${label} with details:`, "user"); + Object.entries(inputs).forEach(([key, value]) => { + this.appendMessage(`${key}: ${value}`, "user"); + }); + + this.showLoading(); + this.state.lastCommand = command; + this.vscode.postMessage({ type: "chat", command, inputs }); + } else { + this.appendMessage(label, "user"); + + // Don't show spinner for certain commands + if (!this.shouldSkipLoading(command)) { + this.showLoading(); + } + + this.state.lastCommand = command; + this.vscode.postMessage({ type: "chat", command }); + } + } + + /** + * Handle authorize command + */ + async handleAuthorizeCommand() { + const requiredInputs = this.getRequiredInputs("semoss.authorize"); + const inputs = await this.showInputDialog(requiredInputs); + if (!inputs) return; + + this.appendMessage("Authorize New Instance with details:", "user"); + this.displayInputs(inputs, { + alias: "Instance Alias", + url: "Semoss Instance URL", + accessKey: "Access Key", + privateKey: "Private Key", + }); + + this.showLoading(); + this.state.lastCommand = "semoss.authorize"; + this.vscode.postMessage({ + type: "chat", + command: "semoss.authorize", + inputs, + }); + } + + /** + * Display input values in chat + */ + displayInputs(inputs, fieldLabels) { + Object.entries(inputs).forEach(([key, value]) => { + const displayLabel = fieldLabels[key] || key; + let displayValue = value; + + if (typeof value === "boolean") { + displayValue = value ? "Yes" : "No"; + } + + if (value !== "" && value !== null && value !== undefined) { + this.appendMessage(`${displayLabel}: ${displayValue}`, "user"); + } + }); + } + + /** + * Check if loading should be skipped for command + */ + shouldSkipLoading(command) { + return [ + "semoss.ziponly", + "semoss.deployonly", + "semoss.zipanddeploy", + ].includes(command); + } + + /** + * Show instance selection + */ + showInstanceSelection(aliases) { + this.elements.optionsArea.innerHTML = ""; + this.appendMessage("Select an instance:", "bot"); + + // If there are multiple aliases, use grid layout + if (aliases.length > 1) { + this.elements.optionsArea.classList.add("options-grid"); + } else { + this.elements.optionsArea.classList.remove("options-grid"); + } + + aliases.forEach((alias) => { + // Create label with URL if available + let label = alias; + if (window.semossInstanceUrls && window.semossInstanceUrls[alias]) { + label = `${alias} (${window.semossInstanceUrls[alias]})`; + } + + const btn = this.createOptionButton(label, () => { + this.appendMessage(`Switch to instance: ${alias}`, "user"); + this.showLoading(); + this.state.lastCommand = "semoss.selectInstance"; + this.vscode.postMessage({ + type: "chat", + command: "semoss.selectInstance", + inputs: { alias }, + }); + }); + + if (window.currentInstance === alias) { + btn.classList.add("selected-instance"); + } + + this.elements.optionsArea.appendChild(btn); + }); + + // Add back button + const backBtn = this.createBackButton(() => { + this.appendMessage( + "Instance selection cancelled. No changes were made.", + "bot", + ); + this.showOptions(); + }); + this.elements.optionsArea.appendChild(backBtn); + + // Apply viewport-specific adjustments + this.adjustOptionsForViewport(); + } + + /** + * Get required inputs for command + */ + getRequiredInputs(command) { + const inputConfigs = { + "semoss.createNewApp": [ + { + name: "appName", + label: "App Name", + placeholder: "Enter app name", + required: true, + }, + { + name: "description", + label: "Description (optional)", + placeholder: "Enter app description (optional)", + }, + { + name: "githubLink", + label: "GitHub Link (optional)", + placeholder: "https://github.com/user/repo", + }, + { + name: "isPrivateRepo", + label: "Private Repository", + type: "toggle", + defaultValue: false, + description: + "Toggle ON for private repositories (requires access token)", + }, + { + name: "accessToken", + label: 'GitHub Access Token (for private repos) ℹ️', + placeholder: "ghp_...", + conditional: "isPrivateRepo", + }, + ], + "semoss.authorize": [ + { + name: "alias", + label: "Instance Alias", + placeholder: "e.g., Production, Development", + required: true, + }, + { + name: "url", + label: "Semoss Instance URL", + placeholder: "Enter only the part before /semoss", + required: true, + }, + { + name: "accessKey", + label: "Access Key", + placeholder: "Your access key", + required: true, + }, + { + name: "privateKey", + label: "Private Key", + placeholder: "Your private key", + required: true, + }, + ], + }; + + return inputConfigs[command] || []; + } + + /** + * Show loading overlay + */ + showLoading() { + this.state.isLoading = true; + this.elements.loader.style.display = "flex"; + this.elements.optionsArea.style.opacity = "0.5"; + } + + /** + * Hide loading overlay + */ + hideLoading() { + this.state.isLoading = false; + this.elements.loader.style.display = "none"; + this.elements.optionsArea.style.opacity = "1"; + } + + /** + * Show input dialog + */ + async showInputDialog(inputs) { + return new Promise((resolve) => { + const dialog = document.createElement("div"); + dialog.className = "input-dialog"; + dialog.setAttribute("role", "dialog"); + dialog.setAttribute("aria-modal", "true"); + + let formHTML = `

    Required Information

    `; - inputs.forEach(input => { - formHTML += this.generateInputHTML(input); - }); + inputs.forEach((input) => { + formHTML += this.generateInputHTML(input); + }); - formHTML += ` + formHTML += `
    @@ -882,71 +1043,74 @@ class SemossChatbot {
    `; - dialog.innerHTML = formHTML; - document.body.appendChild(dialog); - - // Focus first input - const firstInput = dialog.querySelector('input'); - if (firstInput) { - setTimeout(() => firstInput.focus(), 100); - } - - const form = dialog.querySelector('#inputForm'); - const cancelBtn = dialog.querySelector('.cancel-btn'); - - this.setupFormInteractions(form, inputs); - - form.onsubmit = (e) => { - e.preventDefault(); - const formData = this.extractFormData(form, inputs); - dialog.remove(); - resolve(formData); - }; - - cancelBtn.onclick = () => { - dialog.remove(); - resolve(null); - }; - - // Close on backdrop click - dialog.onclick = (e) => { - if (e.target === dialog) { - dialog.remove(); - resolve(null); - } - }; - }); - } - - /** - * Generate HTML for input field - */ - generateInputHTML(input) { - let inputHTML = '"; + } + + /** + * Get input type based on field name + */ + getInputType(name) { + const sensitiveFields = ["key", "token", "password", "secret"]; + return sensitiveFields.some((field) => + name.toLowerCase().includes(field), + ) + ? "password" + : "text"; + } + + /** + * Get autocomplete attribute + */ + getAutocomplete(name) { + const autocompleteMap = { + url: "url", + email: "email", + alias: "username", + appName: "organization-title", + }; + return autocompleteMap[name] || "off"; + } + + /** + * Setup form interactions (toggles, conditional fields) + */ + setupFormInteractions(form, inputs) { + inputs.forEach((input) => { + if (input.type === "toggle") { + const toggle = form.querySelector(`#${input.name}`); + const conditionalFields = form.querySelectorAll( + `[data-depends-on="${input.name}"]`, + ); + + toggle.addEventListener("change", () => { + conditionalFields.forEach((field) => { + if (toggle.checked) { + field.style.display = "block"; + const conditionalInput = + field.querySelector("input"); + if ( + conditionalInput && + input.name === "isPrivateRepo" + ) { + conditionalInput.required = true; + } + } else { + field.style.display = "none"; + const conditionalInput = + field.querySelector("input"); + if (conditionalInput) { + conditionalInput.required = false; + conditionalInput.value = ""; + } + } + }); + }); + + // Trigger initial state + toggle.dispatchEvent(new Event("change")); + } + }); + } + + /** + * Extract form data + */ + extractFormData(form, inputs) { + const formData = {}; + inputs.forEach((input) => { + const element = form.querySelector(`#${input.name}`); + if (input.type === "toggle") { + formData[input.name] = element.checked; + } else { + formData[input.name] = element.value; + } + }); + return formData; + } + + /** + * Show remove instance confirmation + */ + showRemoveInstanceConfirmation(alias) { + this.elements.optionsArea.innerHTML = ""; + this.elements.optionsArea.classList.remove("options-grid"); + this.appendMessage( + `Are you sure you want to remove "${alias}"?`, + "bot", + ); + + // Create a button row container for better responsiveness + const buttonRow = document.createElement("div"); + buttonRow.className = "button-row"; + + const yesBtn = this.createOptionButton("Yes", () => { + this.showLoading(); + this.vscode.postMessage({ type: "removeInstanceByAlias", alias }); + }); + yesBtn.style.background = + "linear-gradient(135deg, var(--color-danger), #ff6b6b)"; + + const noBtn = this.createOptionButton("No", () => { + this.appendMessage( + `Cancelled removal of instance "${alias}".`, + "bot", + ); + this.showOptions(); + }); + + buttonRow.appendChild(yesBtn); + buttonRow.appendChild(noBtn); + this.elements.optionsArea.appendChild(buttonRow); + } + + /** + * Create option button with enhanced responsiveness + */ + createOptionButton(text, onClick, extraClasses = "") { + const btn = document.createElement("button"); + btn.className = `option-btn ${extraClasses}`.trim(); + btn.onclick = onClick; + btn.setAttribute("role", "menuitem"); + + // Check if the text contains URL-like content in parentheses + if ( + typeof text === "string" && + text.includes("(") && + text.includes(")") + ) { + // Extract the main label and URL parts + const parts = text.split("("); + const mainLabel = parts[0].trim(); + const urlPart = `(${parts.slice(1).join("(")}`; + + // Create structured content with label and sublabel + const contentDiv = document.createElement("div"); + contentDiv.className = "option-content"; + + const labelSpan = document.createElement("div"); + labelSpan.className = "option-label"; + labelSpan.textContent = mainLabel; + + const urlSpan = document.createElement("div"); + urlSpan.className = "option-sublabel"; + urlSpan.textContent = urlPart; + + contentDiv.appendChild(labelSpan); + contentDiv.appendChild(urlSpan); + btn.appendChild(contentDiv); + } else { + // Standard text content + btn.textContent = text; + } + + return btn; + } + + /** + * Create back button + */ + createBackButton(onClick) { + const btn = this.createOptionButton("Back", onClick); + btn.style.background = "var(--bg-tertiary)"; + btn.style.color = "var(--text-primary)"; + btn.style.border = "1px solid var(--border-secondary)"; + return btn; + } + + /** + * Show toast notification + */ + showToast(message, type = "info", duration = 3000) { + const toast = document.createElement("div"); + toast.className = `toast ${type}`; + toast.textContent = message; + toast.setAttribute("role", "alert"); + + this.elements.toastContainer.appendChild(toast); + + // Auto remove after duration + setTimeout(() => { + toast.style.opacity = "0"; + toast.style.transform = "translateX(100%)"; + setTimeout(() => { + if (toast.parentNode) { + toast.parentNode.removeChild(toast); + } + }, 300); + }, duration); + } + + /** + * Get state for debugging + */ + getState() { + return { ...this.state }; + } + + /** + * Update state + */ + setState(newState) { + this.state = { ...this.state, ...newState }; + } + + /** + * Handle viewport changes (resize, orientation) + */ + handleViewportChange() { + // Get the new viewport details + const width = window.innerWidth; + const height = window.innerHeight; + + const newViewport = { + width: width, + height: height, + isMobile: width <= 768, + isTablet: width > 768 && width <= 1023, + isDesktop: width > 1023, + isSmallPhone: width <= 375, + isLandscape: width > height, + aspectRatio: width / height, + hasNotch: + window.screen && + window.screen.height > 800 && + "ontouchstart" in window, + }; + + // Detect if device has safe-area insets (iPhone X+ or similar devices) + // This is a basic check, actual values come from CSS env() variables + if (CSS.supports("padding: env(safe-area-inset-top)")) { + newViewport.hasSafeAreaInsets = true; + } + + // Update state + this.state.viewport = newViewport; + + // Apply all viewport-specific adjustments + this.applyViewportAdjustments(); + + // Specifically adjust options if they're visible + if (this.elements.optionsArea.style.display !== "none") { + this.adjustOptionsForViewport(); + } + + // Update body classes for CSS targeting + this.updateViewportClasses(); + + // Debounced notification to extension about viewport changes + clearTimeout(this._viewportChangeTimeout); + this._viewportChangeTimeout = setTimeout(() => { + this.vscode.postMessage({ + type: "viewportChanged", + viewport: newViewport, + }); + }, 200); + } + + /** + * Update body classes based on viewport + */ + updateViewportClasses() { + const { isMobile, isTablet, isDesktop, isSmallPhone, isLandscape } = + this.state.viewport; + + // Clear existing classes + document.body.classList.remove( + "mobile-device", + "tablet-device", + "desktop-device", + "small-phone", + "landscape", + "portrait", + ); + + // Add device type classes + if (isSmallPhone) document.body.classList.add("small-phone"); + if (isMobile) document.body.classList.add("mobile-device"); + if (isTablet) document.body.classList.add("tablet-device"); + if (isDesktop) document.body.classList.add("desktop-device"); + + // Add orientation classes + if (isLandscape) { + document.body.classList.add("landscape"); + } else { + document.body.classList.add("portrait"); + } + } + + /** + * Apply comprehensive viewport-specific UI adjustments + */ + applyViewportAdjustments() { + const { isMobile, isTablet, isLandscape, isSmallPhone, height } = + this.state.viewport; + + // Adjust option buttons layout for mobile/landscape + if (this.elements.optionsArea) { + if (isMobile && isLandscape) { + this.elements.optionsArea.classList.add("landscape-layout"); + } else { + this.elements.optionsArea.classList.remove("landscape-layout"); + } + } + + // Adjust chat container height based on device + if (this.elements.chat) { + if (isMobile) { + const headerHeight = this.elements.chatHeader + ? this.elements.chatHeader.offsetHeight + : 0; + let inputAreaHeight = this.elements.inputArea + ? this.elements.inputArea.offsetHeight + : 0; + + // Default input height if not yet rendered + if (inputAreaHeight < 10) + inputAreaHeight = isSmallPhone ? 60 : 80; + + // Additional padding adjustment + const paddingAdjustment = isSmallPhone + ? 30 + : isLandscape + ? 40 + : 60; + + // Calculate the available height + const adjustedHeight = + height - headerHeight - inputAreaHeight - paddingAdjustment; + + // Apply the calculated height + this.elements.chat.style.maxHeight = `${Math.max(150, adjustedHeight)}px`; + } else if (isTablet) { + // Tablet-specific adjustments + const adjustedHeight = height - 200; // Less aggressive adjustment for tablets + this.elements.chat.style.maxHeight = `${Math.max(250, adjustedHeight)}px`; + } else { + // Reset to CSS default on larger screens + this.elements.chat.style.maxHeight = ""; + } + } + } + + /** + * Safely escape HTML content to prevent XSS + * @param {string} html - The HTML to escape + * @returns {string} - Escaped HTML + */ + escapeHtml(html) { + const div = document.createElement("div"); + div.textContent = html; + return div.innerHTML; + } + + /** + * Download the user manual PDF + */ + downloadUserManual() { + // Request the user manual from VS Code extension + this.vscode.postMessage({ + type: "downloadUserManual", + }); + + // Show toast notification + this.showToast("Downloading user manual...", "info"); + + // Let VS Code know we want to download the manual + this.vscode.postMessage({ + type: "openExternalResource", + resource: "user-manual", + }); + } } // Legacy functions for compatibility with existing VS Code integration let chatbotInstance; // Initialize when DOM is ready -if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', () => { - chatbotInstance = new SemossChatbot(); - }); +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", () => { + chatbotInstance = new SemossChatbot(); + }); } else { - chatbotInstance = new SemossChatbot(); + chatbotInstance = new SemossChatbot(); } // Export for VS Code integration -if (typeof module !== 'undefined' && module.exports) { - module.exports = { - SemossChatbot, - // Legacy function exports - getChatbotHtml: () => { - // This will be handled by the HTML file now - return null; - }, - handleChatbotAction: (action, options, context) => { - console.log('handleChatbotAction called with:', action, options); - // Implementation can be added here if needed - }, - mapMessageToCommand: (msg) => { - if (!msg || !msg.text) return null; - const text = msg.text.toLowerCase(); - if (text.includes('authorize')) return 'semoss.authorize'; - if (text.includes('create') && text.includes('app')) return 'semoss.createNewApp'; - if (text.includes('zip') && text.includes('deploy')) return 'semoss.zipanddeploy'; - if (text.includes('zip')) return 'semoss.ziponly'; - if (text.includes('deploy')) return 'semoss.deployonly'; - if (text.includes('remove') && text.includes('instance')) return 'semoss.removeInstance'; - if (text.includes('select') && text.includes('instance')) return 'semoss.selectInstance'; - if (text.includes('chatbot')) return 'semoss.openChatbot'; - return null; - } - }; +if (typeof module !== "undefined" && module.exports) { + module.exports = { + SemossChatbot, + // Legacy function exports + getChatbotHtml: () => { + // This will be handled by the HTML file now + return null; + }, + handleChatbotAction: (action, options, context) => { + console.log("handleChatbotAction called with:", action, options); + // Implementation can be added here if needed + }, + mapMessageToCommand: (msg) => { + if (!msg || !msg.text) return null; + const text = msg.text.toLowerCase(); + if (text.includes("authorize")) return "semoss.authorize"; + if (text.includes("create") && text.includes("app")) + return "semoss.createNewApp"; + if (text.includes("zip") && text.includes("deploy")) + return "semoss.zipanddeploy"; + if (text.includes("zip")) return "semoss.ziponly"; + if (text.includes("deploy")) return "semoss.deployonly"; + if (text.includes("remove") && text.includes("instance")) + return "semoss.removeInstance"; + if (text.includes("select") && text.includes("instance")) + return "semoss.selectInstance"; + if (text.includes("chatbot")) return "semoss.openChatbot"; + return null; + }, + }; } diff --git a/packages/vscode-extension/src/components/ChatbotWebview/ChatbotSeparateManager.js b/packages/vscode-extension/src/components/ChatbotWebview/ChatbotSeparateManager.js index 218696eaac..6497f270c8 100644 --- a/packages/vscode-extension/src/components/ChatbotWebview/ChatbotSeparateManager.js +++ b/packages/vscode-extension/src/components/ChatbotWebview/ChatbotSeparateManager.js @@ -12,38 +12,56 @@ const fs = require("fs"); * @returns {string} HTML content for the webview */ function getSeparateChatbotHtml(webview, context) { - // Use the extension's file system path - const extensionPath = context.extensionPath; + // Use the extension's file system path + const extensionPath = context.extensionPath; - // Get paths to the HTML, CSS, and JS files - const htmlPath = vscode.Uri.file( - path.join(extensionPath, 'src', 'components', 'Chatbot-ui', 'index.html') - ); - const cssPath = vscode.Uri.file( - path.join(extensionPath, 'src', 'components', 'Chatbot-ui', 'style.css') - ); - const jsPath = vscode.Uri.file( - path.join(extensionPath, 'src', 'components', 'Chatbot-ui', 'script.js') - ); + // Get paths to the HTML, CSS, and JS files + const htmlPath = vscode.Uri.file( + path.join( + extensionPath, + "src", + "components", + "Chatbot-ui", + "index.html", + ), + ); + const cssPath = vscode.Uri.file( + path.join( + extensionPath, + "src", + "components", + "Chatbot-ui", + "style.css", + ), + ); + const jsPath = vscode.Uri.file( + path.join( + extensionPath, + "src", + "components", + "Chatbot-ui", + "script.js", + ), + ); - // Convert URIs to webview-friendly format - const cssUri = webview.asWebviewUri(cssPath); - const jsUri = webview.asWebviewUri(jsPath); + // Convert URIs to webview-friendly format + const cssUri = webview.asWebviewUri(cssPath); + const jsUri = webview.asWebviewUri(jsPath); - // Read the HTML file - try { - let htmlContent = fs.readFileSync(htmlPath.fsPath, 'utf8'); + // Read the HTML file + try { + let htmlContent = fs.readFileSync(htmlPath.fsPath, "utf8"); - // Replace resource references with webview URIs - htmlContent = htmlContent - .replace('href="style.css"', `href="${cssUri}"`) - .replace('src="script.js"', `src="${jsUri}"`); + // Replace resource references with webview URIs + htmlContent = htmlContent + .replace('href="style.css"', `href="${cssUri}"`) + .replace('src="script.js"', `src="${jsUri}"`); - return htmlContent; - } catch (error) { - console.error('Failed to load chatbot HTML:', error); - return getErrorHtml(error); - } + return htmlContent; + } catch (error) { + console.error("Failed to load chatbot HTML:", error); + return getErrorHtml(error); + } } /** @@ -52,7 +70,12 @@ function getSeparateChatbotHtml(webview, context) { * @returns {string} Path to user manual PDF */ function getUserManualPath(context) { - return path.join(context.extensionPath, 'assets', 'docs', 'semoss_user_manual.pdf'); + return path.join( + context.extensionPath, + "assets", + "docs", + "semoss_user_manual.pdf", + ); } /** @@ -61,7 +84,7 @@ function getUserManualPath(context) { * @returns {string} Error HTML */ function getErrorHtml(error) { - return ` + return ` @@ -119,8 +142,8 @@ function getErrorHtml(error) { * Exports the original getChatbotHtml and handleChatbotAction functions for backward compatibility */ function handleChatbotAction(action, options) { - console.log('handleChatbotAction called with:', action, options); - // Implementation can be added here if needed + console.log("handleChatbotAction called with:", action, options); + // Implementation can be added here if needed } /** @@ -129,24 +152,28 @@ function handleChatbotAction(action, options) { * @returns {string|null} The command string or null if not recognized */ function mapMessageToCommand(msg) { - if (!msg || !msg.text) return null; - const text = msg.text.toLowerCase(); + if (!msg || !msg.text) return null; + const text = msg.text.toLowerCase(); - if (text.includes('authorize')) return 'semoss.authorize'; - if (text.includes('create') && text.includes('app')) return 'semoss.createNewApp'; - if (text.includes('zip') && text.includes('deploy')) return 'semoss.zipanddeploy'; - if (text.includes('zip')) return 'semoss.ziponly'; - if (text.includes('deploy')) return 'semoss.deployonly'; - if (text.includes('remove') && text.includes('instance')) return 'semoss.removeInstance'; - if (text.includes('select') && text.includes('instance')) return 'semoss.selectInstance'; - if (text.includes('chatbot')) return 'semoss.openChatbot'; + if (text.includes("authorize")) return "semoss.authorize"; + if (text.includes("create") && text.includes("app")) + return "semoss.createNewApp"; + if (text.includes("zip") && text.includes("deploy")) + return "semoss.zipanddeploy"; + if (text.includes("zip")) return "semoss.ziponly"; + if (text.includes("deploy")) return "semoss.deployonly"; + if (text.includes("remove") && text.includes("instance")) + return "semoss.removeInstance"; + if (text.includes("select") && text.includes("instance")) + return "semoss.selectInstance"; + if (text.includes("chatbot")) return "semoss.openChatbot"; - return null; + return null; } -module.exports = { - getSeparateChatbotHtml, - getUserManualPath, - handleChatbotAction, - mapMessageToCommand +module.exports = { + getSeparateChatbotHtml, + getUserManualPath, + handleChatbotAction, + mapMessageToCommand, }; diff --git a/packages/vscode-extension/src/components/ChatbotWebview/ChatbotWebview.js b/packages/vscode-extension/src/components/ChatbotWebview/ChatbotWebview.js index 214f439ecf..df7cb975c9 100644 --- a/packages/vscode-extension/src/components/ChatbotWebview/ChatbotWebview.js +++ b/packages/vscode-extension/src/components/ChatbotWebview/ChatbotWebview.js @@ -1,397 +1,637 @@ const vscode = require("vscode"); const path = require("path"); -const { getSeparateChatbotHtml, mapMessageToCommand } = require("./ChatbotSeparateManager.js"); -const { getSecrets, getStoredInstances, storeInstance } = require("../../utils/secrets.js"); +const { + getSeparateChatbotHtml, + mapMessageToCommand, +} = require("./ChatbotSeparateManager.js"); +const { + getSecrets, + getStoredInstances, + storeInstance, +} = require("../../utils/secrets.js"); const { createNewApp } = require("../../utils/createApp.js"); const { updateStatusBar } = require("../../utils/statusBar.js"); const fs = require("fs"); function getWebviewContent(webview, context) { - // Always use the new implementation - return getSeparateChatbotHtml(webview, context); + // Always use the new implementation + return getSeparateChatbotHtml(webview, context); } class SemossChatbotViewProvider { - /** - * @param {vscode.ExtensionContext} context - */ - constructor(context) { - this._context = context; - this._chatHistory = []; - this._currentState = 'start'; // 'start', 'options', 'authorized' - } - - /** - * @param {vscode.WebviewView} webviewView - */ - resolveWebviewView(webviewView) { - this._webviewView = webviewView; - webviewView.webview.options = { - enableScripts: true, - localResourceRoots: [ - vscode.Uri.file(path.join(this._context.extensionPath, 'src', 'components', 'ChatbotWebview')), - vscode.Uri.file(path.join(this._context.extensionPath, 'src', 'components', 'Chatbot-ui')) - ] - - }; - - webviewView.webview.html = getWebviewContent(webviewView.webview, this._context); - - // Restore chat history and state when webview becomes visible - webviewView.onDidChangeVisibility(() => { - if (webviewView.visible) { - this._restoreChatState(); - } - }); - - // Initial restore when webview is first created - this._restoreChatState(); - - webviewView.webview.onDidReceiveMessage(async (msg) => { - // Handle history-related messages - if (msg.type === 'saveMessage') { - this._addMessageToHistory(msg.message.text, msg.message.from, msg.status); - return; - } - - if (msg.type === 'saveState') { - this._currentState = msg.state; - return; - } - - if (msg.type === 'getHistory') { - webviewView.webview.postMessage({ - type: 'restoreHistory', - history: this._chatHistory, - state: this._currentState - }); - return; - } - - if (msg.type === 'clearHistory') { - this._chatHistory = []; - this._currentState = 'start'; - return; - } - - if (msg.type === 'openExternalResource' && msg.resource === 'user-manual') { - // Get the path to the user manual PDF - const userManualPath = vscode.Uri.file( - path.join(this._context.extensionPath, 'assets', 'docs', 'semoss_user_manual.pdf') - ); - - // Open the PDF in the default PDF viewer - vscode.env.openExternal(userManualPath); - - // Log that the manual was accessed - this._addMessageToHistory('User manual downloaded', 'bot', 'success'); - return; - } - - if (msg.type === 'getInstanceAliases') { - // Fetch aliases and send to webview, including URLs - const instances = await getStoredInstances(this._context); - const aliases = Object.keys(instances); - // Build a map of alias to URL (no optional chaining for compatibility) - const urls = {}; - for (const alias of aliases) { - urls[alias] = (instances[alias] && instances[alias].semossUrl) ? instances[alias].semossUrl : ''; - } - // Get current instance alias - const currentAlias = await this._context.secrets.get('CURRENT_INSTANCE_ALIAS'); - webviewView.webview.postMessage({ - type: 'instanceAliasesWithUrls', - aliases, - urls, - currentInstance: currentAlias - }); - return; - } - if (msg.type === 'checkSmssFile') { - // Check for .smss file in the workspace root - let hasSmss = false; - let folderPath = undefined; - if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) { - folderPath = vscode.workspace.workspaceFolders[0].uri.fsPath; - try { - const files = fs.readdirSync(folderPath); - hasSmss = files.some(f => f.endsWith('.smss')); - } catch (e) { - hasSmss = false; - } - } - webviewView.webview.postMessage({ type: 'smssFileCheckResult', hasSmss }); - return; - } - if (msg.type === 'checkInstanceAuthorized') { - // Check if any instance is authorized (secrets exist) - const secrets = await getSecrets(this._context); - const authorized = !!secrets && Object.keys(secrets).length > 0; - webviewView.webview.postMessage({ type: 'instanceAuthorizedResult', authorized }); - return; - } - if (msg.type === 'chat') { - let resultMsg = 'Command received: ' + JSON.stringify(msg); - // Use msg.command if present, otherwise map from message - const command = msg.command || mapMessageToCommand(msg); - // Remove deployonly from folderCommands so it never prompts for a folder - const folderCommands = []; - if (!command) { - resultMsg = 'Sorry, I did not understand that command.'; - } else { - try { - if (msg.inputs) { - switch (command) { - case 'semoss.authorize': { - const { alias, url, accessKey, privateKey } = msg.inputs; - - // Input validation - if (!alias || !url || !accessKey || !privateKey) { - webviewView.webview.postMessage({ - type: 'response', - status: 'error', - text: 'All fields are required for authorization.', - hideLoading: true - }); - return; - } - - try { - // Store the instance data - await storeInstance(this._context, alias, { - semossUrl: url, - accessKey, - privateKey - }); - - // Verify the data was stored correctly - const instances = await getStoredInstances(this._context); - const storedInstance = instances[alias]; - - if (!storedInstance || - storedInstance.semossUrl !== url || - storedInstance.accessKey !== accessKey || - storedInstance.privateKey !== privateKey) { - throw new Error('Failed to verify stored instance data'); - } - - // Set as current instance - await this._context.secrets.store('CURRENT_INSTANCE_ALIAS', alias); - - // Update status bar - await updateStatusBar(this._context); - - webviewView.webview.postMessage({ - type: 'response', - status: 'success', - text: 'Instance "' + alias + '" authorized successfully!', - hideLoading: true - }); - this._addMessageToHistory('Instance "' + alias + '" authorized successfully!', 'bot', 'success'); - } catch (e) { - webviewView.webview.postMessage({ - type: 'response', - status: 'error', - text: 'Error authorizing instance: ' + e.message, - hideLoading: true - }); - this._addMessageToHistory('Error authorizing instance: ' + e.message, 'bot', 'error'); - } - return; - } case 'semoss.createNewApp': { - const { appName, description, githubLink, isPrivateRepo, accessToken } = msg.inputs; - - // Debug logging to confirm values are passed correctly - console.log('ChatbotWebview received inputs:', { - appName, - description, - githubLink, - isPrivateRepo, - accessToken: accessToken ? 'PROVIDED' : 'NOT_PROVIDED' - }); - - try { - const secrets = await getSecrets(this._context); - if (!secrets) { - resultMsg = 'Please authorize an instance first.'; - webviewView.webview.postMessage({ type: 'response', status: 'error', text: resultMsg, hideLoading: true }); - return; - } - const result = await createNewApp(this._context, async () => secrets, { appName, description, githubLink, isPrivateRepo, accessToken }); - if (result === false) { - resultMsg = `Cancelled: No folder selected.`; - webviewView.webview.postMessage({ type: 'response', status: 'warning', text: resultMsg, hideLoading: true }); - this._addMessageToHistory(resultMsg, 'bot', 'warning'); - return; - } - resultMsg = `App \"${appName}\" created successfully!`; - // Always send hideLoading to stop spinner - webviewView.webview.postMessage({ type: 'response', status: 'success', text: resultMsg, hideLoading: true }); - this._addMessageToHistory(resultMsg, 'bot', 'success'); - return; - } catch (e) { - resultMsg = `Error creating app: ${e.message}`; - webviewView.webview.postMessage({ type: 'response', status: 'error', text: resultMsg, hideLoading: true }); - this._addMessageToHistory(resultMsg, 'bot', 'error'); - return; - } - } - default: { - // For folder commands, always use first workspace folder - if (folderCommands.includes(command)) { - let uri = msg.inputs && msg.inputs.uri; - if (!uri) { - if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) { - uri = vscode.workspace.workspaceFolders[0].uri; - } else { - resultMsg = 'No workspace folder found.'; // Always hide loading even on error - webviewView.webview.postMessage({ type: 'response', status: 'error', text: resultMsg, hideLoading: true }); - this._addMessageToHistory(resultMsg, 'bot', 'error'); - return; - } - } - await vscode.commands.executeCommand(command, uri); - resultMsg = `Action '${command}' executed on selected folder.`; - // Always hide loading after deploy - webviewView.webview.postMessage({ type: 'response', status: 'success', text: resultMsg, hideLoading: true }); - this._addMessageToHistory(resultMsg, 'bot', 'success'); - return; - } else { - await vscode.commands.executeCommand(command, msg.inputs); - resultMsg = `Action '${command}' executed with provided details.`; - // Always hide loading after any command - webviewView.webview.postMessage({ type: 'response', status: 'success', text: resultMsg, hideLoading: true }); - this._addMessageToHistory(resultMsg, 'bot', 'success'); - return; - } - } - } - } else { - // For folder commands, prompt for folder if not provided - if (folderCommands.includes(command)) { - const folders = await vscode.window.showOpenDialog({ - canSelectFolders: true, - canSelectFiles: false, - canSelectMany: false, - openLabel: 'Select folder for operation' - }); - if (!folders || folders.length === 0) { - resultMsg = 'Operation cancelled: No folder selected.'; - } else { - await vscode.commands.executeCommand(command, folders[0]); - resultMsg = `Action '${command}' executed on selected folder.`; - } - } else { - await vscode.commands.executeCommand(command); - resultMsg = `Action '${command}' executed.`; - } - } - } catch (e) { - resultMsg = `Error: ${e.message}`; - // Save error to history - this._addMessageToHistory(resultMsg, 'bot', 'error'); - } - } - // Ensure resultMsg is always a string before sending - const finalMsg = typeof resultMsg === 'string' ? resultMsg : String(resultMsg); - webviewView.webview.postMessage({ type: 'response', text: finalMsg }); - } - if (msg.type === 'getInstanceAliasesForRemoval') { - // Send aliases for removal - const instances = await getStoredInstances(this._context); - const aliases = Object.keys(instances); - - - // Build a map of alias to URL - const urls = {}; - for (const alias of aliases) { - urls[alias] = (instances[alias] && instances[alias].semossUrl) ? instances[alias].semossUrl : ''; - } - - // Get current instance alias - const currentAlias = await this._context.secrets.get('CURRENT_INSTANCE_ALIAS'); - webviewView.webview.postMessage({ - type: 'instanceAliasesForRemoval', - aliases, - urls, - currentInstance: currentAlias - }); - return; - } - if (msg.type === 'removeInstanceByAlias') { - const { alias } = msg; - const instances = await getStoredInstances(this._context); - if (!instances[alias]) { - webviewView.webview.postMessage({ type: 'response', status: 'error', text: `Instance "${alias}" not found.`, hideLoading: true }); - this._addMessageToHistory(`Instance "${alias}" not found.`, 'bot', 'error'); - return; - } - delete instances[alias]; - await this._context.secrets.store('SEMOSS_INSTANCES', JSON.stringify(instances)); - // If this was the current instance, clear it - const currentAlias = await this._context.secrets.get('CURRENT_INSTANCE_ALIAS'); - if (currentAlias === alias) { - await this._context.secrets.delete('CURRENT_INSTANCE_ALIAS'); - } - // Update the status bar to reflect the changes - await updateStatusBar(this._context); - webviewView.webview.postMessage({ type: 'response', status: 'success', text: `Instance "${alias}" removed successfully!`, hideLoading: true }); - this._addMessageToHistory(`Instance "${alias}" removed successfully!`, 'bot', 'success'); - return; - } - }); - } - - /** - * Add a message to the chat history - * @param {string} text - The message text - * @param {string} from - Who sent the message ('user', 'bot', 'error') - * @param {string} status - The status of the message ('success', 'error', 'warning') - */ - _addMessageToHistory(text, from, status = null) { - // Ensure text is always a string - const messageText = typeof text === 'string' ? text : String(text); - - const message = { - text: messageText, - from, - status, - timestamp: Date.now() - }; - this._chatHistory.push(message); - - // Keep only last 100 messages to prevent memory issues - if (this._chatHistory.length > 100) { - this._chatHistory = this._chatHistory.slice(-100); - } - } - - /** - * Restore the chat state when webview becomes visible - */ - _restoreChatState() { - if (this._webviewView && this._webviewView.visible) { - // Send a small delay to ensure webview is fully loaded - setTimeout(() => { - this._webviewView.webview.postMessage({ - type: 'restoreHistory', - history: this._chatHistory, - state: this._currentState - }); - }, 100); - } - } + /** + * @param {vscode.ExtensionContext} context + */ + constructor(context) { + this._context = context; + this._chatHistory = []; + this._currentState = "start"; // 'start', 'options', 'authorized' + } + + /** + * @param {vscode.WebviewView} webviewView + */ + resolveWebviewView(webviewView) { + this._webviewView = webviewView; + webviewView.webview.options = { + enableScripts: true, + localResourceRoots: [ + vscode.Uri.file( + path.join( + this._context.extensionPath, + "src", + "components", + "ChatbotWebview", + ), + ), + vscode.Uri.file( + path.join( + this._context.extensionPath, + "src", + "components", + "Chatbot-ui", + ), + ), + ], + }; + + webviewView.webview.html = getWebviewContent( + webviewView.webview, + this._context, + ); + + // Restore chat history and state when webview becomes visible + webviewView.onDidChangeVisibility(() => { + if (webviewView.visible) { + this._restoreChatState(); + } + }); + + // Initial restore when webview is first created + this._restoreChatState(); + + webviewView.webview.onDidReceiveMessage(async (msg) => { + // Handle history-related messages + if (msg.type === "saveMessage") { + this._addMessageToHistory( + msg.message.text, + msg.message.from, + msg.status, + ); + return; + } + + if (msg.type === "saveState") { + this._currentState = msg.state; + return; + } + + if (msg.type === "getHistory") { + webviewView.webview.postMessage({ + type: "restoreHistory", + history: this._chatHistory, + state: this._currentState, + }); + return; + } + + if (msg.type === "clearHistory") { + this._chatHistory = []; + this._currentState = "start"; + return; + } + + if ( + msg.type === "openExternalResource" && + msg.resource === "user-manual" + ) { + // Get the path to the user manual PDF + const userManualPath = vscode.Uri.file( + path.join( + this._context.extensionPath, + "assets", + "docs", + "semoss_user_manual.pdf", + ), + ); + + // Open the PDF in the default PDF viewer + vscode.env.openExternal(userManualPath); + + // Log that the manual was accessed + this._addMessageToHistory( + "User manual downloaded", + "bot", + "success", + ); + return; + } + + if (msg.type === "getInstanceAliases") { + // Fetch aliases and send to webview, including URLs + const instances = await getStoredInstances(this._context); + const aliases = Object.keys(instances); + // Build a map of alias to URL (no optional chaining for compatibility) + const urls = {}; + for (const alias of aliases) { + urls[alias] = + instances[alias] && instances[alias].semossUrl + ? instances[alias].semossUrl + : ""; + } + // Get current instance alias + const currentAlias = await this._context.secrets.get( + "CURRENT_INSTANCE_ALIAS", + ); + webviewView.webview.postMessage({ + type: "instanceAliasesWithUrls", + aliases, + urls, + currentInstance: currentAlias, + }); + return; + } + if (msg.type === "checkSmssFile") { + // Check for .smss file in the workspace root + let hasSmss = false; + let folderPath; + if ( + vscode.workspace.workspaceFolders && + vscode.workspace.workspaceFolders.length > 0 + ) { + folderPath = + vscode.workspace.workspaceFolders[0].uri.fsPath; + try { + const files = fs.readdirSync(folderPath); + hasSmss = files.some((f) => f.endsWith(".smss")); + } catch (e) { + hasSmss = false; + } + } + webviewView.webview.postMessage({ + type: "smssFileCheckResult", + hasSmss, + }); + return; + } + if (msg.type === "checkInstanceAuthorized") { + // Check if any instance is authorized (secrets exist) + const secrets = await getSecrets(this._context); + const authorized = !!secrets && Object.keys(secrets).length > 0; + webviewView.webview.postMessage({ + type: "instanceAuthorizedResult", + authorized, + }); + return; + } + if (msg.type === "chat") { + let resultMsg = "Command received: " + JSON.stringify(msg); + // Use msg.command if present, otherwise map from message + const command = msg.command || mapMessageToCommand(msg); + // Remove deployonly from folderCommands so it never prompts for a folder + const folderCommands = []; + if (!command) { + resultMsg = "Sorry, I did not understand that command."; + } else { + try { + if (msg.inputs) { + switch (command) { + case "semoss.authorize": { + const { + alias, + url, + accessKey, + privateKey, + } = msg.inputs; + + // Input validation + if ( + !alias || + !url || + !accessKey || + !privateKey + ) { + webviewView.webview.postMessage({ + type: "response", + status: "error", + text: "All fields are required for authorization.", + hideLoading: true, + }); + return; + } + + try { + // Store the instance data + await storeInstance( + this._context, + alias, + { + semossUrl: url, + accessKey, + privateKey, + }, + ); + + // Verify the data was stored correctly + const instances = + await getStoredInstances( + this._context, + ); + const storedInstance = instances[alias]; + + if ( + !storedInstance || + storedInstance.semossUrl !== url || + storedInstance.accessKey !== + accessKey || + storedInstance.privateKey !== + privateKey + ) { + throw new Error( + "Failed to verify stored instance data", + ); + } + + // Set as current instance + await this._context.secrets.store( + "CURRENT_INSTANCE_ALIAS", + alias, + ); + + // Update status bar + await updateStatusBar(this._context); + + webviewView.webview.postMessage({ + type: "response", + status: "success", + text: + 'Instance "' + + alias + + '" authorized successfully!', + hideLoading: true, + }); + this._addMessageToHistory( + 'Instance "' + + alias + + '" authorized successfully!', + "bot", + "success", + ); + } catch (e) { + webviewView.webview.postMessage({ + type: "response", + status: "error", + text: + "Error authorizing instance: " + + e.message, + hideLoading: true, + }); + this._addMessageToHistory( + "Error authorizing instance: " + + e.message, + "bot", + "error", + ); + } + return; + } + case "semoss.createNewApp": { + const { + appName, + description, + githubLink, + isPrivateRepo, + accessToken, + } = msg.inputs; + + // Debug logging to confirm values are passed correctly + console.log( + "ChatbotWebview received inputs:", + { + appName, + description, + githubLink, + isPrivateRepo, + accessToken: accessToken + ? "PROVIDED" + : "NOT_PROVIDED", + }, + ); + + try { + const secrets = await getSecrets( + this._context, + ); + if (!secrets) { + resultMsg = + "Please authorize an instance first."; + webviewView.webview.postMessage({ + type: "response", + status: "error", + text: resultMsg, + hideLoading: true, + }); + return; + } + const result = await createNewApp( + this._context, + async () => secrets, + { + appName, + description, + githubLink, + isPrivateRepo, + accessToken, + }, + ); + if (result === false) { + resultMsg = `Cancelled: No folder selected.`; + webviewView.webview.postMessage({ + type: "response", + status: "warning", + text: resultMsg, + hideLoading: true, + }); + this._addMessageToHistory( + resultMsg, + "bot", + "warning", + ); + return; + } + resultMsg = `App \"${appName}\" created successfully!`; + // Always send hideLoading to stop spinner + webviewView.webview.postMessage({ + type: "response", + status: "success", + text: resultMsg, + hideLoading: true, + }); + this._addMessageToHistory( + resultMsg, + "bot", + "success", + ); + return; + } catch (e) { + resultMsg = `Error creating app: ${e.message}`; + webviewView.webview.postMessage({ + type: "response", + status: "error", + text: resultMsg, + hideLoading: true, + }); + this._addMessageToHistory( + resultMsg, + "bot", + "error", + ); + return; + } + } + default: { + // For folder commands, always use first workspace folder + if (folderCommands.includes(command)) { + let uri = msg.inputs && msg.inputs.uri; + if (!uri) { + if ( + vscode.workspace + .workspaceFolders && + vscode.workspace + .workspaceFolders.length > 0 + ) { + uri = + vscode.workspace + .workspaceFolders[0] + .uri; + } else { + resultMsg = + "No workspace folder found."; // Always hide loading even on error + webviewView.webview.postMessage( + { + type: "response", + status: "error", + text: resultMsg, + hideLoading: true, + }, + ); + this._addMessageToHistory( + resultMsg, + "bot", + "error", + ); + return; + } + } + await vscode.commands.executeCommand( + command, + uri, + ); + resultMsg = `Action '${command}' executed on selected folder.`; + // Always hide loading after deploy + webviewView.webview.postMessage({ + type: "response", + status: "success", + text: resultMsg, + hideLoading: true, + }); + this._addMessageToHistory( + resultMsg, + "bot", + "success", + ); + return; + } else { + await vscode.commands.executeCommand( + command, + msg.inputs, + ); + resultMsg = `Action '${command}' executed with provided details.`; + // Always hide loading after any command + webviewView.webview.postMessage({ + type: "response", + status: "success", + text: resultMsg, + hideLoading: true, + }); + this._addMessageToHistory( + resultMsg, + "bot", + "success", + ); + return; + } + } + } + } else { + // For folder commands, prompt for folder if not provided + if (folderCommands.includes(command)) { + const folders = + await vscode.window.showOpenDialog({ + canSelectFolders: true, + canSelectFiles: false, + canSelectMany: false, + openLabel: + "Select folder for operation", + }); + if (!folders || folders.length === 0) { + resultMsg = + "Operation cancelled: No folder selected."; + } else { + await vscode.commands.executeCommand( + command, + folders[0], + ); + resultMsg = `Action '${command}' executed on selected folder.`; + } + } else { + await vscode.commands.executeCommand(command); + resultMsg = `Action '${command}' executed.`; + } + } + } catch (e) { + resultMsg = `Error: ${e.message}`; + // Save error to history + this._addMessageToHistory(resultMsg, "bot", "error"); + } + } + // Ensure resultMsg is always a string before sending + const finalMsg = + typeof resultMsg === "string" + ? resultMsg + : String(resultMsg); + webviewView.webview.postMessage({ + type: "response", + text: finalMsg, + }); + } + if (msg.type === "getInstanceAliasesForRemoval") { + // Send aliases for removal + const instances = await getStoredInstances(this._context); + const aliases = Object.keys(instances); + + // Build a map of alias to URL + const urls = {}; + for (const alias of aliases) { + urls[alias] = + instances[alias] && instances[alias].semossUrl + ? instances[alias].semossUrl + : ""; + } + + // Get current instance alias + const currentAlias = await this._context.secrets.get( + "CURRENT_INSTANCE_ALIAS", + ); + webviewView.webview.postMessage({ + type: "instanceAliasesForRemoval", + aliases, + urls, + currentInstance: currentAlias, + }); + return; + } + if (msg.type === "removeInstanceByAlias") { + const { alias } = msg; + const instances = await getStoredInstances(this._context); + if (!instances[alias]) { + webviewView.webview.postMessage({ + type: "response", + status: "error", + text: `Instance "${alias}" not found.`, + hideLoading: true, + }); + this._addMessageToHistory( + `Instance "${alias}" not found.`, + "bot", + "error", + ); + return; + } + delete instances[alias]; + await this._context.secrets.store( + "SEMOSS_INSTANCES", + JSON.stringify(instances), + ); + // If this was the current instance, clear it + const currentAlias = await this._context.secrets.get( + "CURRENT_INSTANCE_ALIAS", + ); + if (currentAlias === alias) { + await this._context.secrets.delete( + "CURRENT_INSTANCE_ALIAS", + ); + } + // Update the status bar to reflect the changes + await updateStatusBar(this._context); + webviewView.webview.postMessage({ + type: "response", + status: "success", + text: `Instance "${alias}" removed successfully!`, + hideLoading: true, + }); + this._addMessageToHistory( + `Instance "${alias}" removed successfully!`, + "bot", + "success", + ); + return; + } + }); + } + + /** + * Add a message to the chat history + * @param {string} text - The message text + * @param {string} from - Who sent the message ('user', 'bot', 'error') + * @param {string} status - The status of the message ('success', 'error', 'warning') + */ + _addMessageToHistory(text, from, status = null) { + // Ensure text is always a string + const messageText = typeof text === "string" ? text : String(text); + + const message = { + text: messageText, + from, + status, + timestamp: Date.now(), + }; + this._chatHistory.push(message); + + // Keep only last 100 messages to prevent memory issues + if (this._chatHistory.length > 100) { + this._chatHistory = this._chatHistory.slice(-100); + } + } + + /** + * Restore the chat state when webview becomes visible + */ + _restoreChatState() { + if (this._webviewView && this._webviewView.visible) { + // Send a small delay to ensure webview is fully loaded + setTimeout(() => { + this._webviewView.webview.postMessage({ + type: "restoreHistory", + history: this._chatHistory, + state: this._currentState, + }); + }, 100); + } + } } function registerChatbotWebview(context) { - const provider = new SemossChatbotViewProvider(context); - context.subscriptions.push( - vscode.window.registerWebviewViewProvider( - 'semossChatbotView', - provider - ) - ); - vscode.window.showInformationMessage('If you do not see the Semoss Chatbot sidebar, click the Semoss Chatbot icon in the Activity Bar or use the command: Semoss: Open Chatbot.'); + const provider = new SemossChatbotViewProvider(context); + context.subscriptions.push( + vscode.window.registerWebviewViewProvider( + "semossChatbotView", + provider, + ), + ); + vscode.window.showInformationMessage( + "If you do not see the Semoss Chatbot sidebar, click the Semoss Chatbot icon in the Activity Bar or use the command: Semoss: Open Chatbot.", + ); } module.exports = { registerChatbotWebview }; diff --git a/packages/vscode-extension/src/utils/createApp.js b/packages/vscode-extension/src/utils/createApp.js index 8ecdd4c92d..3107ae60d0 100644 --- a/packages/vscode-extension/src/utils/createApp.js +++ b/packages/vscode-extension/src/utils/createApp.js @@ -1,28 +1,28 @@ /** * Semoss App Creation Utility - * + * * This module provides functionality for creating new applications in the Semoss platform. * It handles input collection, server communication, and local file operations. - * + * * @module createApp */ -import * as vscode from "vscode"; -import path from "path"; -import fs from "fs"; -import { setDeployConfig, deployProject } from "./deploy.js"; -import { zipProject } from "./zip.js"; import axios from "axios"; +import fs from "fs"; import http from "http"; import https from "https"; -import { processGithubAssets } from "./githubAssets.js"; import StreamZip from "node-stream-zip"; +import path from "path"; +import * as vscode from "vscode"; +import { deployProject, setDeployConfig } from "./deploy.js"; +import { processGithubAssets } from "./githubAssets.js"; +import { zipProject } from "./zip.js"; // Helper for error reporting function logError(context, err) { - const errorDetails = `${context}: ${err.message}`; - vscode.window.showErrorMessage(errorDetails); - console.error(errorDetails); + const errorDetails = `${context}: ${err.message}`; + vscode.window.showErrorMessage(errorDetails); + console.error(errorDetails); } /** @@ -30,14 +30,16 @@ function logError(context, err) { * @private */ const APP_CONFIG = { - PLACEHOLDER_HTML: (appName) => `

    ${appName}

    This is placeholder text for your new Application.

    You can add new files and edit this text using the Code Editor.

    `, - DEFAULT_ASSET_PATH: "version/assets/portals/index.html", - GITHUB_URL_PATTERN: /^https?:\/\/(www\.)?github\.com\/[\w-]+\/[\w.-]+\/?.*$/ + PLACEHOLDER_HTML: (appName) => + `

    ${appName}

    This is placeholder text for your new Application.

    You can add new files and edit this text using the Code Editor.

    `, + DEFAULT_ASSET_PATH: "version/assets/portals/index.html", + GITHUB_URL_PATTERN: + /^https?:\/\/(www\.)?github\.com\/[\w-]+\/[\w.-]+\/?.*$/, }; /** * Creates a new application in Semoss - * + * * @param {vscode.ExtensionContext} context - The extension context * @param {Function} getSecretsWithValidation - Function to get secrets with validation * @param {Object} [args] - Optional arguments for app creation @@ -50,200 +52,245 @@ const APP_CONFIG = { * @throws {Error} - If app creation fails */ export async function createNewApp(context, getSecretsWithValidation, args) { - try { - // 1. Collect all required inputs - const appDetails = await collectAppDetails(args); - if (!appDetails) return false; - - // 2. Select download folder - const downloadsDir = await selectDownloadFolder(); - if (!downloadsDir) return false; - - // 3. Prepare SEMOSS API secrets - const secrets = await getSecretsWithValidation(context); - if (!secrets) return false; - - // 4. Set up HTTP headers and auth - const auth = createAuthHeaders(secrets); - - // 5. Validate GitHub assets if provided before proceeding with app creation - if (appDetails.githubLink) { - const isValid = await validateGithubRepository(appDetails.githubLink, appDetails.isPrivateRepo, appDetails.accessToken); - if (!isValid) return false; - } - - // 6. Create the app on the server - const projectId = await createAppOnServer(secrets, auth.headers, appDetails); - - // 7. Add placeholder assets if needed - if (!appDetails.githubLink) { - await addPlaceholderAsset(secrets, auth.headers, projectId, appDetails.appName); - } - - // 8. Export and download the project - const filePath = await exportAndDownloadProject( - secrets, - auth.headers, - auth.encoded, - projectId, - downloadsDir, - appDetails.appName - ); - - // 9. Extract the downloaded zip - const unzipDir = await extractZipFile(filePath, downloadsDir, appDetails.appName); - - // 10. Process GitHub assets if needed - if (appDetails.githubLink) { - await processGithubAssetsForApp( - appDetails.githubLink, - downloadsDir, - appDetails.appName, - unzipDir, - appDetails.isPrivateRepo, - appDetails.accessToken - ); - } - - // 11. Open folder in VS Code - await vscode.commands.executeCommand('vscode.openFolder', vscode.Uri.file(unzipDir), true); - - // 12. Zip and deploy the project - await zipAndDeployProject( - unzipDir, - projectId, - secrets, - auth.headers, - auth.encoded - ); - - vscode.window.showInformationMessage('App created, zipped and deployed successfully!'); - return true; - } catch (err) { - logError('App creation failed', err); - throw err; - } + try { + // 1. Collect all required inputs + const appDetails = await collectAppDetails(args); + if (!appDetails) return false; + + // 2. Select download folder + const downloadsDir = await selectDownloadFolder(); + if (!downloadsDir) return false; + + // 3. Prepare SEMOSS API secrets + const secrets = await getSecretsWithValidation(context); + if (!secrets) return false; + + // 4. Set up HTTP headers and auth + const auth = createAuthHeaders(secrets); + + // 5. Validate GitHub assets if provided before proceeding with app creation + if (appDetails.githubLink) { + const isValid = await validateGithubRepository( + appDetails.githubLink, + appDetails.isPrivateRepo, + appDetails.accessToken, + ); + if (!isValid) return false; + } + + // 6. Create the app on the server + const projectId = await createAppOnServer( + secrets, + auth.headers, + appDetails, + ); + + // 7. Add placeholder assets if needed + if (!appDetails.githubLink) { + await addPlaceholderAsset( + secrets, + auth.headers, + projectId, + appDetails.appName, + ); + } + + // 8. Export and download the project + const filePath = await exportAndDownloadProject( + secrets, + auth.headers, + auth.encoded, + projectId, + downloadsDir, + appDetails.appName, + ); + + // 9. Extract the downloaded zip + const unzipDir = await extractZipFile( + filePath, + downloadsDir, + appDetails.appName, + ); + + // 10. Process GitHub assets if needed + if (appDetails.githubLink) { + await processGithubAssetsForApp( + appDetails.githubLink, + downloadsDir, + appDetails.appName, + unzipDir, + appDetails.isPrivateRepo, + appDetails.accessToken, + ); + } + + // 11. Open folder in VS Code + await vscode.commands.executeCommand( + "vscode.openFolder", + vscode.Uri.file(unzipDir), + true, + ); + + // 12. Zip and deploy the project + await zipAndDeployProject( + unzipDir, + projectId, + secrets, + auth.headers, + auth.encoded, + ); + + vscode.window.showInformationMessage( + "App created, zipped and deployed successfully!", + ); + return true; + } catch (err) { + logError("App creation failed", err); + throw err; + } } /** * Collects app details from user input or provided arguments - * + * * @param {Object} [args] - Optional arguments containing app details * @returns {Promise} - Object containing app details or null if cancelled */ async function collectAppDetails(args) { - let appName, description, githubLink, isPrivateRepo = false, accessToken = ''; - - if (args && args.appName) { - appName = args.appName; - description = args.description || ''; - githubLink = args.githubLink || ''; - isPrivateRepo = args.isPrivateRepo || false; - accessToken = args.accessToken || ''; - } else { - appName = await vscode.window.showInputBox({ prompt: 'Enter app name' }); - if (!appName) return null; - - description = await vscode.window.showInputBox({ prompt: 'Enter app description (optional)' }); - githubLink = await vscode.window.showInputBox({ prompt: 'GitHub link for assets (optional)' }); - - // Ask about private repository if GitHub link is provided - if (githubLink) { - const privateRepoChoice = await vscode.window.showQuickPick( - ['No', 'Yes'], - { - placeHolder: 'Is this a private repository?', - ignoreFocusOut: true - } - ); - - if (privateRepoChoice === 'Yes') { - isPrivateRepo = true; - accessToken = await vscode.window.showInputBox({ - prompt: 'Enter GitHub access token (required for private repositories)', - password: true - }); - if (!accessToken) { - vscode.window.showErrorMessage('Access token is required for private repositories'); - return null; - } - } - } - } - - return { appName, description, githubLink, isPrivateRepo, accessToken }; + let appName, + description, + githubLink, + isPrivateRepo = false, + accessToken = ""; + + if (args && args.appName) { + appName = args.appName; + description = args.description || ""; + githubLink = args.githubLink || ""; + isPrivateRepo = args.isPrivateRepo || false; + accessToken = args.accessToken || ""; + } else { + appName = await vscode.window.showInputBox({ + prompt: "Enter app name", + }); + if (!appName) return null; + + description = await vscode.window.showInputBox({ + prompt: "Enter app description (optional)", + }); + githubLink = await vscode.window.showInputBox({ + prompt: "GitHub link for assets (optional)", + }); + + // Ask about private repository if GitHub link is provided + if (githubLink) { + const privateRepoChoice = await vscode.window.showQuickPick( + ["No", "Yes"], + { + placeHolder: "Is this a private repository?", + ignoreFocusOut: true, + }, + ); + + if (privateRepoChoice === "Yes") { + isPrivateRepo = true; + accessToken = await vscode.window.showInputBox({ + prompt: "Enter GitHub access token (required for private repositories)", + password: true, + }); + if (!accessToken) { + vscode.window.showErrorMessage( + "Access token is required for private repositories", + ); + return null; + } + } + } + } + + return { appName, description, githubLink, isPrivateRepo, accessToken }; } /** * Prompts user to select a download folder - * + * * @returns {Promise} - Selected folder path or null if cancelled * @throws {Error} - If no folder is selected */ async function selectDownloadFolder() { - const uri = await vscode.window.showOpenDialog({ - canSelectFolders: true, - canSelectFiles: false, - canSelectMany: false, - openLabel: 'Select download folder' - }); - - if (!uri || uri.length === 0) { - return null; - } - - return uri[0].fsPath; + const uri = await vscode.window.showOpenDialog({ + canSelectFolders: true, + canSelectFiles: false, + canSelectMany: false, + openLabel: "Select download folder", + }); + + if (!uri || uri.length === 0) { + return null; + } + + return uri[0].fsPath; } /** * Creates authentication headers from secrets - * + * * @param {Object} secrets - The secrets object * @returns {Object} - Object containing encoded credentials and headers */ function createAuthHeaders(secrets) { - const encoded = Buffer.from(secrets.accessKey + ':' + secrets.privateKey).toString('base64'); - const headers = { - 'Authorization': 'Basic ' + encoded, - 'Content-Type': 'application/x-www-form-urlencoded' - }; - - return { encoded, headers }; + const encoded = Buffer.from( + secrets.accessKey + ":" + secrets.privateKey, + ).toString("base64"); + const headers = { + Authorization: "Basic " + encoded, + "Content-Type": "application/x-www-form-urlencoded", + }; + + return { encoded, headers }; } /** * Validates a GitHub repository - * + * * @param {string} githubLink - The GitHub repository URL * @param {boolean} isPrivateRepo - Whether the repo is private * @param {string} accessToken - GitHub access token for private repos * @returns {Promise} - Whether the repository is valid * @throws {Error} - If validation fails */ -async function validateGithubRepository(githubLink, isPrivateRepo, accessToken) { - try { - vscode.window.showInformationMessage(`Validating GitHub repository: ${githubLink}`); - - if (isPrivateRepo && (!accessToken || accessToken.trim() === '')) { - throw new Error('Access token is required for private repositories'); - } - - const githubUrlPattern = APP_CONFIG.GITHUB_URL_PATTERN; - if (!githubUrlPattern.test(githubLink)) { - throw new Error('Invalid GitHub repository URL format'); - } - - return true; - } catch (err) { - const msg = `GitHub validation failed: ${err.message || err}`; - vscode.window.showErrorMessage(msg); - return false; - } +async function validateGithubRepository( + githubLink, + isPrivateRepo, + accessToken, +) { + try { + vscode.window.showInformationMessage( + `Validating GitHub repository: ${githubLink}`, + ); + + if (isPrivateRepo && (!accessToken || accessToken.trim() === "")) { + throw new Error( + "Access token is required for private repositories", + ); + } + + const githubUrlPattern = APP_CONFIG.GITHUB_URL_PATTERN; + if (!githubUrlPattern.test(githubLink)) { + throw new Error("Invalid GitHub repository URL format"); + } + + return true; + } catch (err) { + const msg = `GitHub validation failed: ${err.message || err}`; + vscode.window.showErrorMessage(msg); + return false; + } } /** * Creates a new application on the Semoss server - * + * * @param {Object} secrets - The secrets object * @param {Object} headers - The HTTP headers * @param {Object} appDetails - The app details @@ -251,64 +298,77 @@ async function validateGithubRepository(githubLink, isPrivateRepo, accessToken) * @throws {Error} - If app creation fails */ async function createAppOnServer(secrets, headers, appDetails) { - const params = new URLSearchParams(); - params.append('expression', - `CreateProject(project=["${appDetails.appName}"], portal=[true], projectType=["CODE"])` - ); - params.append('insightId', 'new'); - - try { - const response = await axios.post( - `${secrets.semossUrl}/Monolith/api/engine/runPixel`, - params, - { headers } - ); - - if (!response.data || - !response.data.pixelReturn || - !response.data.pixelReturn[0] || - !response.data.pixelReturn[0].output || - !response.data.pixelReturn[0].output.project_id) { - logError('CreateProject response invalid', new Error('Invalid response from SEMOSS API')); - throw new Error('Failed to create app: Invalid response'); - } - - const projectId = response.data.pixelReturn[0].output.project_id; - - // Set description using SetProjectMetadata if description is provided - if (appDetails.description) { - const metadataParams = new URLSearchParams(); - metadataParams.append('expression', - `SetProjectMetadata(project=["${projectId}"], meta=[{"tag":[],"description":"${appDetails.description}"}])` - ); - metadataParams.append('insightId', response.data.insightID || 'new'); - - await axios.post( - `${secrets.semossUrl}/Monolith/api/engine/runPixel`, - metadataParams, - { headers } - ); - } - - return projectId; - } catch (err) { - if (err.isAxiosError) { - logError('Axios error during CreateProject', err); - const url = (err.config && err.config.url) ? err.config.url : 'N/A'; - const status = (err.response && err.response.status) ? err.response.status : 'N/A'; - vscode.window.showErrorMessage( - `Network/API error: ${err.message}\nURL: ${url}\nStatus: ${status}` - ); - } else { - logError('App creation failed', err); - } - throw err; - } + const params = new URLSearchParams(); + params.append( + "expression", + `CreateProject(project=["${appDetails.appName}"], portal=[true], projectType=["CODE"])`, + ); + params.append("insightId", "new"); + + try { + const response = await axios.post( + `${secrets.semossUrl}/Monolith/api/engine/runPixel`, + params, + { headers }, + ); + + if ( + !response.data || + !response.data.pixelReturn || + !response.data.pixelReturn[0] || + !response.data.pixelReturn[0].output || + !response.data.pixelReturn[0].output.project_id + ) { + logError( + "CreateProject response invalid", + new Error("Invalid response from SEMOSS API"), + ); + throw new Error("Failed to create app: Invalid response"); + } + + const projectId = response.data.pixelReturn[0].output.project_id; + + // Set description using SetProjectMetadata if description is provided + if (appDetails.description) { + const metadataParams = new URLSearchParams(); + metadataParams.append( + "expression", + `SetProjectMetadata(project=["${projectId}"], meta=[{"tag":[],"description":"${appDetails.description}"}])`, + ); + metadataParams.append( + "insightId", + response.data.insightID || "new", + ); + + await axios.post( + `${secrets.semossUrl}/Monolith/api/engine/runPixel`, + metadataParams, + { headers }, + ); + } + + return projectId; + } catch (err) { + if (err.isAxiosError) { + logError("Axios error during CreateProject", err); + const url = err.config && err.config.url ? err.config.url : "N/A"; + const status = + err.response && err.response.status + ? err.response.status + : "N/A"; + vscode.window.showErrorMessage( + `Network/API error: ${err.message}\nURL: ${url}\nStatus: ${status}`, + ); + } else { + logError("App creation failed", err); + } + throw err; + } } /** * Adds a placeholder HTML asset to the project - * + * * @param {Object} secrets - The secrets object * @param {Object} headers - The HTTP headers * @param {string} projectId - The project ID @@ -317,28 +377,33 @@ async function createAppOnServer(secrets, headers, appDetails) { * @throws {Error} - If adding the placeholder asset fails */ async function addPlaceholderAsset(secrets, headers, projectId, appName) { - const saveAssetParams = new URLSearchParams(); - saveAssetParams.append( - 'expression', - `SaveAsset(fileName=["${APP_CONFIG.DEFAULT_ASSET_PATH}"], content=["${APP_CONFIG.PLACEHOLDER_HTML(appName)}"], space=["${projectId}"]);` - ); - saveAssetParams.append('insightId', 'new'); - - try { - await axios.post( - `${secrets.semossUrl}/Monolith/api/engine/runPixel`, - saveAssetParams, - { headers } - ); - vscode.window.showInformationMessage('Placeholder asset (index.html) added to the project.'); - } catch (err) { - throw new Error('Failed to add placeholder asset: ' + (err.message || 'Unknown error')); - } + const saveAssetParams = new URLSearchParams(); + saveAssetParams.append( + "expression", + `SaveAsset(fileName=["${APP_CONFIG.DEFAULT_ASSET_PATH}"], content=["${APP_CONFIG.PLACEHOLDER_HTML(appName)}"], space=["${projectId}"]);`, + ); + saveAssetParams.append("insightId", "new"); + + try { + await axios.post( + `${secrets.semossUrl}/Monolith/api/engine/runPixel`, + saveAssetParams, + { headers }, + ); + vscode.window.showInformationMessage( + "Placeholder asset (index.html) added to the project.", + ); + } catch (err) { + throw new Error( + "Failed to add placeholder asset: " + + (err.message || "Unknown error"), + ); + } } /** * Exports and downloads the project - * + * * @param {Object} secrets - The secrets object * @param {Object} headers - The HTTP headers * @param {string} encoded - The encoded credentials @@ -348,119 +413,137 @@ async function addPlaceholderAsset(secrets, headers, projectId, appName) { * @returns {Promise} - The path to the downloaded file * @throws {Error} - If export or download fails */ -async function exportAndDownloadProject(secrets, headers, encoded, projectId, downloadsDir, appName) { - // Export project - const exportParams = new URLSearchParams(); - exportParams.append('expression', `ExportProjectApp(project=["${projectId}"]);`); - exportParams.append('insightId', 'new'); - - const exportResponse = await axios.post( - `${secrets.semossUrl}/Monolith/api/engine/runPixel`, - exportParams, - { headers } - ); - - if (!exportResponse.data || - !exportResponse.data.pixelReturn || - !exportResponse.data.pixelReturn[0] || - !exportResponse.data.pixelReturn[0].output) { - throw new Error('Export failed: Invalid response from server.'); - } - - const fileKey = exportResponse.data.pixelReturn[0].output; - const insightId = exportResponse.data.insightID; - const filePath = path.join(downloadsDir, `${appName}.zip`); - const downloadUrl = `${secrets.semossUrl}/Monolith/api/engine/downloadFile?insightId=${insightId}&fileKey=${encodeURIComponent(fileKey)}`; - - await downloadFile(downloadUrl, filePath, encoded); - - try { - const stats = fs.statSync(filePath); - vscode.window.showInformationMessage(`Downloaded file size: ${stats.size} bytes`); - return filePath; - } catch (e) { - console.error(`Failed to get file stats for ${filePath}:`, e); - throw new Error(`Could not get file size for ${filePath}.`); - } +async function exportAndDownloadProject( + secrets, + headers, + encoded, + projectId, + downloadsDir, + appName, +) { + // Export project + const exportParams = new URLSearchParams(); + exportParams.append( + "expression", + `ExportProjectApp(project=["${projectId}"]);`, + ); + exportParams.append("insightId", "new"); + + const exportResponse = await axios.post( + `${secrets.semossUrl}/Monolith/api/engine/runPixel`, + exportParams, + { headers }, + ); + + if ( + !exportResponse.data || + !exportResponse.data.pixelReturn || + !exportResponse.data.pixelReturn[0] || + !exportResponse.data.pixelReturn[0].output + ) { + throw new Error("Export failed: Invalid response from server."); + } + + const fileKey = exportResponse.data.pixelReturn[0].output; + const insightId = exportResponse.data.insightID; + const filePath = path.join(downloadsDir, `${appName}.zip`); + const downloadUrl = `${secrets.semossUrl}/Monolith/api/engine/downloadFile?insightId=${insightId}&fileKey=${encodeURIComponent(fileKey)}`; + + await downloadFile(downloadUrl, filePath, encoded); + + try { + const stats = fs.statSync(filePath); + vscode.window.showInformationMessage( + `Downloaded file size: ${stats.size} bytes`, + ); + return filePath; + } catch (e) { + console.error(`Failed to get file stats for ${filePath}:`, e); + throw new Error(`Could not get file size for ${filePath}.`); + } } /** * Downloads a file from a URL - * + * * @param {string} url - The URL to download from * @param {string} filePath - The path to save the file to * @param {string} encoded - The encoded credentials * @returns {Promise} */ async function downloadFile(url, filePath, encoded) { - return new Promise((resolve, reject) => { - const file = fs.createWriteStream(filePath); - const parsedUrl = new URL(url); - const protocol = parsedUrl.protocol === 'https:' ? https : http; - const options = { - hostname: parsedUrl.hostname, - port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80), - path: parsedUrl.pathname + parsedUrl.search, - method: 'GET', - headers: { - 'Authorization': 'Basic ' + encoded - } - }; - - const req = protocol.request(options, (response) => { - if (response.statusCode !== 200) { - let errorMsg = `Download failed with status code: ${response.statusCode}`; - response.on('data', chunk => errorMsg += chunk.toString()); - response.on('end', () => { - vscode.window.showErrorMessage(errorMsg); - reject(new Error(errorMsg)); - }); - return; - } - - response.pipe(file); - file.on('finish', () => { - file.close(resolve); - }); - file.on('error', (err) => reject(err)); - }); - - req.on('error', (err) => { - fs.unlink(filePath, () => { }); - vscode.window.showErrorMessage(`Download failed: ${err.message}`); - reject(err); - }); - - req.end(); - }); + return new Promise((resolve, reject) => { + const file = fs.createWriteStream(filePath); + const parsedUrl = new URL(url); + const protocol = parsedUrl.protocol === "https:" ? https : http; + const options = { + hostname: parsedUrl.hostname, + port: + parsedUrl.port || (parsedUrl.protocol === "https:" ? 443 : 80), + path: parsedUrl.pathname + parsedUrl.search, + method: "GET", + headers: { + Authorization: "Basic " + encoded, + }, + }; + + const req = protocol.request(options, (response) => { + if (response.statusCode !== 200) { + let errorMsg = `Download failed with status code: ${response.statusCode}`; + response.on("data", (chunk) => (errorMsg += chunk.toString())); + response.on("end", () => { + vscode.window.showErrorMessage(errorMsg); + reject(new Error(errorMsg)); + }); + return; + } + + response.pipe(file); + file.on("finish", () => { + file.close(resolve); + }); + file.on("error", (err) => reject(err)); + }); + + req.on("error", (err) => { + fs.unlink(filePath, () => {}); + vscode.window.showErrorMessage(`Download failed: ${err.message}`); + reject(err); + }); + + req.end(); + }); } /** * Extracts a zip file - * + * * @param {string} filePath - The path to the zip file * @param {string} downloadsDir - The directory containing the zip * @param {string} appName - The app name * @returns {Promise} - The path to the extracted directory */ async function extractZipFile(filePath, downloadsDir, appName) { - const unzipDir = path.join(downloadsDir, `${appName}_unzipped_${Date.now()}`); + const unzipDir = path.join( + downloadsDir, + `${appName}_unzipped_${Date.now()}`, + ); - if (!fs.existsSync(unzipDir)) { - fs.mkdirSync(unzipDir); - } + if (!fs.existsSync(unzipDir)) { + fs.mkdirSync(unzipDir); + } - const zip = new StreamZip.async({ file: filePath }); - await zip.extract(null, unzipDir); // Extract all files - await zip.close(); + const zip = new StreamZip.async({ file: filePath }); + await zip.extract(null, unzipDir); // Extract all files + await zip.close(); - vscode.window.showInformationMessage(`App unzipped to ${unzipDir}`); - return unzipDir; + vscode.window.showInformationMessage(`App unzipped to ${unzipDir}`); + return unzipDir; } /** * Processes GitHub assets for an app - * + * * @param {string} githubLink - The GitHub repository URL * @param {string} downloadsDir - The downloads directory * @param {string} appName - The app name @@ -470,28 +553,41 @@ async function extractZipFile(filePath, downloadsDir, appName) { * @returns {Promise} * @throws {Error} - If processing GitHub assets fails */ -async function processGithubAssetsForApp(githubLink, downloadsDir, appName, unzipDir, isPrivateRepo, accessToken) { - vscode.window.showInformationMessage(`Processing GitHub assets from: ${githubLink}`); - - const githubSuccess = await processGithubAssets( - githubLink, - downloadsDir, - appName, - unzipDir, - isPrivateRepo, - accessToken - ); - - if (!githubSuccess) { - throw new Error('Failed to process GitHub assets. App creation aborted.'); - } - - vscode.window.showInformationMessage('GitHub assets processed successfully. Continuing with app setup...'); +async function processGithubAssetsForApp( + githubLink, + downloadsDir, + appName, + unzipDir, + isPrivateRepo, + accessToken, +) { + vscode.window.showInformationMessage( + `Processing GitHub assets from: ${githubLink}`, + ); + + const githubSuccess = await processGithubAssets( + githubLink, + downloadsDir, + appName, + unzipDir, + isPrivateRepo, + accessToken, + ); + + if (!githubSuccess) { + throw new Error( + "Failed to process GitHub assets. App creation aborted.", + ); + } + + vscode.window.showInformationMessage( + "GitHub assets processed successfully. Continuing with app setup...", + ); } /** * Zips and deploys a project - * + * * @param {string} unzipDir - The directory containing the unzipped app * @param {string} projectId - The project ID * @param {Object} secrets - The secrets object @@ -499,19 +595,25 @@ async function processGithubAssetsForApp(githubLink, downloadsDir, appName, unzi * @param {string} encoded - The encoded credentials * @returns {Promise} - The path to the zip file */ -async function zipAndDeployProject(unzipDir, projectId, secrets, headers, encoded) { - await zipProject(unzipDir); - const zipOutputPath = path.join(unzipDir, 'assets.zip'); - vscode.window.showInformationMessage(`App zipped to ${zipOutputPath}`); - - // Deploy the zipped app - setDeployConfig({ - semossUrl: secrets.semossUrl, - authHeaders: headers, - base64Encoded: encoded, - outputPath: zipOutputPath - }); - - await deployProject(projectId); - return zipOutputPath; +async function zipAndDeployProject( + unzipDir, + projectId, + secrets, + headers, + encoded, +) { + await zipProject(unzipDir); + const zipOutputPath = path.join(unzipDir, "assets.zip"); + vscode.window.showInformationMessage(`App zipped to ${zipOutputPath}`); + + // Deploy the zipped app + setDeployConfig({ + semossUrl: secrets.semossUrl, + authHeaders: headers, + base64Encoded: encoded, + outputPath: zipOutputPath, + }); + + await deployProject(projectId); + return zipOutputPath; } diff --git a/packages/vscode-extension/src/utils/deploy.js b/packages/vscode-extension/src/utils/deploy.js index 3523c03324..481595dbaa 100644 --- a/packages/vscode-extension/src/utils/deploy.js +++ b/packages/vscode-extension/src/utils/deploy.js @@ -1,7 +1,7 @@ const vscode = require("vscode"); const fs = require("fs"); const axios = require("axios"); -const FormData = require('form-data'); +const FormData = require("form-data"); let SEMOSS_URL = ""; let headers = {}; @@ -14,16 +14,16 @@ let outputFilePath = ""; * @returns {string} - A user-friendly error message */ function getErrorMessage(error) { - if (error.response) { - // Server responded with error status - return `Server error ${error.response.status}: ${error.response.statusText}`; - } else if (error.request) { - // Request made but no response received - return 'No response from server - check your connection and server URL'; - } else { - // Error in setting up the request - return error.message; - } + if (error.response) { + // Server responded with error status + return `Server error ${error.response.status}: ${error.response.statusText}`; + } else if (error.request) { + // Request made but no response received + return "No response from server - check your connection and server URL"; + } else { + // Error in setting up the request + return error.message; + } } /** @@ -35,10 +35,10 @@ function getErrorMessage(error) { * @param {string} config.outputPath - The output file path */ function setDeployConfig(config) { - SEMOSS_URL = config.semossUrl; - headers = config.authHeaders; - encoded = config.base64Encoded; - outputFilePath = config.outputPath; + SEMOSS_URL = config.semossUrl; + headers = config.authHeaders; + encoded = config.base64Encoded; + outputFilePath = config.outputPath; } /** @@ -47,191 +47,283 @@ function setDeployConfig(config) { * @returns {Promise} */ async function deployProject(projectId) { - await vscode.window.withProgress({ - location: vscode.ProgressLocation.Notification, - title: "Deploying Project", - cancellable: false - }, async (progress) => { - progress.report({ increment: 10 }); - - let response, params, insightId = ""; - - // Create new insight - try { - params = new URLSearchParams(); - params.append('expression', 'true'); - params.append('insightId', 'new'); - - response = await axios.post(`${SEMOSS_URL}/Monolith/api/engine/runPixel`, params, { headers }); - insightId = response.data.insightID; - } catch (error) { - vscode.window.showErrorMessage(`Failed to create new insight: ${getErrorMessage(error)}`); - return; - } - - if (!insightId) { - vscode.window.showErrorMessage('Empty insight ID returned created'); - return; - } - - progress.report({ increment: 15 }); - - // Delete existing assets - try { - params = new URLSearchParams(); - params.append('expression', `DeleteAsset(filePath=["version/assets/"], space=["${projectId}"]);`); - params.append('insightId', insightId); - - console.log(`Deleting assets for project: ${projectId}`); - response = await axios.post(`${SEMOSS_URL}/Monolith/api/engine/runPixel`, params, { headers }); - } catch (error) { - console.error('Delete assets error:', error); - vscode.window.showErrorMessage(`Failed to delete assets: ${getErrorMessage(error)}`); - return; - } - - // Check if deletion was successful or if assets didn't exist (both are OK) - if (response.data.pixelReturn[0].operationType[0] !== "SUCCESS") { - const errorOutput = response.data.pixelReturn[0].output; - console.error('Delete assets failed:', errorOutput); - - // If the error is just that the folder doesn't exist, that's fine - continue - if (errorOutput && errorOutput.includes('does not exist') || errorOutput.includes('not found')) { - console.log('Assets folder does not exist, continuing with upload...'); - } else { - vscode.window.showErrorMessage(`Failed to delete assets: ${errorOutput}`); - return; - } - } else { - console.log('Assets deleted successfully'); - } - - progress.report({ increment: 20 }); - - // Upload new assets - try { - // Verify the file exists and is readable - if (!fs.existsSync(outputFilePath)) { - vscode.window.showErrorMessage(`Upload file does not exist: ${outputFilePath}`); - return; - } - - const stats = fs.statSync(outputFilePath); - if (stats.size === 0) { - vscode.window.showErrorMessage(`Upload file is empty: ${outputFilePath}`); - return; - } - - const formData = new FormData(); - formData.append('file', fs.createReadStream(outputFilePath)); - - console.log(`Uploading file: ${outputFilePath} (${Math.round(stats.size / 1024)} KB) to project: ${projectId}`); - response = await axios.post(`${SEMOSS_URL}/Monolith/api/uploadFile/baseUpload?insightId=${insightId}&projectId=${projectId}&path=version/assets/`, formData, { - headers: { - ...formData.getHeaders(), - 'Authorization': 'Basic ' + encoded - }, - timeout: 60000 // 60 second timeout for large files - }); - } catch (error) { - console.error('Upload assets error:', error); - vscode.window.showErrorMessage(`Failed to upload assets: ${getErrorMessage(error)}`); - return; - } - - if (!response.data || !response.data[0] || !response.data[0].fileLocation) { - console.error('Upload response:', response.data); - vscode.window.showErrorMessage('Failed to upload assets: Invalid response from server'); - return; - } - - console.log('Assets uploaded successfully:', response.data[0].fileLocation); - - progress.report({ increment: 50 }); - - // Unzip the uploaded file - const fileLocation = response.data[0].fileLocation; - try { - params = new URLSearchParams(); - params.append('expression', `UnzipFile(filePath=["${fileLocation}"], space=["${projectId}"]);`) - params.append('insightId', insightId); - - response = await axios.post(`${SEMOSS_URL}/Monolith/api/engine/runPixel`, params, { headers }); - } catch (error) { - vscode.window.showErrorMessage(`Failed to unzip file: ${getErrorMessage(error)}`); - return; - } - - if (response.data.pixelReturn[0].output !== true) { - const apiError = response.data.pixelReturn[0].output; - vscode.window.showErrorMessage(`Failed to unzip the uploaded file on the server. API response: ${apiError}`); - return; - } - - progress.report({ increment: 70 }); - - // Reload insight classes - try { - params = new URLSearchParams(); - params.append('expression', `ReloadInsightClasses('${projectId}');`) - params.append('insightId', insightId); - - response = await axios.post(`${SEMOSS_URL}/Monolith/api/engine/runPixel`, params, { headers }); - } catch (error) { - vscode.window.showErrorMessage(`Failed to reload insight classes: ${getErrorMessage(error)}`); - return; - } - - if (!response.data.pixelReturn[0].output) { - vscode.window.showErrorMessage('Failed to reload insight classes'); - return; - } - - progress.report({ increment: 80 }); - - // Set project portal - try { - params = new URLSearchParams(); - params.append('projectId', projectId) - params.append('hasPortal', true); - - response = await axios.post(`${SEMOSS_URL}/Monolith/api/auth/project/setProjectPortal`, params, { headers }); - } catch (error) { - vscode.window.showErrorMessage(`Failed to set project portal: ${getErrorMessage(error)}`); - return; - } - - if (!response.data) { - vscode.window.showErrorMessage('Failed to set project portal'); - return; - } - - progress.report({ increment: 90 }); - - // Publish project - try { - params = new URLSearchParams(); - params.append('expression', `PublishProject('${projectId}', release=true);`) - params.append('insightId', insightId); - - response = await axios.post(`${SEMOSS_URL}/Monolith/api/engine/runPixel`, params, { headers }); - } catch (error) { - vscode.window.showErrorMessage(`Failed to publish project: ${getErrorMessage(error)}`); - return; - } - - progress.report({ increment: 100 }); - - if (response.data.pixelReturn[0].additionalOutput[0].operationType[0] !== "SUCCESS") { - vscode.window.showErrorMessage('Failed to publish project'); - return; - } - - vscode.window.showInformationMessage('Project deployed successfully!'); - }); + await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: "Deploying Project", + cancellable: false, + }, + async (progress) => { + progress.report({ increment: 10 }); + + let response, + params, + insightId = ""; + + // Create new insight + try { + params = new URLSearchParams(); + params.append("expression", "true"); + params.append("insightId", "new"); + + response = await axios.post( + `${SEMOSS_URL}/Monolith/api/engine/runPixel`, + params, + { headers }, + ); + insightId = response.data.insightID; + } catch (error) { + vscode.window.showErrorMessage( + `Failed to create new insight: ${getErrorMessage(error)}`, + ); + return; + } + + if (!insightId) { + vscode.window.showErrorMessage( + "Empty insight ID returned created", + ); + return; + } + + progress.report({ increment: 15 }); + + // Delete existing assets + try { + params = new URLSearchParams(); + params.append( + "expression", + `DeleteAsset(filePath=["version/assets/"], space=["${projectId}"]);`, + ); + params.append("insightId", insightId); + + console.log(`Deleting assets for project: ${projectId}`); + response = await axios.post( + `${SEMOSS_URL}/Monolith/api/engine/runPixel`, + params, + { headers }, + ); + } catch (error) { + console.error("Delete assets error:", error); + vscode.window.showErrorMessage( + `Failed to delete assets: ${getErrorMessage(error)}`, + ); + return; + } + + // Check if deletion was successful or if assets didn't exist (both are OK) + if (response.data.pixelReturn[0].operationType[0] !== "SUCCESS") { + const errorOutput = response.data.pixelReturn[0].output; + console.error("Delete assets failed:", errorOutput); + + // If the error is just that the folder doesn't exist, that's fine - continue + if ( + (errorOutput && errorOutput.includes("does not exist")) || + errorOutput.includes("not found") + ) { + console.log( + "Assets folder does not exist, continuing with upload...", + ); + } else { + vscode.window.showErrorMessage( + `Failed to delete assets: ${errorOutput}`, + ); + return; + } + } else { + console.log("Assets deleted successfully"); + } + + progress.report({ increment: 20 }); + + // Upload new assets + try { + // Verify the file exists and is readable + if (!fs.existsSync(outputFilePath)) { + vscode.window.showErrorMessage( + `Upload file does not exist: ${outputFilePath}`, + ); + return; + } + + const stats = fs.statSync(outputFilePath); + if (stats.size === 0) { + vscode.window.showErrorMessage( + `Upload file is empty: ${outputFilePath}`, + ); + return; + } + + const formData = new FormData(); + formData.append("file", fs.createReadStream(outputFilePath)); + + console.log( + `Uploading file: ${outputFilePath} (${Math.round(stats.size / 1024)} KB) to project: ${projectId}`, + ); + response = await axios.post( + `${SEMOSS_URL}/Monolith/api/uploadFile/baseUpload?insightId=${insightId}&projectId=${projectId}&path=version/assets/`, + formData, + { + headers: { + ...formData.getHeaders(), + Authorization: "Basic " + encoded, + }, + timeout: 60000, // 60 second timeout for large files + }, + ); + } catch (error) { + console.error("Upload assets error:", error); + vscode.window.showErrorMessage( + `Failed to upload assets: ${getErrorMessage(error)}`, + ); + return; + } + + if ( + !response.data || + !response.data[0] || + !response.data[0].fileLocation + ) { + console.error("Upload response:", response.data); + vscode.window.showErrorMessage( + "Failed to upload assets: Invalid response from server", + ); + return; + } + + console.log( + "Assets uploaded successfully:", + response.data[0].fileLocation, + ); + + progress.report({ increment: 50 }); + + // Unzip the uploaded file + const fileLocation = response.data[0].fileLocation; + try { + params = new URLSearchParams(); + params.append( + "expression", + `UnzipFile(filePath=["${fileLocation}"], space=["${projectId}"]);`, + ); + params.append("insightId", insightId); + + response = await axios.post( + `${SEMOSS_URL}/Monolith/api/engine/runPixel`, + params, + { headers }, + ); + } catch (error) { + vscode.window.showErrorMessage( + `Failed to unzip file: ${getErrorMessage(error)}`, + ); + return; + } + + if (response.data.pixelReturn[0].output !== true) { + const apiError = response.data.pixelReturn[0].output; + vscode.window.showErrorMessage( + `Failed to unzip the uploaded file on the server. API response: ${apiError}`, + ); + return; + } + + progress.report({ increment: 70 }); + + // Reload insight classes + try { + params = new URLSearchParams(); + params.append( + "expression", + `ReloadInsightClasses('${projectId}');`, + ); + params.append("insightId", insightId); + + response = await axios.post( + `${SEMOSS_URL}/Monolith/api/engine/runPixel`, + params, + { headers }, + ); + } catch (error) { + vscode.window.showErrorMessage( + `Failed to reload insight classes: ${getErrorMessage(error)}`, + ); + return; + } + + if (!response.data.pixelReturn[0].output) { + vscode.window.showErrorMessage( + "Failed to reload insight classes", + ); + return; + } + + progress.report({ increment: 80 }); + + // Set project portal + try { + params = new URLSearchParams(); + params.append("projectId", projectId); + params.append("hasPortal", true); + + response = await axios.post( + `${SEMOSS_URL}/Monolith/api/auth/project/setProjectPortal`, + params, + { headers }, + ); + } catch (error) { + vscode.window.showErrorMessage( + `Failed to set project portal: ${getErrorMessage(error)}`, + ); + return; + } + + if (!response.data) { + vscode.window.showErrorMessage("Failed to set project portal"); + return; + } + + progress.report({ increment: 90 }); + + // Publish project + try { + params = new URLSearchParams(); + params.append( + "expression", + `PublishProject('${projectId}', release=true);`, + ); + params.append("insightId", insightId); + + response = await axios.post( + `${SEMOSS_URL}/Monolith/api/engine/runPixel`, + params, + { headers }, + ); + } catch (error) { + vscode.window.showErrorMessage( + `Failed to publish project: ${getErrorMessage(error)}`, + ); + return; + } + + progress.report({ increment: 100 }); + + if ( + response.data.pixelReturn[0].additionalOutput[0] + .operationType[0] !== "SUCCESS" + ) { + vscode.window.showErrorMessage("Failed to publish project"); + return; + } + + vscode.window.showInformationMessage( + "Project deployed successfully!", + ); + }, + ); } module.exports = { - setDeployConfig, - deployProject + setDeployConfig, + deployProject, }; diff --git a/packages/vscode-extension/src/utils/githubAssets.js b/packages/vscode-extension/src/utils/githubAssets.js index 76175b8d19..dd0bb85f62 100644 --- a/packages/vscode-extension/src/utils/githubAssets.js +++ b/packages/vscode-extension/src/utils/githubAssets.js @@ -1,10 +1,10 @@ -import * as vscode from 'vscode'; -import path from 'path'; -import fs from 'fs'; -import https from 'https'; -import axios from 'axios'; -import ncp from 'ncp'; -import StreamZip from 'node-stream-zip'; +import axios from "axios"; +import fs from "fs"; +import https from "https"; +import ncp from "ncp"; +import StreamZip from "node-stream-zip"; +import path from "path"; +import * as vscode from "vscode"; /** * Downloads and extracts assets from a GitHub repository @@ -18,291 +18,323 @@ import StreamZip from 'node-stream-zip'; * @returns {Promise} - True if successful, false otherwise */ export async function processGithubAssets( - githubLink, - downloadsDir, - appName, - unzipDir, - isPrivateRepo = false, - accessToken = '' + githubLink, + downloadsDir, + appName, + unzipDir, + isPrivateRepo = false, + accessToken = "", ) { - if (!githubLink) return false; - - let zipPath = ''; - let extractPath = ''; - - try { - // Parse GitHub link - handles URLs with or without protocol - const match = githubLink.match( - /(?:https?:\/\/)?(?:www\.)?github\.com\/([^\/]+)\/([^\/]+)(?:\/tree\/([^\/]+)\/(.+))?/ - ); - if (!match) { - throw new Error( - 'Invalid GitHub link format. Expected format: github.com/user/repo' - ); - } - - const owner = match[1]; - const repo = match[2]; - const branch = match[3] || 'main'; - const folderPath = match[4] || ''; - - // Get default branch if not specified - let usedBranch = branch; - if (!match[3]) { - try { - const apiUrl = `https://api.github.com/repos/${owner}/${repo}`; - const headers = { 'User-Agent': 'node.js' }; - - // Add authorization header for private repositories OR if we have a token - if ((isPrivateRepo && accessToken) || (accessToken && accessToken.startsWith('ghp_'))) { - headers['Authorization'] = `token ${accessToken}`; - } - - const res = await axios.get(apiUrl, { headers }); - usedBranch = res.data.default_branch; - } catch (apiError) { - if (apiError.response && apiError.response.status === 404) { - throw new Error(`Repository not found: ${owner}/${repo}. Please check the URL and access permissions.`); - } else if (apiError.response && apiError.response.status === 401) { - throw new Error(`Unauthorized access to ${owner}/${repo}. Please check your access token.`); - } else { - // If API call fails, try with default branch - usedBranch = 'main'; - vscode.window.showWarningMessage(`Could not fetch repository info, using default branch: ${usedBranch}`); - } - } - } - - // For private repositories, use the GitHub API zipball URL instead of the public archive URL - let zipUrl; - const shouldUsePrivateUrl = Boolean(accessToken); - - if (shouldUsePrivateUrl) { - // Use the same format as your working PowerShell command - zipUrl = `https://api.github.com/repos/${owner}/${repo}/zipball/${usedBranch}`; - } else { - zipUrl = `https://github.com/${owner}/${repo}/archive/refs/heads/${usedBranch}.zip`; - } - fs.mkdirSync(downloadsDir, { recursive: true }); - zipPath = path.join(downloadsDir, `${appName}_github.zip`); - extractPath = path.join( - downloadsDir, - `${appName}_github_unzipped_${Date.now()}` - ); - - vscode.window.showInformationMessage( - `Downloading ${isPrivateRepo ? 'private' : 'public'} repository from GitHub...` - ); - - // Download GitHub repo - Always use downloadPrivateRepo for private repos - // Temporary workaround: If we have an access token but isPrivateRepo is false, force private repo logic - const shouldUsePrivateLogic = (isPrivateRepo && accessToken) || (!isPrivateRepo && accessToken && accessToken.startsWith('ghp_')); - - if (shouldUsePrivateLogic) { - await downloadPrivateRepo(zipUrl, zipPath, accessToken); - } else { - await downloadZipWithRedirect(zipUrl, zipPath, null); - } - - // Verify the download was successful before proceeding - if (!fs.existsSync(zipPath)) { - throw new Error('Repository download failed: ZIP file was not created'); - } - - const stats = fs.statSync(zipPath); - if (stats.size === 0) { - throw new Error('Repository download failed: ZIP file is empty'); - } - - vscode.window.showInformationMessage(`Repository downloaded successfully. File size: ${stats.size} bytes`); - - - // Unzip GitHub repo using node-stream-zip - const zip = new StreamZip.async({ file: zipPath }); - await zip.extract(null, extractPath); // Extract all files - await zip.close(); - - // Find the extracted top-level folder - const [topFolder] = fs.readdirSync(extractPath); - let finalDir = path.join(extractPath, topFolder); - - // If a folderPath is specified, use that subfolder - if (folderPath) { - finalDir = path.join(finalDir, folderPath); - } - - // Check if finalDir exists and is a directory - if (!fs.existsSync(finalDir) || !fs.lstatSync(finalDir).isDirectory()) { - throw new Error( - `The specified path (${folderPath || 'repository root'}) does not exist in the repo.` - ); - } - - // Copy assets to the app - const assetsDir = path.join(unzipDir, 'assets'); - - // Remove existing assets directory if it exists - if (fs.existsSync(assetsDir)) { - fs.rmSync(assetsDir, { recursive: true, force: true }); - } - - // Create assets directory - fs.mkdirSync(assetsDir, { recursive: true }); - - await new Promise((resolve, reject) => { - fs.readdir(finalDir, (err, items) => { - if (err) return reject(err); - let pending = items.length; - if (!pending) return resolve(); - items.forEach((item) => { - const srcPath = path.join(finalDir, item); - const destPath = path.join(assetsDir, item); - fs.stat(srcPath, (err, stat) => { - if (err) return reject(err); - if (stat.isDirectory()) { - ncp(srcPath, destPath, (err) => { - if (err) return reject(err); - if (!--pending) resolve(); - }); - } else { - fs.copyFile(srcPath, destPath, (err) => { - if (err) return reject(err); - if (!--pending) resolve(); - }); - } - }); - }); - }); - }); - - vscode.window.showInformationMessage( - `Successfully copied assets from GitHub repository.` - ); - - // Clean up: delete the zip file and extracted folder - try { - if (fs.existsSync(zipPath)) { - fs.unlinkSync(zipPath); - vscode.window.showInformationMessage( - `Deleted temporary GitHub zip file.` - ); - } - - if (fs.existsSync(extractPath)) { - fs.rmSync(extractPath, { recursive: true, force: true }); - vscode.window.showInformationMessage( - `Deleted temporary GitHub extracted folder.` - ); - } - } catch (cleanupErr) { - vscode.window.showWarningMessage( - `Warning: Failed to clean up temporary files: ${cleanupErr.message}` - ); - // Continue anyway since the assets are already copied - } - - return true; - } catch (err) { - vscode.window.showErrorMessage( - `Error processing GitHub assets: ${err.message}` - ); - - // Attempt to clean up even on error - try { - if (zipPath && fs.existsSync(zipPath)) { - fs.unlinkSync(zipPath); - } - - if (extractPath && fs.existsSync(extractPath)) { - fs.rmSync(extractPath, { recursive: true, force: true }); - } - } catch (cleanupErr) { - // Just log, don't throw additional errors during cleanup - console.error('Error during cleanup:', cleanupErr); - } - - return false; - } + if (!githubLink) return false; + + let zipPath = ""; + let extractPath = ""; + + try { + // Parse GitHub link - handles URLs with or without protocol + const match = githubLink.match( + /(?:https?:\/\/)?(?:www\.)?github\.com\/([^/]+)\/([^/]+)(?:\/tree\/([^/]+)\/(.+))?/, + ); + if (!match) { + throw new Error( + "Invalid GitHub link format. Expected format: github.com/user/repo", + ); + } + + const owner = match[1]; + const repo = match[2]; + const branch = match[3] || "main"; + const folderPath = match[4] || ""; + + // Get default branch if not specified + let usedBranch = branch; + if (!match[3]) { + try { + const apiUrl = `https://api.github.com/repos/${owner}/${repo}`; + const headers = { "User-Agent": "node.js" }; + + // Add authorization header for private repositories OR if we have a token + if ( + (isPrivateRepo && accessToken) || + (accessToken && accessToken.startsWith("ghp_")) + ) { + headers["Authorization"] = `token ${accessToken}`; + } + + const res = await axios.get(apiUrl, { headers }); + usedBranch = res.data.default_branch; + } catch (apiError) { + if (apiError.response && apiError.response.status === 404) { + throw new Error( + `Repository not found: ${owner}/${repo}. Please check the URL and access permissions.`, + ); + } else if ( + apiError.response && + apiError.response.status === 401 + ) { + throw new Error( + `Unauthorized access to ${owner}/${repo}. Please check your access token.`, + ); + } else { + // If API call fails, try with default branch + usedBranch = "main"; + vscode.window.showWarningMessage( + `Could not fetch repository info, using default branch: ${usedBranch}`, + ); + } + } + } + + // For private repositories, use the GitHub API zipball URL instead of the public archive URL + let zipUrl; + const shouldUsePrivateUrl = Boolean(accessToken); + + if (shouldUsePrivateUrl) { + // Use the same format as your working PowerShell command + zipUrl = `https://api.github.com/repos/${owner}/${repo}/zipball/${usedBranch}`; + } else { + zipUrl = `https://github.com/${owner}/${repo}/archive/refs/heads/${usedBranch}.zip`; + } + fs.mkdirSync(downloadsDir, { recursive: true }); + zipPath = path.join(downloadsDir, `${appName}_github.zip`); + extractPath = path.join( + downloadsDir, + `${appName}_github_unzipped_${Date.now()}`, + ); + + vscode.window.showInformationMessage( + `Downloading ${isPrivateRepo ? "private" : "public"} repository from GitHub...`, + ); + + // Download GitHub repo - Always use downloadPrivateRepo for private repos + // Temporary workaround: If we have an access token but isPrivateRepo is false, force private repo logic + const shouldUsePrivateLogic = + (isPrivateRepo && accessToken) || + (!isPrivateRepo && accessToken && accessToken.startsWith("ghp_")); + + if (shouldUsePrivateLogic) { + await downloadPrivateRepo(zipUrl, zipPath, accessToken); + } else { + await downloadZipWithRedirect(zipUrl, zipPath, null); + } + + // Verify the download was successful before proceeding + if (!fs.existsSync(zipPath)) { + throw new Error( + "Repository download failed: ZIP file was not created", + ); + } + + const stats = fs.statSync(zipPath); + if (stats.size === 0) { + throw new Error("Repository download failed: ZIP file is empty"); + } + + vscode.window.showInformationMessage( + `Repository downloaded successfully. File size: ${stats.size} bytes`, + ); + + // Unzip GitHub repo using node-stream-zip + const zip = new StreamZip.async({ file: zipPath }); + await zip.extract(null, extractPath); // Extract all files + await zip.close(); + + // Find the extracted top-level folder + const [topFolder] = fs.readdirSync(extractPath); + let finalDir = path.join(extractPath, topFolder); + + // If a folderPath is specified, use that subfolder + if (folderPath) { + finalDir = path.join(finalDir, folderPath); + } + + // Check if finalDir exists and is a directory + if (!fs.existsSync(finalDir) || !fs.lstatSync(finalDir).isDirectory()) { + throw new Error( + `The specified path (${folderPath || "repository root"}) does not exist in the repo.`, + ); + } + + // Copy assets to the app + const assetsDir = path.join(unzipDir, "assets"); + + // Remove existing assets directory if it exists + if (fs.existsSync(assetsDir)) { + fs.rmSync(assetsDir, { recursive: true, force: true }); + } + + // Create assets directory + fs.mkdirSync(assetsDir, { recursive: true }); + + await new Promise((resolve, reject) => { + fs.readdir(finalDir, (err, items) => { + if (err) return reject(err); + let pending = items.length; + if (!pending) return resolve(); + items.forEach((item) => { + const srcPath = path.join(finalDir, item); + const destPath = path.join(assetsDir, item); + fs.stat(srcPath, (err, stat) => { + if (err) return reject(err); + if (stat.isDirectory()) { + ncp(srcPath, destPath, (err) => { + if (err) return reject(err); + if (!--pending) resolve(); + }); + } else { + fs.copyFile(srcPath, destPath, (err) => { + if (err) return reject(err); + if (!--pending) resolve(); + }); + } + }); + }); + }); + }); + + vscode.window.showInformationMessage( + `Successfully copied assets from GitHub repository.`, + ); + + // Clean up: delete the zip file and extracted folder + try { + if (fs.existsSync(zipPath)) { + fs.unlinkSync(zipPath); + vscode.window.showInformationMessage( + `Deleted temporary GitHub zip file.`, + ); + } + + if (fs.existsSync(extractPath)) { + fs.rmSync(extractPath, { recursive: true, force: true }); + vscode.window.showInformationMessage( + `Deleted temporary GitHub extracted folder.`, + ); + } + } catch (cleanupErr) { + vscode.window.showWarningMessage( + `Warning: Failed to clean up temporary files: ${cleanupErr.message}`, + ); + // Continue anyway since the assets are already copied + } + + return true; + } catch (err) { + vscode.window.showErrorMessage( + `Error processing GitHub assets: ${err.message}`, + ); + + // Attempt to clean up even on error + try { + if (zipPath && fs.existsSync(zipPath)) { + fs.unlinkSync(zipPath); + } + + if (extractPath && fs.existsSync(extractPath)) { + fs.rmSync(extractPath, { recursive: true, force: true }); + } + } catch (cleanupErr) { + // Just log, don't throw additional errors during cleanup + console.error("Error during cleanup:", cleanupErr); + } + + return false; + } } // Helper to download private repositories using axios const downloadPrivateRepo = async (url, dest, accessToken) => { - try { - const response = await axios({ - method: 'GET', - url: url, - headers: { - 'Authorization': `token ${accessToken}`, - 'User-Agent': 'node.js' - }, - responseType: 'stream', - maxRedirects: 5, - timeout: 30000 - }); - - const writer = fs.createWriteStream(dest); - response.data.pipe(writer); - - return new Promise((resolve, reject) => { - writer.on('finish', () => { - resolve(); - }); - writer.on('error', reject); - response.data.on('error', reject); - }); - } catch (error) { - const status = error.response && error.response.status ? error.response.status : 'unknown'; - const statusText = error.response && error.response.statusText ? error.response.statusText : error.message; - vscode.window.showErrorMessage(`Download failed - Status: ${status}, Message: ${statusText}`); - throw new Error(`Failed to download private repository: ${status} - ${statusText}`); - } + try { + const response = await axios({ + method: "GET", + url: url, + headers: { + Authorization: `token ${accessToken}`, + "User-Agent": "node.js", + }, + responseType: "stream", + maxRedirects: 5, + timeout: 30000, + }); + + const writer = fs.createWriteStream(dest); + response.data.pipe(writer); + + return new Promise((resolve, reject) => { + writer.on("finish", () => { + resolve(); + }); + writer.on("error", reject); + response.data.on("error", reject); + }); + } catch (error) { + const status = + error.response && error.response.status + ? error.response.status + : "unknown"; + const statusText = + error.response && error.response.statusText + ? error.response.statusText + : error.message; + vscode.window.showErrorMessage( + `Download failed - Status: ${status}, Message: ${statusText}`, + ); + throw new Error( + `Failed to download private repository: ${status} - ${statusText}`, + ); + } }; // Helper to follow redirects const downloadZipWithRedirect = (url, dest, accessToken = null) => { - return new Promise((resolve, reject) => { - const headers = {}; - - // Add authorization header for private repositories - if (accessToken) { - headers['Authorization'] = `token ${accessToken}`; - headers['User-Agent'] = 'node.js'; - } - - https - .get(url, { headers }, (res) => { - if ([301, 302, 303, 307, 308].includes(res.statusCode) && res.headers.location) { - // For redirects, preserve the authorization header if present - https - .get(res.headers.location, { headers }, (res2) => { - if (res2.statusCode !== 200) { - reject( - new Error( - `Failed to download repo zip: ${res2.statusCode}` - ) - ); - return; - } - const file = fs.createWriteStream(dest); - res2.pipe(file); - file.on('finish', () => file.close(resolve)); - file.on('error', reject); - }) - .on('error', reject); - } else if (res.statusCode === 200) { - const file = fs.createWriteStream(dest); - res.pipe(file); - file.on('finish', () => file.close(resolve)); - file.on('error', reject); - } else { - vscode.window.showErrorMessage(`Download failed with status: ${res.statusCode} for URL: ${url}`); - reject( - new Error( - `Failed to download repo zip: ${res.statusCode}` - ) - ); - } - }) - .on('error', reject); - }); + return new Promise((resolve, reject) => { + const headers = {}; + + // Add authorization header for private repositories + if (accessToken) { + headers["Authorization"] = `token ${accessToken}`; + headers["User-Agent"] = "node.js"; + } + + https + .get(url, { headers }, (res) => { + if ( + [301, 302, 303, 307, 308].includes(res.statusCode) && + res.headers.location + ) { + // For redirects, preserve the authorization header if present + https + .get(res.headers.location, { headers }, (res2) => { + if (res2.statusCode !== 200) { + reject( + new Error( + `Failed to download repo zip: ${res2.statusCode}`, + ), + ); + return; + } + const file = fs.createWriteStream(dest); + res2.pipe(file); + file.on("finish", () => file.close(resolve)); + file.on("error", reject); + }) + .on("error", reject); + } else if (res.statusCode === 200) { + const file = fs.createWriteStream(dest); + res.pipe(file); + file.on("finish", () => file.close(resolve)); + file.on("error", reject); + } else { + vscode.window.showErrorMessage( + `Download failed with status: ${res.statusCode} for URL: ${url}`, + ); + reject( + new Error( + `Failed to download repo zip: ${res.statusCode}`, + ), + ); + } + }) + .on("error", reject); + }); }; diff --git a/packages/vscode-extension/src/utils/projectUtils.js b/packages/vscode-extension/src/utils/projectUtils.js index 7e7355ee50..8be2314845 100644 --- a/packages/vscode-extension/src/utils/projectUtils.js +++ b/packages/vscode-extension/src/utils/projectUtils.js @@ -1,5 +1,5 @@ import fs from "fs"; -import path from 'path'; +import path from "path"; let assetsFolderPath = ""; let outputFilePath = ""; @@ -9,9 +9,12 @@ let outputFilePath = ""; * @param {vscode.Uri} uri - The URI from the context menu */ export function setFolderPaths(uri) { - assetsFolderPath = uri.fsPath.replace(/\\client|\/client|\\py|\/py|\\portals|\/portals/g, ""); - const projectName = path.basename(assetsFolderPath); - outputFilePath = path.join(assetsFolderPath, `${projectName}.zip`); + assetsFolderPath = uri.fsPath.replace( + /\\client|\/client|\\py|\/py|\\portals|\/portals/g, + "", + ); + const projectName = path.basename(assetsFolderPath); + outputFilePath = path.join(assetsFolderPath, `${projectName}.zip`); } /** @@ -19,22 +22,32 @@ export function setFolderPaths(uri) { * @returns {string} The project ID */ export function getProjectId() { - const projectFolderPath = assetsFolderPath.replace(/\\assets|\/assets/g, ""); - const smssFile = fs.readdirSync(projectFolderPath).find(file => file.endsWith('.smss')); - if (!smssFile) { - throw new Error(`No .smss file found in project folder: ${projectFolderPath}`); - } - const smssContent = fs.readFileSync(path.join(projectFolderPath, smssFile), 'utf8'); - const projectLines = smssContent.split('\n'); + const projectFolderPath = assetsFolderPath.replace( + /\\assets|\/assets/g, + "", + ); + const smssFile = fs + .readdirSync(projectFolderPath) + .find((file) => file.endsWith(".smss")); + if (!smssFile) { + throw new Error( + `No .smss file found in project folder: ${projectFolderPath}`, + ); + } + const smssContent = fs.readFileSync( + path.join(projectFolderPath, smssFile), + "utf8", + ); + const projectLines = smssContent.split("\n"); - let projectId = ""; - projectLines.forEach((line) => { - if (line.startsWith('PROJECT\t')) { - projectId = line.split('\t')[1]; - } - }); + let projectId = ""; + projectLines.forEach((line) => { + if (line.startsWith("PROJECT\t")) { + projectId = line.split("\t")[1]; + } + }); - return projectId; + return projectId; } /** @@ -42,7 +55,7 @@ export function getProjectId() { * @returns {string} The assets folder path */ export function getAssetsFolderPath() { - return assetsFolderPath; + return assetsFolderPath; } /** @@ -50,5 +63,5 @@ export function getAssetsFolderPath() { * @returns {string} The output file path */ export function getOutputFilePath() { - return outputFilePath; + return outputFilePath; } diff --git a/packages/vscode-extension/src/utils/secrets.js b/packages/vscode-extension/src/utils/secrets.js index 38891b2aad..24b4259308 100644 --- a/packages/vscode-extension/src/utils/secrets.js +++ b/packages/vscode-extension/src/utils/secrets.js @@ -1,5 +1,5 @@ import * as vscode from "vscode"; -import { updateStatusBar } from './statusBar.js'; +import { updateStatusBar } from "./statusBar.js"; /** * Get user input through VS Code input box @@ -7,12 +7,12 @@ import { updateStatusBar } from './statusBar.js'; * @param {string} placeholder - Placeholder text for the input box * @returns {Promise} The user input */ -export async function getUserInput(prompt, placeholder = '') { - return await vscode.window.showInputBox({ - prompt, - ignoreFocusOut: true, - placeHolder: placeholder - }); +export async function getUserInput(prompt, placeholder = "") { + return await vscode.window.showInputBox({ + prompt, + ignoreFocusOut: true, + placeHolder: placeholder, + }); } /** @@ -21,12 +21,13 @@ export async function getUserInput(prompt, placeholder = '') { * @returns {Promise} Object containing all stored instances */ export async function getStoredInstances(context) { - const instancesJson = await context.secrets.get('SEMOSS_INSTANCES') || '{}'; - try { - return JSON.parse(instancesJson); - } catch (error) { - return {}; - } + const instancesJson = + (await context.secrets.get("SEMOSS_INSTANCES")) || "{}"; + try { + return JSON.parse(instancesJson); + } catch (error) { + return {}; + } } /** @@ -36,9 +37,9 @@ export async function getStoredInstances(context) { * @param {Object} instanceData - The instance data */ export async function storeInstance(context, alias, instanceData) { - const instances = await getStoredInstances(context); - instances[alias] = instanceData; - await context.secrets.store('SEMOSS_INSTANCES', JSON.stringify(instances)); + const instances = await getStoredInstances(context); + instances[alias] = instanceData; + await context.secrets.store("SEMOSS_INSTANCES", JSON.stringify(instances)); } /** @@ -46,68 +47,70 @@ export async function storeInstance(context, alias, instanceData) { * @param {vscode.ExtensionContext} context - The extension context */ export async function storeSecrets(context) { - const instances = await getStoredInstances(context); - const existingAliases = Object.keys(instances); - - // Show existing instances if any - if (existingAliases.length > 0) { - const message = `Existing instances: ${existingAliases.join(', ')}`; - vscode.window.showInformationMessage(message); - } - - const alias = await getUserInput( - 'Enter an alias for this Semoss instance:', - 'e.g., Production, Development, Staging' - ); - - if (!alias) { - vscode.window.showErrorMessage('Alias is required'); - return; - } - - // Check if alias already exists - if (instances[alias]) { - const overwrite = await vscode.window.showQuickPick(['Yes', 'No'], { - placeHolder: `Instance "${alias}" already exists. Overwrite?` - }); - - if (overwrite !== 'Yes') { - return; - } - } - - const semossUrl = await getUserInput( - 'Enter Semoss Instance URL (Before /SemossWeb):', - 'https://your-semoss-instance.com' - ); - const accessKey = await getUserInput( - 'Enter Access Key:', - 'Your access key' - ); - const privateKey = await getUserInput( - 'Enter Private Key:', - 'Your private key' - ); - - if (!semossUrl || !accessKey || !privateKey) { - vscode.window.showErrorMessage('All fields are required'); - return; - } - - // Store the instance - await storeInstance(context, alias, { - semossUrl, - accessKey, - privateKey - }); - - // Set as current instance - await context.secrets.store('CURRENT_INSTANCE_ALIAS', alias); - - // Update status bar - await updateStatusBar(context); - - vscode.window.showInformationMessage(`Instance "${alias}" saved successfully!`); + const instances = await getStoredInstances(context); + const existingAliases = Object.keys(instances); + + // Show existing instances if any + if (existingAliases.length > 0) { + const message = `Existing instances: ${existingAliases.join(", ")}`; + vscode.window.showInformationMessage(message); + } + + const alias = await getUserInput( + "Enter an alias for this Semoss instance:", + "e.g., Production, Development, Staging", + ); + + if (!alias) { + vscode.window.showErrorMessage("Alias is required"); + return; + } + + // Check if alias already exists + if (instances[alias]) { + const overwrite = await vscode.window.showQuickPick(["Yes", "No"], { + placeHolder: `Instance "${alias}" already exists. Overwrite?`, + }); + + if (overwrite !== "Yes") { + return; + } + } + + const semossUrl = await getUserInput( + "Enter Semoss Instance URL (Before /SemossWeb):", + "https://your-semoss-instance.com", + ); + const accessKey = await getUserInput( + "Enter Access Key:", + "Your access key", + ); + const privateKey = await getUserInput( + "Enter Private Key:", + "Your private key", + ); + + if (!semossUrl || !accessKey || !privateKey) { + vscode.window.showErrorMessage("All fields are required"); + return; + } + + // Store the instance + await storeInstance(context, alias, { + semossUrl, + accessKey, + privateKey, + }); + + // Set as current instance + await context.secrets.store("CURRENT_INSTANCE_ALIAS", alias); + + // Update status bar + await updateStatusBar(context); + + vscode.window.showInformationMessage( + `Instance "${alias}" saved successfully!`, + ); } /** @@ -116,32 +119,36 @@ export async function storeSecrets(context) { * @returns {Promise} True if an instance was selected */ export async function selectInstance(context) { - const instances = await getStoredInstances(context); - const aliases = Object.keys(instances); - - if (aliases.length === 0) { - vscode.window.showWarningMessage('No stored instances found. Please authorize a new instance first.'); - return false; - } - - const items = aliases.map(alias => ({ - label: alias, - description: instances[alias].semossUrl, - detail: `Access Key: ${instances[alias].accessKey.substring(0, 8)}...` - })); - - const selected = await vscode.window.showQuickPick(items, { - placeHolder: 'Select a Semoss instance' - }); - - if (selected) { - await context.secrets.store('CURRENT_INSTANCE_ALIAS', selected.label); - await updateStatusBar(context); - vscode.window.showInformationMessage(`Switched to instance: ${selected.label}`); - return true; - } - - return false; + const instances = await getStoredInstances(context); + const aliases = Object.keys(instances); + + if (aliases.length === 0) { + vscode.window.showWarningMessage( + "No stored instances found. Please authorize a new instance first.", + ); + return false; + } + + const items = aliases.map((alias) => ({ + label: alias, + description: instances[alias].semossUrl, + detail: `Access Key: ${instances[alias].accessKey.substring(0, 8)}...`, + })); + + const selected = await vscode.window.showQuickPick(items, { + placeHolder: "Select a Semoss instance", + }); + + if (selected) { + await context.secrets.store("CURRENT_INSTANCE_ALIAS", selected.label); + await updateStatusBar(context); + vscode.window.showInformationMessage( + `Switched to instance: ${selected.label}`, + ); + return true; + } + + return false; } /** @@ -150,25 +157,25 @@ export async function selectInstance(context) { * @returns {Promise<{accessKey: string, privateKey: string, semossUrl: string, alias: string} | null>} The current instance secrets */ export async function getCurrentInstance(context) { - const currentAlias = await context.secrets.get('CURRENT_INSTANCE_ALIAS'); + const currentAlias = await context.secrets.get("CURRENT_INSTANCE_ALIAS"); - if (!currentAlias) { - return null; - } + if (!currentAlias) { + return null; + } - const instances = await getStoredInstances(context); - const instance = instances[currentAlias]; + const instances = await getStoredInstances(context); + const instance = instances[currentAlias]; - if (!instance) { - return null; - } + if (!instance) { + return null; + } - return { - alias: currentAlias, - accessKey: instance.accessKey, - privateKey: instance.privateKey, - semossUrl: instance.semossUrl - }; + return { + alias: currentAlias, + accessKey: instance.accessKey, + privateKey: instance.privateKey, + semossUrl: instance.semossUrl, + }; } /** @@ -177,35 +184,39 @@ export async function getCurrentInstance(context) { * @returns {Promise<{accessKey: string, privateKey: string, semossUrl: string, alias: string} | null>} The secrets */ export async function getSecrets(context) { - // First try to get current instance - const currentInstance = await getCurrentInstance(context); - if (currentInstance) { - return currentInstance; - } - - // Fallback to old storage method for backward compatibility - const accessKey = await context.secrets.get('ACCESS_KEY'); - const privateKey = await context.secrets.get('PRIVATE_KEY'); - const semossUrl = await context.secrets.get('SEMOSS_URL'); - - if (accessKey && privateKey && semossUrl) { - // Migrate old storage to new format - const alias = 'Default'; - await storeInstance(context, alias, { semossUrl, accessKey, privateKey }); - await context.secrets.store('CURRENT_INSTANCE_ALIAS', alias); - - // Update status bar after migration - await updateStatusBar(context); - - // Clean up old storage - await context.secrets.delete('ACCESS_KEY'); - await context.secrets.delete('PRIVATE_KEY'); - await context.secrets.delete('SEMOSS_URL'); - - return { alias, accessKey, privateKey, semossUrl }; - } - - return null; + // First try to get current instance + const currentInstance = await getCurrentInstance(context); + if (currentInstance) { + return currentInstance; + } + + // Fallback to old storage method for backward compatibility + const accessKey = await context.secrets.get("ACCESS_KEY"); + const privateKey = await context.secrets.get("PRIVATE_KEY"); + const semossUrl = await context.secrets.get("SEMOSS_URL"); + + if (accessKey && privateKey && semossUrl) { + // Migrate old storage to new format + const alias = "Default"; + await storeInstance(context, alias, { + semossUrl, + accessKey, + privateKey, + }); + await context.secrets.store("CURRENT_INSTANCE_ALIAS", alias); + + // Update status bar after migration + await updateStatusBar(context); + + // Clean up old storage + await context.secrets.delete("ACCESS_KEY"); + await context.secrets.delete("PRIVATE_KEY"); + await context.secrets.delete("SEMOSS_URL"); + + return { alias, accessKey, privateKey, semossUrl }; + } + + return null; } /** @@ -213,42 +224,49 @@ export async function getSecrets(context) { * @param {vscode.ExtensionContext} context - The extension context */ export async function removeInstance(context) { - const instances = await getStoredInstances(context); - const aliases = Object.keys(instances); - - if (aliases.length === 0) { - vscode.window.showWarningMessage('No stored instances found.'); - return; - } - - const items = aliases.map(alias => ({ - label: alias, - description: instances[alias].semossUrl - })); - - const selected = await vscode.window.showQuickPick(items, { - placeHolder: 'Select instance to remove' - }); - - if (selected) { - const confirm = await vscode.window.showQuickPick(['Yes', 'No'], { - placeHolder: `Are you sure you want to remove "${selected.label}"?` - }); - - if (confirm === 'Yes') { - delete instances[selected.label]; - await context.secrets.store('SEMOSS_INSTANCES', JSON.stringify(instances)); - - // If this was the current instance, clear it - const currentAlias = await context.secrets.get('CURRENT_INSTANCE_ALIAS'); - if (currentAlias === selected.label) { - await context.secrets.delete('CURRENT_INSTANCE_ALIAS'); - } - - // Update the status bar to reflect the changes - await updateStatusBar(context); - - vscode.window.showInformationMessage(`Instance "${selected.label}" removed successfully!`); - } - } + const instances = await getStoredInstances(context); + const aliases = Object.keys(instances); + + if (aliases.length === 0) { + vscode.window.showWarningMessage("No stored instances found."); + return; + } + + const items = aliases.map((alias) => ({ + label: alias, + description: instances[alias].semossUrl, + })); + + const selected = await vscode.window.showQuickPick(items, { + placeHolder: "Select instance to remove", + }); + + if (selected) { + const confirm = await vscode.window.showQuickPick(["Yes", "No"], { + placeHolder: `Are you sure you want to remove "${selected.label}"?`, + }); + + if (confirm === "Yes") { + delete instances[selected.label]; + await context.secrets.store( + "SEMOSS_INSTANCES", + JSON.stringify(instances), + ); + + // If this was the current instance, clear it + const currentAlias = await context.secrets.get( + "CURRENT_INSTANCE_ALIAS", + ); + if (currentAlias === selected.label) { + await context.secrets.delete("CURRENT_INSTANCE_ALIAS"); + } + + // Update the status bar to reflect the changes + await updateStatusBar(context); + + vscode.window.showInformationMessage( + `Instance "${selected.label}" removed successfully!`, + ); + } + } } diff --git a/packages/vscode-extension/src/utils/statusBar.js b/packages/vscode-extension/src/utils/statusBar.js index ed075da03f..39e9c56da9 100644 --- a/packages/vscode-extension/src/utils/statusBar.js +++ b/packages/vscode-extension/src/utils/statusBar.js @@ -1,5 +1,5 @@ import * as vscode from "vscode"; -import { getStoredInstances } from './secrets.js'; +import { getStoredInstances } from "./secrets.js"; let statusBarItem; @@ -9,10 +9,13 @@ let statusBarItem; * @returns {vscode.StatusBarItem} The created status bar item */ export function initStatusBar(context) { - statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100); - statusBarItem.command = 'semoss.selectInstance'; // Make it clickable to change instance - context.subscriptions.push(statusBarItem); - return statusBarItem; + statusBarItem = vscode.window.createStatusBarItem( + vscode.StatusBarAlignment.Left, + 100, + ); + statusBarItem.command = "semoss.selectInstance"; // Make it clickable to change instance + context.subscriptions.push(statusBarItem); + return statusBarItem; } /** @@ -20,30 +23,35 @@ export function initStatusBar(context) { * @param {vscode.ExtensionContext} context - The extension context */ export async function updateStatusBar(context) { - if (!statusBarItem) { - statusBarItem = initStatusBar(context); - } + if (!statusBarItem) { + statusBarItem = initStatusBar(context); + } - const currentAlias = await context.secrets.get('CURRENT_INSTANCE_ALIAS'); - const instances = await getStoredInstances(context); + const currentAlias = await context.secrets.get("CURRENT_INSTANCE_ALIAS"); + const instances = await getStoredInstances(context); - // Check if we have any instances at all - const hasInstances = Object.keys(instances).length > 0; + // Check if we have any instances at all + const hasInstances = Object.keys(instances).length > 0; - if (currentAlias && instances[currentAlias]) { - const instance = instances[currentAlias]; - statusBarItem.text = "$(server) Semoss: " + currentAlias; - statusBarItem.tooltip = "Current Semoss Instance: " + currentAlias + " (" + instance.semossUrl + ")"; - statusBarItem.show(); - } else if (hasInstances) { - // We have instances but none selected - statusBarItem.text = "$(server) Semoss: Select Instance"; - statusBarItem.tooltip = "Click to select a Semoss instance"; - statusBarItem.show(); - } else { - // No instances configured - statusBarItem.text = "$(server) Semoss: Not Connected"; - statusBarItem.tooltip = "Click to add a Semoss instance"; - statusBarItem.show(); - } + if (currentAlias && instances[currentAlias]) { + const instance = instances[currentAlias]; + statusBarItem.text = "$(server) Semoss: " + currentAlias; + statusBarItem.tooltip = + "Current Semoss Instance: " + + currentAlias + + " (" + + instance.semossUrl + + ")"; + statusBarItem.show(); + } else if (hasInstances) { + // We have instances but none selected + statusBarItem.text = "$(server) Semoss: Select Instance"; + statusBarItem.tooltip = "Click to select a Semoss instance"; + statusBarItem.show(); + } else { + // No instances configured + statusBarItem.text = "$(server) Semoss: Not Connected"; + statusBarItem.tooltip = "Click to add a Semoss instance"; + statusBarItem.show(); + } } diff --git a/packages/vscode-extension/src/utils/zip.js b/packages/vscode-extension/src/utils/zip.js index 01cf23a9d9..713938947b 100644 --- a/packages/vscode-extension/src/utils/zip.js +++ b/packages/vscode-extension/src/utils/zip.js @@ -19,41 +19,46 @@ const fsReaddir = promisify(fs.readdir); * @param {number} maxDepth - Maximum depth to search (prevent infinite recursion) * @returns {Promise} - Path to the found folder or null if not found */ -async function findFolderRecursive(startPath, folderName, maxDepth = MAX_SEARCH_DEPTH) { - try { - if (maxDepth <= 0) return null; - - const exists = await fsExists(startPath); - if (!exists) return null; - - const files = await fsReaddir(startPath); - - // First check immediate children (faster search for common case) - const directMatch = files.find(file => file === folderName); - if (directMatch) { - return path.join(startPath, directMatch); - } - - // Then search recursively - for (const file of files) { - const filename = path.join(startPath, file); - try { - const stat = await fsLstat(filename); - - if (stat.isDirectory()) { - const found = await findFolderRecursive(filename, folderName, maxDepth - 1); - if (found) return found; - } - } catch (error) { - // Skip inaccessible directories - continue; - } - } - } catch (error) { - console.error(`Error searching directory ${startPath}:`, error); - } - - return null; +async function findFolderRecursive( + startPath, + folderName, + maxDepth = MAX_SEARCH_DEPTH, +) { + try { + if (maxDepth <= 0) return null; + + const exists = await fsExists(startPath); + if (!exists) return null; + + const files = await fsReaddir(startPath); + + // First check immediate children (faster search for common case) + const directMatch = files.find((file) => file === folderName); + if (directMatch) { + return path.join(startPath, directMatch); + } + + // Then search recursively + for (const file of files) { + const filename = path.join(startPath, file); + try { + const stat = await fsLstat(filename); + + if (stat.isDirectory()) { + const found = await findFolderRecursive( + filename, + folderName, + maxDepth - 1, + ); + if (found) return found; + } + } catch (error) {} + } + } catch (error) { + console.error(`Error searching directory ${startPath}:`, error); + } + + return null; } /** @@ -63,106 +68,149 @@ async function findFolderRecursive(startPath, folderName, maxDepth = MAX_SEARCH_ * @returns {Promise} Path to the created zip file */ async function zipProject(baseFolder) { - return vscode.window.withProgress({ - location: vscode.ProgressLocation.Notification, - title: "Zipping Project Folder", - cancellable: false - }, async (progress) => { - try { - progress.report({ increment: 0, message: "Determining project folder..." }); - - // Determine the base folder path - let folderPath = baseFolder; - if (!folderPath) { - const folders = vscode.workspace.workspaceFolders; - if (!folders || folders.length === 0) { - throw new Error('No workspace folder open and no folder path provided.'); - } - folderPath = folders[0].uri.fsPath; - } - - // First, try to find the portals folder - progress.report({ increment: 20, message: "Finding portals folder..." }); - const portalsFolder = await findFolderRecursive(folderPath, 'portals'); - - let folderToZip; - let zipFolderName; - - if (portalsFolder) { - // Use the parent directory of the portals folder - folderToZip = path.dirname(portalsFolder); - zipFolderName = path.basename(folderToZip); - progress.report({ increment: 20, message: `Found portals in ${zipFolderName}` }); - } else { - // Fallback to assets folder if it exists - progress.report({ increment: 20, message: "Looking for assets folder..." }); - const assetsFolder = path.join(folderPath, 'assets'); - - const assetsExists = await fsExists(assetsFolder); - if (assetsExists) { - const stats = await fsLstat(assetsFolder); - if (stats.isDirectory()) { - folderToZip = assetsFolder; - zipFolderName = 'assets'; - progress.report({ increment: 0, message: "Using assets folder" }); - } else { - throw new Error('Assets exists but is not a directory.'); - } - } else { - throw new Error('No portals folder or assets folder found in the project.'); - } - } - - // Output zip in the parent directory with the folder name - const zipFileName = `${zipFolderName}.zip`; - const outputFilePath = path.join(folderPath, zipFileName); - progress.report({ increment: 20, message: `Creating ${zipFileName}...` }); - - // Create zip file - await new Promise((resolve, reject) => { - // Create a file to stream archive data to - const writeStream = fs.createWriteStream(outputFilePath); - const archive = archiver('zip', {}); - - // Handle any errors that occur - archive.on('error', (err) => { - vscode.window.showErrorMessage('Failed to create archive'); - reject(err); - }); - - // Pipe archive data to the file - archive.pipe(writeStream); - - // Append files, excluding unwanted files and directories - archive.glob('**/*', { - cwd: folderToZip, - dot: true, - ignore: ['client/node_modules/**', '.DS_Store', '__MACOSX', '*.zip'] - }); - - // Finalize the archive - archive.finalize(); - - // Listen for all archive data to be written - writeStream.on('finish', () => { - progress.report({ increment: 40, message: "Zip completed!" }); - resolve(outputFilePath); - }); - - writeStream.on('error', (err) => { - vscode.window.showErrorMessage('Failed to write zip file'); - reject(err); - }); - }); - - vscode.window.showInformationMessage(`${zipFolderName} folder zipped as ${zipFileName} successfully!`); - return outputFilePath; - - } catch (error) { - vscode.window.showErrorMessage(`Zip error: ${error.message}`); - throw error; - } - }); + return vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: "Zipping Project Folder", + cancellable: false, + }, + async (progress) => { + try { + progress.report({ + increment: 0, + message: "Determining project folder...", + }); + + // Determine the base folder path + let folderPath = baseFolder; + if (!folderPath) { + const folders = vscode.workspace.workspaceFolders; + if (!folders || folders.length === 0) { + throw new Error( + "No workspace folder open and no folder path provided.", + ); + } + folderPath = folders[0].uri.fsPath; + } + + // First, try to find the portals folder + progress.report({ + increment: 20, + message: "Finding portals folder...", + }); + const portalsFolder = await findFolderRecursive( + folderPath, + "portals", + ); + + let folderToZip; + let zipFolderName; + + if (portalsFolder) { + // Use the parent directory of the portals folder + folderToZip = path.dirname(portalsFolder); + zipFolderName = path.basename(folderToZip); + progress.report({ + increment: 20, + message: `Found portals in ${zipFolderName}`, + }); + } else { + // Fallback to assets folder if it exists + progress.report({ + increment: 20, + message: "Looking for assets folder...", + }); + const assetsFolder = path.join(folderPath, "assets"); + + const assetsExists = await fsExists(assetsFolder); + if (assetsExists) { + const stats = await fsLstat(assetsFolder); + if (stats.isDirectory()) { + folderToZip = assetsFolder; + zipFolderName = "assets"; + progress.report({ + increment: 0, + message: "Using assets folder", + }); + } else { + throw new Error( + "Assets exists but is not a directory.", + ); + } + } else { + throw new Error( + "No portals folder or assets folder found in the project.", + ); + } + } + + // Output zip in the parent directory with the folder name + const zipFileName = `${zipFolderName}.zip`; + const outputFilePath = path.join(folderPath, zipFileName); + progress.report({ + increment: 20, + message: `Creating ${zipFileName}...`, + }); + + // Create zip file + await new Promise((resolve, reject) => { + // Create a file to stream archive data to + const writeStream = fs.createWriteStream(outputFilePath); + const archive = archiver("zip", {}); + + // Handle any errors that occur + archive.on("error", (err) => { + vscode.window.showErrorMessage( + "Failed to create archive", + ); + reject(err); + }); + + // Pipe archive data to the file + archive.pipe(writeStream); + + // Append files, excluding unwanted files and directories + archive.glob("**/*", { + cwd: folderToZip, + dot: true, + ignore: [ + "client/node_modules/**", + ".DS_Store", + "__MACOSX", + "*.zip", + ], + }); + + // Finalize the archive + archive.finalize(); + + // Listen for all archive data to be written + writeStream.on("finish", () => { + progress.report({ + increment: 40, + message: "Zip completed!", + }); + resolve(outputFilePath); + }); + + writeStream.on("error", (err) => { + vscode.window.showErrorMessage( + "Failed to write zip file", + ); + reject(err); + }); + }); + + vscode.window.showInformationMessage( + `${zipFolderName} folder zipped as ${zipFileName} successfully!`, + ); + return outputFilePath; + } catch (error) { + vscode.window.showErrorMessage(`Zip error: ${error.message}`); + throw error; + } + }, + ); } /** @@ -170,6 +218,6 @@ async function zipProject(baseFolder) { * Exported for potential use by other modules */ module.exports = { - zipProject, - findFolderRecursive -}; \ No newline at end of file + zipProject, + findFolderRecursive, +}; diff --git a/packages/vscode-extension/tasks.json b/packages/vscode-extension/tasks.json index f21cb4903f..a73272f6ab 100644 --- a/packages/vscode-extension/tasks.json +++ b/packages/vscode-extension/tasks.json @@ -1,15 +1,15 @@ { - "version": "1.0.0", - "tasks": [ - { - "label": "Link Semoss Instance", - "command": "${input:variableID}" - } - ], - "inputs": [ - { - "id": "variableID", - "type": "type of input variable" - } - ] -} \ No newline at end of file + "version": "1.0.0", + "tasks": [ + { + "label": "Link Semoss Instance", + "command": "${input:variableID}" + } + ], + "inputs": [ + { + "id": "variableID", + "type": "type of input variable" + } + ] +}