diff --git a/graphql.config.yml b/graphql.config.yml index dab28289..f269c6ed 100644 --- a/graphql.config.yml +++ b/graphql.config.yml @@ -3,4 +3,4 @@ documents: '**/*.graphql' extensions: endpoints: Default GraphQL Endpoint: - url: http://localhost:3001/graphql + url: http://localhost:3010/graphql diff --git a/package-lock.json b/package-lock.json index 051afa88..350dbb7f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,12 +9,13 @@ "version": "0.1.0", "dependencies": { "@apollo/client": "^4.0.9", - "@code0-tech/pictor": "^0.0.0-mvp.31", + "@code0-tech/pictor": "^0.0.0-mvp.45", + "date-fns": "^4.1.0", "graphql": "^16.12.0", "graphql-tag": "^2.12.6", - "next": "16.0.7", - "react": "19.2.0", - "react-dom": "19.2.0", + "next": "16.1.5", + "react": "19.2.3", + "react-dom": "19.2.3", "rxjs": "^7.8.2", "sass": "^1.93.3" }, @@ -24,108 +25,14 @@ "@types/react-dom": "^19", "babel-plugin-react-compiler": "^1.0.0", "eslint": "^9", - "eslint-config-next": "16.0.7", + "eslint-config-next": "16.1.5", "typescript": "^5" } }, - "../pictor": { - "name": "@code0-tech/pictor", - "version": "0.0.0", - "extraneous": true, - "dependencies": { - "@code0-tech/definition-reader": "^0.0.16" - }, - "devDependencies": { - "@ariakit/react": "^0.4.17", - "@babel/plugin-proposal-decorators": "^7.28.0", - "@babel/plugin-transform-class-properties": "^7.27.1", - "@code0-tech/sagittarius-graphql-types": "^0.0.0-65144a9920c6a8de3bcf24acdcb8eec4158cef73", - "@dagrejs/dagre": "^1.1.5", - "@mdx-js/react": "^3.1.1", - "@radix-ui/react-checkbox": "^1.3.3", - "@radix-ui/react-dialog": "^1.1.15", - "@radix-ui/react-dropdown-menu": "^2.1.16", - "@radix-ui/react-one-time-password-field": "^0.1.8", - "@radix-ui/react-radio-group": "^1.3.8", - "@radix-ui/react-scroll-area": "^1.2.10", - "@radix-ui/react-tabs": "^1.1.13", - "@radix-ui/react-toggle-group": "^1.1.11", - "@radix-ui/react-tooltip": "^1.2.8", - "@rollup/plugin-commonjs": "^28.0.9", - "@rollup/plugin-node-resolve": "^16.0.3", - "@rollup/plugin-terser": "^0.4.4", - "@rollup/plugin-typescript": "^12.3.0", - "@storybook/addon-a11y": "^10.0.4", - "@storybook/addon-links": "^10.0.4", - "@storybook/addon-onboarding": "^10.0.4", - "@storybook/builder-vite": "^10.0.4", - "@storybook/cli": "^10.0.4", - "@storybook/react": "^10.0.4", - "@storybook/react-vite": "^10.0.4", - "@storybook/test-runner": "^0.24.1", - "@storybook/testing-library": "^0.2.2", - "@tabler/icons-react": "3.35.0", - "@types/jest-image-snapshot": "^6.4.0", - "@types/react": "^19.2.2", - "@vitejs/plugin-react": "^5.1.0", - "@xyflow/react": "^12.9.2", - "axe-playwright": "^2.2.2", - "babel-loader": "^10.0.0", - "babel-plugin-react-compiler": "^19.1.0-rc.3", - "cmdk": "^1.1.1", - "concurrently": "^9.2.1", - "css-loader": "^7.1.2", - "html-webpack-plugin": "^5.6.4", - "identity-obj-proxy": "^3.0.0", - "jest-image-snapshot": "^6.5.1", - "js-md5": "^0.8.3", - "merge-props": "^6.0.0", - "overlap-area": "^1.1.0", - "playwright": "1.55.1", - "react": "^19.2.0", - "react-dom": "^19.2.0", - "react-resizable-panels": "^3.0.6", - "react-zoom-pan-pinch": "^3.7.0", - "rimraf": "^6.1.0", - "sass": "^1.93.3", - "sass-loader": "^16.0.6", - "storybook": "^10.0.4", - "style-loader": "^4.0.0", - "ts-jest": "^29.4.5", - "ts-node": "^10.9.2", - "typescript": "^5.9.3", - "vite": "^7.2.1", - "vite-plugin-dts": "^4.5.4", - "vite-plugin-lib-inject-css": "^2.2.2" - }, - "peerDependencies": { - "@ariakit/react": "^0.4.5", - "@code0-tech/sagittarius-graphql-types": "^0.0.0-65144a9920c6a8de3bcf24acdcb8eec4158cef73", - "@radix-ui/react-checkbox": "^1.3.2", - "@radix-ui/react-dialog": "^1.1.14", - "@radix-ui/react-dropdown-menu": "^2.1.15", - "@radix-ui/react-one-time-password-field": "^0.1.7", - "@radix-ui/react-radio-group": "^1.3.7", - "@radix-ui/react-scroll-area": "^1.2.10", - "@radix-ui/react-tabs": "^1.1.12", - "@radix-ui/react-toggle-group": "^1.1.10", - "@radix-ui/react-tooltip": "^1.2.8", - "@tabler/icons-react": "^3.5.0", - "@xyflow/react": "^12.8.2", - "cmdk": "^1.1.1", - "js-md5": "^0.8.3", - "merge-props": "^6.0.0", - "overlap-area": "^1.1.0", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0", - "react-resizable-panels": "^3.0.3", - "react-zoom-pan-pinch": "^3.6.1" - } - }, "node_modules/@apollo/client": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@apollo/client/-/client-4.0.9.tgz", - "integrity": "sha512-Lh2drMzFE9x5jVS8RKmlGL5SORkvpyUJIT+wTErxDUR2HpWePiBfhhcHHRSlZFiCR866ewCv4euTc4IDF0GWxw==", + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@apollo/client/-/client-4.0.11.tgz", + "integrity": "sha512-jyW5j3DEYnFlYA1Lk9Szd7O/od1DptnbZnj03DQXxuQb+Gnop0w/uQxVRKaU7bPhvVuBnlAtZYPOykArX+xWdg==", "license": "MIT", "workspaces": [ "dist", @@ -397,6 +304,16 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/runtime": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", @@ -446,44 +363,167 @@ } }, "node_modules/@code0-tech/pictor": { - "version": "0.0.0-mvp.31", - "resolved": "https://registry.npmjs.org/@code0-tech/pictor/-/pictor-0.0.0-mvp.31.tgz", - "integrity": "sha512-UIc+6I1coRxm7bDHLMTYRJk9iMOFieGz4ULmve8s0GcJZHXV+njunzbDWhvTzf7UTA3wSj9i038xKqczc6c4ow==", - "dependencies": { - "@radix-ui/react-context-menu": "^2.2.16", - "react-contenteditable": "^3.3.7" - }, + "version": "0.0.0-mvp.45", + "resolved": "https://registry.npmjs.org/@code0-tech/pictor/-/pictor-0.0.0-mvp.45.tgz", + "integrity": "sha512-lCiqOhD+9dZowbnHg+UMJey2yWVVFUk8NRgxxk0DwUUVOXTqbWs+EGMv367tJi6aIrlhnsTlcWnFgbt2CvYY4w==", "peerDependencies": { - "@ariakit/react": "^0.4.5", - "@code0-tech/sagittarius-graphql-types": "0.0.0-a2b1f5e9adf8f52b5a0f235ca9906ac5a699b4fc", - "@radix-ui/react-checkbox": "^1.3.2", - "@radix-ui/react-dialog": "^1.1.14", - "@radix-ui/react-dropdown-menu": "^2.1.15", - "@radix-ui/react-one-time-password-field": "^0.1.7", - "@radix-ui/react-radio-group": "^1.3.7", + "@ariakit/react": "^0.4.17", + "@code0-tech/sagittarius-graphql-types": "0.0.0-703d578a55a3f0f20be3cb6892418f9e04d25716", + "@codemirror/autocomplete": "^6.20.0", + "@codemirror/lang-json": "^6.0.2", + "@codemirror/language": "^6.12.1", + "@codemirror/lint": "^6.9.4", + "@codemirror/state": "^6.5.4", + "@codemirror/view": "^6.39.13", + "@monaco-editor/react": "^4.7.0", + "@radix-ui/react-checkbox": "^1.3.3", + "@radix-ui/react-context-menu": "^2.2.16", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-hover-card": "^1.1.15", + "@radix-ui/react-one-time-password-field": "^0.1.8", + "@radix-ui/react-radio-group": "^1.3.8", "@radix-ui/react-scroll-area": "^1.2.10", - "@radix-ui/react-tabs": "^1.1.12", - "@radix-ui/react-toggle-group": "^1.1.10", + "@radix-ui/react-tabs": "^1.1.13", + "@radix-ui/react-toggle-group": "^1.1.11", "@radix-ui/react-tooltip": "^1.2.8", - "@tabler/icons-react": "^3.5.0", - "@xyflow/react": "^12.8.2", + "@tabler/icons-react": "3.36.1", + "@uiw/codemirror-themes": "^4.25.4", + "@uiw/react-codemirror": "^4.25.4", + "@xyflow/react": "^12.10.0", + "avvvatars-react": "^0.4.2", "cmdk": "^1.1.1", "js-md5": "^0.8.3", + "ldrs": "^1.1.9", "merge-props": "^6.0.0", "overlap-area": "^1.1.0", "react": "^18.0.0 || ^19.0.0", + "react-contenteditable": "^3.3.7", "react-dom": "^18.0.0 || ^19.0.0", - "react-resizable-panels": "^3.0.3 || ^4.0.0", - "react-zoom-pan-pinch": "^3.6.1", + "react-resizable-panels": "^4.3.1", + "react-syntax-highlighter": "^16.1.0", + "react-zoom-pan-pinch": "^3.7.0", "sonner": "^2.0.7" } }, "node_modules/@code0-tech/sagittarius-graphql-types": { - "version": "0.0.0-a2b1f5e9adf8f52b5a0f235ca9906ac5a699b4fc", - "resolved": "https://registry.npmjs.org/@code0-tech/sagittarius-graphql-types/-/sagittarius-graphql-types-0.0.0-a2b1f5e9adf8f52b5a0f235ca9906ac5a699b4fc.tgz", - "integrity": "sha512-LmdOiCHFRiUDXh0Ol89AA3BvN95t9El2GZhhbgXgNmyVYIXJENaZCMCVzAG/W3bhNsGQQARhFNcAGp3kxnxx+Q==", + "version": "0.0.0-703d578a55a3f0f20be3cb6892418f9e04d25716", + "resolved": "https://registry.npmjs.org/@code0-tech/sagittarius-graphql-types/-/sagittarius-graphql-types-0.0.0-703d578a55a3f0f20be3cb6892418f9e04d25716.tgz", + "integrity": "sha512-rPxL8U2Otuo4DYR2ExVhp2wnz7r+jlU70o45WXS6PI89xZ03+T7wGuPcPNJUoB/SGVNl/+5WaqWlCh+HSfhmjA==", "peer": true }, + "node_modules/@codemirror/autocomplete": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.0.tgz", + "integrity": "sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@codemirror/commands": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.2.tgz", + "integrity": "sha512-vvX1fsih9HledO1c9zdotZYUZnE4xV0m6i3m25s5DIfXofuprk6cRcLUZvSk3CASUbwjQX21tOGbkY2BH8TpnQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.4.0", + "@codemirror/view": "^6.27.0", + "@lezer/common": "^1.1.0" + } + }, + "node_modules/@codemirror/lang-json": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.2.tgz", + "integrity": "sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/json": "^1.0.0" + } + }, + "node_modules/@codemirror/language": { + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.1.tgz", + "integrity": "sha512-Fa6xkSiuGKc8XC8Cn96T+TQHYj4ZZ7RdFmXA3i9xe/3hLHfwPZdM+dqfX0Cp0zQklBKhVD8Yzc8LS45rkqcwpQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.23.0", + "@lezer/common": "^1.5.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/lint": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.4.tgz", + "integrity": "sha512-ABc9vJ8DEmvOWuH26P3i8FpMWPQkduD9Rvba5iwb6O3hxASgclm3T3krGo8NASXkHCidz6b++LWlzWIUfEPSWw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.35.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/search": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.6.0.tgz", + "integrity": "sha512-koFuNXcDvyyotWcgOnZGmY7LZqEOXZaaxD/j6n18TCLx2/9HieZJ5H6hs1g8FiRxBD0DNfs0nXn17g872RmYdw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.37.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/state": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.4.tgz", + "integrity": "sha512-8y7xqG/hpB53l25CIoit9/ngxdfoG+fx+V3SHBrinnhOtLvKHRyAJJuHzkWrR4YXXLX8eXBsejgAAxHUOdW1yw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@marijn/find-cluster-break": "^1.0.0" + } + }, + "node_modules/@codemirror/theme-one-dark": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.3.tgz", + "integrity": "sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/highlight": "^1.0.0" + } + }, + "node_modules/@codemirror/view": { + "version": "6.39.14", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.14.tgz", + "integrity": "sha512-WJcvgHm/6Q7dvGT0YFv/6PSkoc36QlR0VCESS6x9tGsnF1lWLmmYxOgX3HH6v8fo6AvSLgpcs+H0Olre6MKXlg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@codemirror/state": "^6.5.0", + "crelt": "^1.0.6", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, "node_modules/@daybrush/utils": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/@daybrush/utils/-/utils-1.13.0.tgz", @@ -492,9 +532,9 @@ "peer": true }, "node_modules/@emnapi/core": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.0.tgz", - "integrity": "sha512-pJdKGq/1iquWYtv1RRSljZklxHCOCAJFJrImO5ZLKPJVJlVUcs8yFwNQlqS0Lo8xT1VAXXTCZocF9n26FWEKsw==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", + "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", "dev": true, "license": "MIT", "optional": true, @@ -504,9 +544,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.0.tgz", - "integrity": "sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", "license": "MIT", "optional": true, "dependencies": { @@ -525,9 +565,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -608,9 +648,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", "dev": true, "license": "MIT", "dependencies": { @@ -620,7 +660,7 @@ "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", + "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, @@ -632,9 +672,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", - "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", "dev": true, "license": "MIT", "engines": { @@ -673,6 +713,7 @@ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", "license": "MIT", + "peer": true, "dependencies": { "@floating-ui/utils": "^0.2.10" } @@ -682,6 +723,7 @@ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", "license": "MIT", + "peer": true, "dependencies": { "@floating-ui/core": "^1.7.3", "@floating-ui/utils": "^0.2.10" @@ -692,6 +734,7 @@ "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", "license": "MIT", + "peer": true, "dependencies": { "@floating-ui/dom": "^1.7.4" }, @@ -704,7 +747,8 @@ "version": "0.2.10", "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@graphql-typed-document-node/core": { "version": "3.2.0", @@ -778,9 +822,9 @@ } }, "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.4.tgz", - "integrity": "sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", "cpu": [ "arm64" ], @@ -796,13 +840,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.3" + "@img/sharp-libvips-darwin-arm64": "1.2.4" } }, "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.4.tgz", - "integrity": "sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", "cpu": [ "x64" ], @@ -818,13 +862,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.3" + "@img/sharp-libvips-darwin-x64": "1.2.4" } }, "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.3.tgz", - "integrity": "sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", "cpu": [ "arm64" ], @@ -838,9 +882,9 @@ } }, "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.3.tgz", - "integrity": "sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", "cpu": [ "x64" ], @@ -854,9 +898,9 @@ } }, "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.3.tgz", - "integrity": "sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", "cpu": [ "arm" ], @@ -870,9 +914,9 @@ } }, "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.3.tgz", - "integrity": "sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", "cpu": [ "arm64" ], @@ -886,9 +930,9 @@ } }, "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.3.tgz", - "integrity": "sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", "cpu": [ "ppc64" ], @@ -901,10 +945,26 @@ "url": "https://opencollective.com/libvips" } }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.3.tgz", - "integrity": "sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", "cpu": [ "s390x" ], @@ -918,9 +978,9 @@ } }, "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.3.tgz", - "integrity": "sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", "cpu": [ "x64" ], @@ -934,9 +994,9 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.3.tgz", - "integrity": "sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", "cpu": [ "arm64" ], @@ -950,9 +1010,9 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.3.tgz", - "integrity": "sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", "cpu": [ "x64" ], @@ -966,9 +1026,9 @@ } }, "node_modules/@img/sharp-linux-arm": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.4.tgz", - "integrity": "sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", "cpu": [ "arm" ], @@ -984,13 +1044,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.3" + "@img/sharp-libvips-linux-arm": "1.2.4" } }, "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.4.tgz", - "integrity": "sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", "cpu": [ "arm64" ], @@ -1006,13 +1066,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.3" + "@img/sharp-libvips-linux-arm64": "1.2.4" } }, "node_modules/@img/sharp-linux-ppc64": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.4.tgz", - "integrity": "sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", "cpu": [ "ppc64" ], @@ -1028,13 +1088,35 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.3" + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" } }, "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.4.tgz", - "integrity": "sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", "cpu": [ "s390x" ], @@ -1050,13 +1132,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.3" + "@img/sharp-libvips-linux-s390x": "1.2.4" } }, "node_modules/@img/sharp-linux-x64": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.4.tgz", - "integrity": "sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", "cpu": [ "x64" ], @@ -1072,13 +1154,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.3" + "@img/sharp-libvips-linux-x64": "1.2.4" } }, "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.4.tgz", - "integrity": "sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", "cpu": [ "arm64" ], @@ -1094,13 +1176,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.3" + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" } }, "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.4.tgz", - "integrity": "sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", "cpu": [ "x64" ], @@ -1116,20 +1198,20 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.3" + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" } }, "node_modules/@img/sharp-wasm32": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.4.tgz", - "integrity": "sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", "cpu": [ "wasm32" ], "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, "dependencies": { - "@emnapi/runtime": "^1.5.0" + "@emnapi/runtime": "^1.7.0" }, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" @@ -1139,9 +1221,9 @@ } }, "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.4.tgz", - "integrity": "sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", "cpu": [ "arm64" ], @@ -1158,9 +1240,9 @@ } }, "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.4.tgz", - "integrity": "sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", "cpu": [ "ia32" ], @@ -1177,9 +1259,9 @@ } }, "node_modules/@img/sharp-win32-x64": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.4.tgz", - "integrity": "sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", "cpu": [ "x64" ], @@ -1245,6 +1327,77 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@lezer/common": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.1.tgz", + "integrity": "sha512-6YRVG9vBkaY7p1IVxL4s44n5nUnaNnGM2/AckNgYOnxTG2kWh1vR8BMxPseWPjRNpb5VtXnMpeYAEAADoRV1Iw==", + "license": "MIT", + "peer": true + }, + "node_modules/@lezer/highlight": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz", + "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@lezer/common": "^1.3.0" + } + }, + "node_modules/@lezer/json": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz", + "integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.8.tgz", + "integrity": "sha512-bPWa0Pgx69ylNlMlPvBPryqeLYQjyJjqPx+Aupm5zydLIF3NE+6MMLT8Yi23Bd9cif9VS00aUebn+6fDIGBcDA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@marijn/find-cluster-break": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", + "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", + "license": "MIT", + "peer": true + }, + "node_modules/@monaco-editor/loader": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.7.0.tgz", + "integrity": "sha512-gIwR1HrJrrx+vfyOhYmCZ0/JcWqG5kbfG7+d3f/C1LXk2EvzAbHSg3MQ5lO2sMlo9izoAZ04shohfKLVT6crVA==", + "license": "MIT", + "peer": true, + "dependencies": { + "state-local": "^1.0.6" + } + }, + "node_modules/@monaco-editor/react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.7.0.tgz", + "integrity": "sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@monaco-editor/loader": "^1.5.0" + }, + "peerDependencies": { + "monaco-editor": ">= 0.25.0 < 1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/@napi-rs/wasm-runtime": { "version": "0.2.12", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", @@ -1259,15 +1412,15 @@ } }, "node_modules/@next/env": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.7.tgz", - "integrity": "sha512-gpaNgUh5nftFKRkRQGnVi5dpcYSKGcZZkQffZ172OrG/XkrnS7UBTQ648YY+8ME92cC4IojpI2LqTC8sTDhAaw==", + "version": "16.1.5", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.5.tgz", + "integrity": "sha512-CRSCPJiSZoi4Pn69RYBDI9R7YK2g59vLexPQFXY0eyw+ILevIenCywzg+DqmlBik9zszEnw2HLFOUlLAcJbL7g==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.0.7.tgz", - "integrity": "sha512-hFrTNZcMEG+k7qxVxZJq3F32Kms130FAhG8lvw2zkKBgAcNOJIxlljNiCjGygvBshvaGBdf88q2CqWtnqezDHA==", + "version": "16.1.5", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.1.5.tgz", + "integrity": "sha512-gUWcEsOl+1W7XakmouClcJ0TNFCkblvDUho31wulbDY9na0C6mGtBTSXGRU5GXJY65GjGj0zNaCD/GaBp888Mg==", "dev": true, "license": "MIT", "dependencies": { @@ -1275,9 +1428,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.7.tgz", - "integrity": "sha512-LlDtCYOEj/rfSnEn/Idi+j1QKHxY9BJFmxx7108A6D8K0SB+bNgfYQATPk/4LqOl4C0Wo3LACg2ie6s7xqMpJg==", + "version": "16.1.5", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.5.tgz", + "integrity": "sha512-eK7Wdm3Hjy/SCL7TevlH0C9chrpeOYWx2iR7guJDaz4zEQKWcS1IMVfMb9UKBFMg1XgzcPTYPIp1Vcpukkjg6Q==", "cpu": [ "arm64" ], @@ -1291,9 +1444,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.7.tgz", - "integrity": "sha512-rtZ7BhnVvO1ICf3QzfW9H3aPz7GhBrnSIMZyr4Qy6boXF0b5E3QLs+cvJmg3PsTCG2M1PBoC+DANUi4wCOKXpA==", + "version": "16.1.5", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.5.tgz", + "integrity": "sha512-foQscSHD1dCuxBmGkbIr6ScAUF6pRoDZP6czajyvmXPAOFNnQUJu2Os1SGELODjKp/ULa4fulnBWoHV3XdPLfA==", "cpu": [ "x64" ], @@ -1307,9 +1460,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.7.tgz", - "integrity": "sha512-mloD5WcPIeIeeZqAIP5c2kdaTa6StwP4/2EGy1mUw8HiexSHGK/jcM7lFuS3u3i2zn+xH9+wXJs6njO7VrAqww==", + "version": "16.1.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.5.tgz", + "integrity": "sha512-qNIb42o3C02ccIeSeKjacF3HXotGsxh/FMk/rSRmCzOVMtoWH88odn2uZqF8RLsSUWHcAqTgYmPD3pZ03L9ZAA==", "cpu": [ "arm64" ], @@ -1323,9 +1476,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.7.tgz", - "integrity": "sha512-+ksWNrZrthisXuo9gd1XnjHRowCbMtl/YgMpbRvFeDEqEBd523YHPWpBuDjomod88U8Xliw5DHhekBC3EOOd9g==", + "version": "16.1.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.5.tgz", + "integrity": "sha512-U+kBxGUY1xMAzDTXmuVMfhaWUZQAwzRaHJ/I6ihtR5SbTVUEaDRiEU9YMjy1obBWpdOBuk1bcm+tsmifYSygfw==", "cpu": [ "arm64" ], @@ -1339,9 +1492,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.7.tgz", - "integrity": "sha512-4WtJU5cRDxpEE44Ana2Xro1284hnyVpBb62lIpU5k85D8xXxatT+rXxBgPkc7C1XwkZMWpK5rXLXTh9PFipWsA==", + "version": "16.1.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.5.tgz", + "integrity": "sha512-gq2UtoCpN7Ke/7tKaU7i/1L7eFLfhMbXjNghSv0MVGF1dmuoaPeEVDvkDuO/9LVa44h5gqpWeJ4mRRznjDv7LA==", "cpu": [ "x64" ], @@ -1355,9 +1508,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.7.tgz", - "integrity": "sha512-HYlhqIP6kBPXalW2dbMTSuB4+8fe+j9juyxwfMwCe9kQPPeiyFn7NMjNfoFOfJ2eXkeQsoUGXg+O2SE3m4Qg2w==", + "version": "16.1.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.5.tgz", + "integrity": "sha512-bQWSE729PbXT6mMklWLf8dotislPle2L70E9q6iwETYEOt092GDn0c+TTNj26AjmeceSsC4ndyGsK5nKqHYXjQ==", "cpu": [ "x64" ], @@ -1371,9 +1524,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.7.tgz", - "integrity": "sha512-EviG+43iOoBRZg9deGauXExjRphhuYmIOJ12b9sAPy0eQ6iwcPxfED2asb/s2/yiLYOdm37kPaiZu8uXSYPs0Q==", + "version": "16.1.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.5.tgz", + "integrity": "sha512-LZli0anutkIllMtTAWZlDqdfvjWX/ch8AFK5WgkNTvaqwlouiD1oHM+WW8RXMiL0+vAkAJyAGEzPPjO+hnrSNQ==", "cpu": [ "arm64" ], @@ -1387,9 +1540,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.7.tgz", - "integrity": "sha512-gniPjy55zp5Eg0896qSrf3yB1dw4F/3s8VK1ephdsZZ129j2n6e1WqCbE2YgcKhW9hPB9TVZENugquWJD5x0ug==", + "version": "16.1.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.5.tgz", + "integrity": "sha512-7is37HJTNQGhjPpQbkKjKEboHYQnCgpVt/4rBrrln0D9nderNxZ8ZWs8w1fAtzUx7wEyYjQ+/13myFgFj6K2Ng==", "cpu": [ "x64" ], @@ -1746,19 +1899,6 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@parcel/watcher/node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "license": "Apache-2.0", - "optional": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/@radix-ui/number": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", @@ -1770,13 +1910,15 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@radix-ui/react-arrow": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", "license": "MIT", + "peer": true, "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, @@ -1831,6 +1973,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", "license": "MIT", + "peer": true, "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", @@ -1857,6 +2000,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -1872,6 +2016,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -1887,6 +2032,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.2.16.tgz", "integrity": "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==", "license": "MIT", + "peer": true, "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", @@ -1952,6 +2098,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -1967,6 +2114,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", "license": "MIT", + "peer": true, "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", @@ -2024,6 +2172,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -2039,6 +2188,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", "license": "MIT", + "peer": true, "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", @@ -2059,11 +2209,44 @@ } } }, + "node_modules/@radix-ui/react-hover-card": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.15.tgz", + "integrity": "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-id": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", "license": "MIT", + "peer": true, "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, @@ -2082,6 +2265,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", "license": "MIT", + "peer": true, "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", @@ -2157,6 +2341,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", "license": "MIT", + "peer": true, "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", @@ -2189,6 +2374,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", "license": "MIT", + "peer": true, "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" @@ -2213,6 +2399,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", "license": "MIT", + "peer": true, "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" @@ -2237,6 +2424,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", + "peer": true, "dependencies": { "@radix-ui/react-slot": "1.2.3" }, @@ -2293,6 +2481,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", "license": "MIT", + "peer": true, "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", @@ -2356,6 +2545,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", + "peer": true, "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, @@ -2496,6 +2686,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -2511,6 +2702,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", "license": "MIT", + "peer": true, "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" @@ -2530,6 +2722,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", "license": "MIT", + "peer": true, "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, @@ -2548,6 +2741,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", "license": "MIT", + "peer": true, "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, @@ -2585,6 +2779,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -2616,6 +2811,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", "license": "MIT", + "peer": true, "dependencies": { "@radix-ui/rect": "1.1.1" }, @@ -2634,6 +2830,7 @@ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", "license": "MIT", + "peer": true, "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, @@ -2675,7 +2872,8 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@rtsao/scc": { "version": "1.1.0", @@ -2794,6 +2992,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -2809,51 +3017,64 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.25", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.25.tgz", - "integrity": "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==", + "version": "20.19.28", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.28.tgz", + "integrity": "sha512-VyKBr25BuFDzBFCK5sUM6ZXiWfqgCTwTAOK8qzGV/m9FCirXYDlmczJ+d5dXBAQALGCdRRdbteKYfJ84NGEusw==", "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" } }, + "node_modules/@types/prismjs": { + "version": "1.26.5", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz", + "integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==", + "license": "MIT", + "peer": true + }, "node_modules/@types/react": { - "version": "19.2.2", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", - "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.8.tgz", + "integrity": "sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==", "devOptional": true, "license": "MIT", "dependencies": { - "csstype": "^3.0.2" + "csstype": "^3.2.2" } }, "node_modules/@types/react-dom": { - "version": "19.2.2", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.2.tgz", - "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.2.0" } }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT", + "peer": true + }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.3.tgz", - "integrity": "sha512-sbaQ27XBUopBkRiuY/P9sWGOWUW4rl8fDoHIUmLpZd8uldsTyB4/Zg6bWTegPoTLnKj9Hqgn3QD6cjPNB32Odw==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.52.0.tgz", + "integrity": "sha512-okqtOgqu2qmZJ5iN4TWlgfF171dZmx2FzdOv2K/ixL2LZWDStL8+JgQerI2sa8eAEfoydG9+0V96m7V+P8yE1Q==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.46.3", - "@typescript-eslint/type-utils": "8.46.3", - "@typescript-eslint/utils": "8.46.3", - "@typescript-eslint/visitor-keys": "8.46.3", - "graphemer": "^1.4.0", - "ignore": "^7.0.0", + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.52.0", + "@typescript-eslint/type-utils": "8.52.0", + "@typescript-eslint/utils": "8.52.0", + "@typescript-eslint/visitor-keys": "8.52.0", + "ignore": "^7.0.5", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.1.0" + "ts-api-utils": "^2.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2863,7 +3084,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.46.3", + "@typescript-eslint/parser": "^8.52.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } @@ -2879,17 +3100,17 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.3.tgz", - "integrity": "sha512-6m1I5RmHBGTnUGS113G04DMu3CpSdxCAU/UvtjNWL4Nuf3MW9tQhiJqRlHzChIkhy6kZSAQmc+I1bcGjE3yNKg==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.52.0.tgz", + "integrity": "sha512-iIACsx8pxRnguSYhHiMn2PvhvfpopO9FXHyn1mG5txZIsAaB6F0KwbFnUQN3KCiG3Jcuad/Cao2FAs1Wp7vAyg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.46.3", - "@typescript-eslint/types": "8.46.3", - "@typescript-eslint/typescript-estree": "8.46.3", - "@typescript-eslint/visitor-keys": "8.46.3", - "debug": "^4.3.4" + "@typescript-eslint/scope-manager": "8.52.0", + "@typescript-eslint/types": "8.52.0", + "@typescript-eslint/typescript-estree": "8.52.0", + "@typescript-eslint/visitor-keys": "8.52.0", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2904,15 +3125,15 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.3.tgz", - "integrity": "sha512-Fz8yFXsp2wDFeUElO88S9n4w1I4CWDTXDqDr9gYvZgUpwXQqmZBr9+NTTql5R3J7+hrJZPdpiWaB9VNhAKYLuQ==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.52.0.tgz", + "integrity": "sha512-xD0MfdSdEmeFa3OmVqonHi+Cciab96ls1UhIF/qX/O/gPu5KXD0bY9lu33jj04fjzrXHcuvjBcBC+D3SNSadaw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.46.3", - "@typescript-eslint/types": "^8.46.3", - "debug": "^4.3.4" + "@typescript-eslint/tsconfig-utils": "^8.52.0", + "@typescript-eslint/types": "^8.52.0", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2926,14 +3147,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.3.tgz", - "integrity": "sha512-FCi7Y1zgrmxp3DfWfr+3m9ansUUFoy8dkEdeQSgA9gbm8DaHYvZCdkFRQrtKiedFf3Ha6VmoqoAaP68+i+22kg==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.52.0.tgz", + "integrity": "sha512-ixxqmmCcc1Nf8S0mS0TkJ/3LKcC8mruYJPOU6Ia2F/zUUR4pApW7LzrpU3JmtePbRUTes9bEqRc1Gg4iyRnDzA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.3", - "@typescript-eslint/visitor-keys": "8.46.3" + "@typescript-eslint/types": "8.52.0", + "@typescript-eslint/visitor-keys": "8.52.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2944,9 +3165,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.3.tgz", - "integrity": "sha512-GLupljMniHNIROP0zE7nCcybptolcH8QZfXOpCfhQDAdwJ/ZTlcaBOYebSOZotpti/3HrHSw7D3PZm75gYFsOA==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.52.0.tgz", + "integrity": "sha512-jl+8fzr/SdzdxWJznq5nvoI7qn2tNYV/ZBAEcaFMVXf+K6jmXvAFrgo/+5rxgnL152f//pDEAYAhhBAZGrVfwg==", "dev": true, "license": "MIT", "engines": { @@ -2961,17 +3182,17 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.3.tgz", - "integrity": "sha512-ZPCADbr+qfz3aiTTYNNkCbUt+cjNwI/5McyANNrFBpVxPt7GqpEYz5ZfdwuFyGUnJ9FdDXbGODUu6iRCI6XRXw==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.52.0.tgz", + "integrity": "sha512-JD3wKBRWglYRQkAtsyGz1AewDu3mTc7NtRjR/ceTyGoPqmdS5oCdx/oZMWD5Zuqmo6/MpsYs0wp6axNt88/2EQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.3", - "@typescript-eslint/typescript-estree": "8.46.3", - "@typescript-eslint/utils": "8.46.3", - "debug": "^4.3.4", - "ts-api-utils": "^2.1.0" + "@typescript-eslint/types": "8.52.0", + "@typescript-eslint/typescript-estree": "8.52.0", + "@typescript-eslint/utils": "8.52.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2986,9 +3207,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.3.tgz", - "integrity": "sha512-G7Ok9WN/ggW7e/tOf8TQYMaxgID3Iujn231hfi0Pc7ZheztIJVpO44ekY00b7akqc6nZcvregk0Jpah3kep6hA==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.52.0.tgz", + "integrity": "sha512-LWQV1V4q9V4cT4H5JCIx3481iIFxH1UkVk+ZkGGAV1ZGcjGI9IoFOfg3O6ywz8QqCDEp7Inlg6kovMofsNRaGg==", "dev": true, "license": "MIT", "engines": { @@ -3000,22 +3221,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.3.tgz", - "integrity": "sha512-f/NvtRjOm80BtNM5OQtlaBdM5BRFUv7gf381j9wygDNL+qOYSNOgtQ/DCndiYi80iIOv76QqaTmp4fa9hwI0OA==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.52.0.tgz", + "integrity": "sha512-XP3LClsCc0FsTK5/frGjolyADTh3QmsLp6nKd476xNI9CsSsLnmn4f0jrzNoAulmxlmNIpeXuHYeEQv61Q6qeQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.46.3", - "@typescript-eslint/tsconfig-utils": "8.46.3", - "@typescript-eslint/types": "8.46.3", - "@typescript-eslint/visitor-keys": "8.46.3", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.1.0" + "@typescript-eslint/project-service": "8.52.0", + "@typescript-eslint/tsconfig-utils": "8.52.0", + "@typescript-eslint/types": "8.52.0", + "@typescript-eslint/visitor-keys": "8.52.0", + "debug": "^4.4.3", + "minimatch": "^9.0.5", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3038,36 +3258,6 @@ "balanced-match": "^1.0.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/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/@typescript-eslint/typescript-estree/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -3098,16 +3288,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.3.tgz", - "integrity": "sha512-VXw7qmdkucEx9WkmR3ld/u6VhRyKeiF1uxWwCy/iuNfokjJ7VhsgLSOTjsol8BunSw190zABzpwdNsze2Kpo4g==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.52.0.tgz", + "integrity": "sha512-wYndVMWkweqHpEpwPhwqE2lnD2DxC6WVLupU/DOt/0/v+/+iQbbzO3jOHjmBMnhu0DgLULvOaU4h4pwHYi2oRQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.46.3", - "@typescript-eslint/types": "8.46.3", - "@typescript-eslint/typescript-estree": "8.46.3" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.52.0", + "@typescript-eslint/types": "8.52.0", + "@typescript-eslint/typescript-estree": "8.52.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3122,13 +3312,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.3.tgz", - "integrity": "sha512-uk574k8IU0rOF/AjniX8qbLSGURJVUCeM5e4MIMKBFFi8weeiLrG1fyQejyLXQpRZbU/1BuQasleV/RfHC3hHg==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.52.0.tgz", + "integrity": "sha512-ink3/Zofus34nmBsPjow63FP5M7IGff0RKAgqR6+CFpdk22M7aLwC9gOcLGYqr7MczLPzZVERW9hRog3O4n1sQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.3", + "@typescript-eslint/types": "8.52.0", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -3139,6 +3329,81 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@uiw/codemirror-extensions-basic-setup": { + "version": "4.25.4", + "resolved": "https://registry.npmjs.org/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.25.4.tgz", + "integrity": "sha512-YzNwkm0AbPv1EXhCHYR5v0nqfemG2jEB0Z3Att4rBYqKrlG7AA9Rhjc3IyBaOzsBu18wtrp9/+uhTyu7TXSRng==", + "license": "MIT", + "peer": true, + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@codemirror/autocomplete": ">=6.0.0", + "@codemirror/commands": ">=6.0.0", + "@codemirror/language": ">=6.0.0", + "@codemirror/lint": ">=6.0.0", + "@codemirror/search": ">=6.0.0", + "@codemirror/state": ">=6.0.0", + "@codemirror/view": ">=6.0.0" + } + }, + "node_modules/@uiw/codemirror-themes": { + "version": "4.25.4", + "resolved": "https://registry.npmjs.org/@uiw/codemirror-themes/-/codemirror-themes-4.25.4.tgz", + "integrity": "sha512-2SLktItgcZC4p0+PfFusEbAHwbuAWe3bOOntCevVgHtrWGtGZX3IPv2k8IKZMgOXtAHyGKpJvT9/nspPn/uCQg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@codemirror/language": ">=6.0.0", + "@codemirror/state": ">=6.0.0", + "@codemirror/view": ">=6.0.0" + } + }, + "node_modules/@uiw/react-codemirror": { + "version": "4.25.4", + "resolved": "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.25.4.tgz", + "integrity": "sha512-ipO067oyfUw+DVaXhQCxkB0ZD9b7RnY+ByrprSYSKCHaULvJ3sqWYC/Zen6zVQ8/XC4o5EPBfatGiX20kC7XGA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.6", + "@codemirror/commands": "^6.1.0", + "@codemirror/state": "^6.1.1", + "@codemirror/theme-one-dark": "^6.0.0", + "@uiw/codemirror-extensions-basic-setup": "4.25.4", + "codemirror": "^6.0.0" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.11.0", + "@codemirror/state": ">=6.0.0", + "@codemirror/theme-one-dark": ">=6.0.0", + "@codemirror/view": ">=6.0.0", + "codemirror": ">=6.0.0", + "react": ">=17.0.0", + "react-dom": ">=17.0.0" + } + }, "node_modules/@unrs/resolver-binding-android-arm-eabi": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", @@ -3558,6 +3823,7 @@ "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.0.0" }, @@ -3768,10 +4034,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/avvvatars-react": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/avvvatars-react/-/avvvatars-react-0.4.2.tgz", + "integrity": "sha512-D/bnSM+P6pQi71dFeFVqQsqmv+ct5XG7uO2lvJoiksALpXLd6kPgpRR1SUQxFZJkJNrkmg0NPgbhIgJgOsDYRQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "goober": "^2.1.8" + }, + "peerDependencies": { + "react": ">= 16", + "react-dom": ">= 16" + } + }, "node_modules/axe-core": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.0.tgz", - "integrity": "sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.1.tgz", + "integrity": "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==", "dev": true, "license": "MPL-2.0", "engines": { @@ -3806,10 +4086,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.25", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.25.tgz", - "integrity": "sha512-2NovHVesVF5TXefsGX1yzx1xgr7+m9JQenvz6FQY3qd+YXkKkYiv+vTCc7OriP9mcDZpTC5mAOYN4ocd29+erA==", - "dev": true, + "version": "2.9.14", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.14.tgz", + "integrity": "sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -3840,9 +4119,9 @@ } }, "node_modules/browserslist": { - "version": "4.27.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.27.0.tgz", - "integrity": "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dev": true, "funding": [ { @@ -3860,11 +4139,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.8.19", - "caniuse-lite": "^1.0.30001751", - "electron-to-chromium": "^1.5.238", - "node-releases": "^2.0.26", - "update-browserslist-db": "^1.1.4" + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" @@ -3934,9 +4213,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001753", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001753.tgz", - "integrity": "sha512-Bj5H35MD/ebaOV4iDLqPEtiliTN29qkGtEHCwawWn4cYm+bPJM2NsaP30vtZcnERClMzp52J4+aw2UNbK4o+zw==", + "version": "1.0.30001764", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001764.tgz", + "integrity": "sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==", "funding": [ { "type": "opencollective", @@ -3959,15 +4238,48 @@ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, + "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/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "peer": true, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, "node_modules/chokidar": { @@ -4015,6 +4327,22 @@ "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, + "node_modules/codemirror": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz", + "integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -4035,6 +4363,17 @@ "dev": true, "license": "MIT" }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -4049,6 +4388,13 @@ "dev": true, "license": "MIT" }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", + "license": "MIT", + "peer": true + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -4065,10 +4411,9 @@ } }, "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "devOptional": true, + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, "node_modules/d3-color": { @@ -4246,6 +4591,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -4264,6 +4619,20 @@ } } }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -4308,20 +4677,24 @@ } }, "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", "license": "Apache-2.0", "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, "engines": { - "node": ">=8" + "node": ">=0.10" } }, "node_modules/detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/doctrine": { "version": "2.1.0", @@ -4336,6 +4709,16 @@ "node": ">=0.10.0" } }, + "node_modules/dompurify": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz", + "integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==", + "license": "(MPL-2.0 OR Apache-2.0)", + "peer": true, + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -4352,9 +4735,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.245", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.245.tgz", - "integrity": "sha512-rdmGfW47ZhL/oWEJAY4qxRtdly2B98ooTJ0pdEI4jhVLZ6tNf8fPtov2wS1IRKwFJT92le3x4Knxiwzl7cPPpQ==", + "version": "1.5.267", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", "dev": true, "license": "ISC" }, @@ -4366,9 +4749,9 @@ "license": "MIT" }, "node_modules/es-abstract": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", + "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", "dev": true, "license": "MIT", "dependencies": { @@ -4455,27 +4838,27 @@ } }, "node_modules/es-iterator-helpers": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", - "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.2.tgz", + "integrity": "sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==", "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", - "call-bound": "^1.0.3", + "call-bound": "^1.0.4", "define-properties": "^1.2.1", - "es-abstract": "^1.23.6", + "es-abstract": "^1.24.1", "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.3", + "es-set-tostringtag": "^2.1.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.6", + "get-intrinsic": "^1.3.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", - "iterator.prototype": "^1.1.4", + "iterator.prototype": "^1.1.5", "safe-array-concat": "^1.1.3" }, "engines": { @@ -4566,9 +4949,9 @@ } }, "node_modules/eslint": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", - "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", "dependencies": { @@ -4578,7 +4961,7 @@ "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.1", + "@eslint/js": "9.39.2", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -4626,13 +5009,13 @@ } }, "node_modules/eslint-config-next": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.0.7.tgz", - "integrity": "sha512-WubFGLFHfk2KivkdRGfx6cGSFhaQqhERRfyO8BRx+qiGPGp7WLKcPvYC4mdx1z3VhVRcrfFzczjjTrbJZOpnEQ==", + "version": "16.1.5", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.1.5.tgz", + "integrity": "sha512-XwXyv65DC1HXI3gMxm13jvgx0IxKu6XhZhIWTfCDt4c45njHYUM2pk1Y8QXMAWMMnqPy94I2OLMmvIrNGcwLwQ==", "dev": true, "license": "MIT", "dependencies": { - "@next/eslint-plugin-next": "16.0.7", + "@next/eslint-plugin-next": "16.1.5", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.32.0", @@ -4944,9 +5327,9 @@ } }, "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -5040,15 +5423,29 @@ "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==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" } }, + "node_modules/fault": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", + "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", + "license": "MIT", + "peer": true, + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -5129,6 +5526,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "peer": true, + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -5220,6 +5626,7 @@ "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=6" } @@ -5312,6 +5719,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/goober": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.18.tgz", + "integrity": "sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "csstype": "^3.0.10" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -5325,13 +5742,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "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/graphql": { "version": "16.12.0", "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.12.0.tgz", @@ -5450,6 +5860,38 @@ "node": ">= 0.4" } }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hermes-estree": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", @@ -5467,6 +5909,23 @@ "hermes-estree": "0.25.1" } }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/highlightjs-vue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/highlightjs-vue/-/highlightjs-vue-1.0.0.tgz", + "integrity": "sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==", + "license": "CC0-1.0", + "peer": true + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -5525,6 +5984,32 @@ "node": ">= 0.4" } }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "peer": true, + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", @@ -5683,6 +6168,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -5742,6 +6238,17 @@ "node": ">=0.10.0" } }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", @@ -5986,9 +6493,9 @@ "license": "MIT" }, "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==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -6091,6 +6598,13 @@ "node": ">=0.10" } }, + "node_modules/ldrs": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/ldrs/-/ldrs-1.1.9.tgz", + "integrity": "sha512-JKVdzboxeZrKecA8ovi5iIDgs59wUrtJ+LDrHCgZecNrR0AJi2cJ3ZANJ+UCNS/sHRol73/jlypNCAMCXS+Ung==", + "license": "MIT", + "peer": true + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -6140,6 +6654,21 @@ "loose-envify": "cli.js" } }, + "node_modules/lowlight": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", + "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", + "license": "MIT", + "peer": true, + "dependencies": { + "fault": "^1.0.0", + "highlight.js": "~10.7.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -6150,6 +6679,19 @@ "yallist": "^3.0.2" } }, + "node_modules/marked": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", + "integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==", + "license": "MIT", + "peer": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -6214,6 +6756,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/monaco-editor": { + "version": "0.55.1", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz", + "integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==", + "license": "MIT", + "peer": true, + "dependencies": { + "dompurify": "3.2.7", + "marked": "14.0.0" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -6263,13 +6816,14 @@ "license": "MIT" }, "node_modules/next": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/next/-/next-16.0.7.tgz", - "integrity": "sha512-3mBRJyPxT4LOxAJI6IsXeFtKfiJUbjCLgvXO02fV8Wy/lIhPvP94Fe7dGhUgHXcQy4sSuYwQNcOLhIfOm0rL0A==", + "version": "16.1.5", + "resolved": "https://registry.npmjs.org/next/-/next-16.1.5.tgz", + "integrity": "sha512-f+wE+NSbiQgh3DSAlTaw2FwY5yGdVViAtp8TotNQj4kk4Q8Bh1sC/aL9aH+Rg1YAVn18OYXsRDT7U/079jgP7w==", "license": "MIT", "dependencies": { - "@next/env": "16.0.7", + "@next/env": "16.1.5", "@swc/helpers": "0.5.15", + "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" @@ -6281,14 +6835,14 @@ "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "16.0.7", - "@next/swc-darwin-x64": "16.0.7", - "@next/swc-linux-arm64-gnu": "16.0.7", - "@next/swc-linux-arm64-musl": "16.0.7", - "@next/swc-linux-x64-gnu": "16.0.7", - "@next/swc-linux-x64-musl": "16.0.7", - "@next/swc-win32-arm64-msvc": "16.0.7", - "@next/swc-win32-x64-msvc": "16.0.7", + "@next/swc-darwin-arm64": "16.1.5", + "@next/swc-darwin-x64": "16.1.5", + "@next/swc-linux-arm64-gnu": "16.1.5", + "@next/swc-linux-arm64-musl": "16.1.5", + "@next/swc-linux-x64-gnu": "16.1.5", + "@next/swc-linux-x64-musl": "16.1.5", + "@next/swc-win32-arm64-msvc": "16.1.5", + "@next/swc-win32-x64-msvc": "16.1.5", "sharp": "^0.34.4" }, "peerDependencies": { @@ -6553,6 +7107,33 @@ "node": ">=6" } }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT", + "peer": true + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -6647,6 +7228,16 @@ "node": ">= 0.8.0" } }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -6658,6 +7249,17 @@ "react-is": "^16.13.1" } }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -6690,9 +7292,9 @@ "license": "MIT" }, "node_modules/react": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", - "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", + "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6703,6 +7305,7 @@ "resolved": "https://registry.npmjs.org/react-contenteditable/-/react-contenteditable-3.3.7.tgz", "integrity": "sha512-GA9NbC0DkDdpN3iGvib/OMHWTJzDX2cfkgy5Tt98JJAbA3kLnyrNbBIpsSpPpq7T8d3scD39DHP+j8mAM7BIfQ==", "license": "Apache-2.0", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "prop-types": "^15.7.1" @@ -6712,15 +7315,15 @@ } }, "node_modules/react-dom": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", - "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "license": "MIT", "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.0" + "react": "^19.2.3" } }, "node_modules/react-is": { @@ -6734,6 +7337,7 @@ "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", "license": "MIT", + "peer": true, "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", @@ -6759,6 +7363,7 @@ "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", "license": "MIT", + "peer": true, "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" @@ -6792,6 +7397,7 @@ "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", "license": "MIT", + "peer": true, "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" @@ -6809,6 +7415,27 @@ } } }, + "node_modules/react-syntax-highlighter": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-16.1.0.tgz", + "integrity": "sha512-E40/hBiP5rCNwkeBN1vRP+xow1X0pndinO+z3h7HLsHyjztbyjfzNWNKuAsJj+7DLam9iT4AaaOZnueCU+Nplg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.28.4", + "highlight.js": "^10.4.1", + "highlightjs-vue": "^1.0.0", + "lowlight": "^1.17.0", + "prismjs": "^1.30.0", + "refractor": "^5.0.0" + }, + "engines": { + "node": ">= 16.20.2" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, "node_modules/react-zoom-pan-pinch": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/react-zoom-pan-pinch/-/react-zoom-pan-pinch-3.7.0.tgz", @@ -6860,6 +7487,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/refractor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-5.0.0.tgz", + "integrity": "sha512-QXOrHQF5jOpjjLfiNk5GFnWhRXvxjUVnlFxkeDmewR5sXkr3iM46Zo+CnRR8B+MDVqkULW4EcLVcRBNOPXHosw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/hast": "^3.0.0", + "@types/prismjs": "^1.0.0", + "hastscript": "^9.0.0", + "parse-entities": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", @@ -7022,9 +7666,9 @@ } }, "node_modules/sass": { - "version": "1.94.2", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.94.2.tgz", - "integrity": "sha512-N+7WK20/wOr7CzA2snJcUSSNTCzeCGUTFY3OgeQP3mZ1aj9NMQ0mSTXwlrnd89j33zzQJGqIN52GIOmYrfq46A==", + "version": "1.97.2", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.2.tgz", + "integrity": "sha512-y5LWb0IlbO4e97Zr7c3mlpabcbBtS+ieiZ9iwDooShpFKWXf62zz5pEPdwrLYm+Bxn1fnbwFGzHuCLSA9tBmrw==", "license": "MIT", "dependencies": { "chokidar": "^4.0.0", @@ -7107,16 +7751,16 @@ } }, "node_modules/sharp": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.4.tgz", - "integrity": "sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", "hasInstallScript": true, "license": "Apache-2.0", "optional": true, "dependencies": { "@img/colour": "^1.0.0", - "detect-libc": "^2.1.0", - "semver": "^7.7.2" + "detect-libc": "^2.1.2", + "semver": "^7.7.3" }, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" @@ -7125,28 +7769,40 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.4", - "@img/sharp-darwin-x64": "0.34.4", - "@img/sharp-libvips-darwin-arm64": "1.2.3", - "@img/sharp-libvips-darwin-x64": "1.2.3", - "@img/sharp-libvips-linux-arm": "1.2.3", - "@img/sharp-libvips-linux-arm64": "1.2.3", - "@img/sharp-libvips-linux-ppc64": "1.2.3", - "@img/sharp-libvips-linux-s390x": "1.2.3", - "@img/sharp-libvips-linux-x64": "1.2.3", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.3", - "@img/sharp-libvips-linuxmusl-x64": "1.2.3", - "@img/sharp-linux-arm": "0.34.4", - "@img/sharp-linux-arm64": "0.34.4", - "@img/sharp-linux-ppc64": "0.34.4", - "@img/sharp-linux-s390x": "0.34.4", - "@img/sharp-linux-x64": "0.34.4", - "@img/sharp-linuxmusl-arm64": "0.34.4", - "@img/sharp-linuxmusl-x64": "0.34.4", - "@img/sharp-wasm32": "0.34.4", - "@img/sharp-win32-arm64": "0.34.4", - "@img/sharp-win32-ia32": "0.34.4", - "@img/sharp-win32-x64": "0.34.4" + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/sharp/node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" } }, "node_modules/sharp/node_modules/semver": { @@ -7281,6 +7937,17 @@ "node": ">=0.10.0" } }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/stable-hash": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", @@ -7288,6 +7955,13 @@ "dev": true, "license": "MIT" }, + "node_modules/state-local": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", + "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==", + "license": "MIT", + "peer": true + }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -7438,6 +8112,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/style-mod": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz", + "integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==", + "license": "MIT", + "peer": true + }, "node_modules/styled-jsx": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", @@ -7549,9 +8230,9 @@ } }, "node_modules/ts-api-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", - "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", "dev": true, "license": "MIT", "engines": { @@ -7699,16 +8380,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.46.3.tgz", - "integrity": "sha512-bAfgMavTuGo+8n6/QQDVQz4tZ4f7Soqg53RbrlZQEoAltYop/XR4RAts/I0BrO3TTClTSTFJ0wYbla+P8cEWJA==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.52.0.tgz", + "integrity": "sha512-atlQQJ2YkO4pfTVQmQ+wvYQwexPDOIgo+RaVcD7gHgzy/IQA+XTyuxNM9M9TVXvttkF7koBHmcwisKdOAf2EcA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.46.3", - "@typescript-eslint/parser": "8.46.3", - "@typescript-eslint/typescript-estree": "8.46.3", - "@typescript-eslint/utils": "8.46.3" + "@typescript-eslint/eslint-plugin": "8.52.0", + "@typescript-eslint/parser": "8.52.0", + "@typescript-eslint/typescript-estree": "8.52.0", + "@typescript-eslint/utils": "8.52.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7784,9 +8465,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", - "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "funding": [ { @@ -7829,6 +8510,7 @@ "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.0.0" }, @@ -7850,6 +8532,7 @@ "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", "license": "MIT", + "peer": true, "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" @@ -7877,6 +8560,13 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "license": "MIT", + "peer": true + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -8013,9 +8703,9 @@ } }, "node_modules/zod": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz", - "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.5.tgz", + "integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==", "dev": true, "license": "MIT", "funding": { diff --git a/package.json b/package.json index cfc9727d..22eb150d 100644 --- a/package.json +++ b/package.json @@ -15,12 +15,13 @@ }, "dependencies": { "@apollo/client": "^4.0.9", - "@code0-tech/pictor": "^0.0.0-mvp.31", + "@code0-tech/pictor": "^0.0.0-mvp.45", + "date-fns": "^4.1.0", "graphql": "^16.12.0", "graphql-tag": "^2.12.6", - "next": "16.0.7", - "react": "19.2.0", - "react-dom": "19.2.0", + "next": "16.1.5", + "react": "19.2.3", + "react-dom": "19.2.3", "rxjs": "^7.8.2", "sass": "^1.93.3" }, @@ -30,7 +31,7 @@ "@types/react-dom": "^19", "babel-plugin-react-compiler": "^1.0.0", "eslint": "^9", - "eslint-config-next": "16.0.7", + "eslint-config-next": "16.1.5", "typescript": "^5" } } diff --git a/src/app/(auth)/email/page.tsx b/src/app/(auth)/email/page.tsx index 7e9a6ec0..dd8fb0ab 100644 --- a/src/app/(auth)/email/page.tsx +++ b/src/app/(auth)/email/page.tsx @@ -1,5 +1,5 @@ import React from "react"; -import {UserEmailVerificationPage} from "@edition/auth/UserEmailVerificationPage"; +import {UserEmailVerificationPage} from "@edition/user/pages/UserEmailVerificationPage"; export default function Page() { return diff --git a/src/app/(auth)/layout.tsx b/src/app/(auth)/layout.tsx index 7e64ff5b..1cd99e4f 100644 --- a/src/app/(auth)/layout.tsx +++ b/src/app/(auth)/layout.tsx @@ -1,12 +1,13 @@ "use client" import {Col, Container, ContextStoreProvider, DFullScreen, DUserView, Flex, Text} from "@code0-tech/pictor"; -import {UserService} from "@edition/user/User.service"; +import {UserService} from "@edition/user/services/User.service"; import {useApolloClient} from "@apollo/client/react"; import {GraphqlClient} from "@core/util/graphql-client"; import Image from "next/image"; import React from "react"; import {usePersistentReactiveArrayService} from "@/hooks/usePersistentReactiveArrayService"; +import {View} from "@code0-tech/pictor/dist/utils/view"; export default function AuthLayout({children}: Readonly<{ children: React.ReactNode }>) { diff --git a/src/app/(auth)/login/page.tsx b/src/app/(auth)/login/page.tsx index 66166924..28b69e29 100644 --- a/src/app/(auth)/login/page.tsx +++ b/src/app/(auth)/login/page.tsx @@ -1,5 +1,5 @@ import React from "react"; -import {UserLoginPage} from "@edition/auth/UserLoginPage"; +import {UserLoginPage} from "@edition/user/pages/UserLoginPage"; export default function Page() { return diff --git a/src/app/(auth)/password/page.tsx b/src/app/(auth)/password/page.tsx index 35cdb887..fa65ee95 100644 --- a/src/app/(auth)/password/page.tsx +++ b/src/app/(auth)/password/page.tsx @@ -1,5 +1,5 @@ import React from "react"; -import {UserForgotPasswordPage} from "@edition/auth/UserForgotPasswordPage"; +import {UserForgotPasswordPage} from "@edition/user/pages/UserForgotPasswordPage"; export default function Page() { return diff --git a/src/app/(auth)/password/reset/page.tsx b/src/app/(auth)/password/reset/page.tsx index 14555482..f0347649 100644 --- a/src/app/(auth)/password/reset/page.tsx +++ b/src/app/(auth)/password/reset/page.tsx @@ -1,5 +1,5 @@ import React from "react"; -import {UserResetPasswordPage} from "@edition/auth/UserResetPasswordPage"; +import {UserResetPasswordPage} from "@edition/user/pages/UserResetPasswordPage"; export default function Page() { return diff --git a/src/app/(auth)/register/page.tsx b/src/app/(auth)/register/page.tsx index b63f15c8..1c3e4f49 100644 --- a/src/app/(auth)/register/page.tsx +++ b/src/app/(auth)/register/page.tsx @@ -1,5 +1,5 @@ import React from "react"; -import {UserRegistrationPage} from "@edition/auth/UserRegistrationPage"; +import {UserRegistrationPage} from "@edition/user/pages/UserRegistrationPage"; export default function Page() { return diff --git a/src/app/(dashboard)/@bar/default.tsx b/src/app/(dashboard)/@bar/default.tsx index c46b4bb5..99055c6e 100644 --- a/src/app/(dashboard)/@bar/default.tsx +++ b/src/app/(dashboard)/@bar/default.tsx @@ -1,7 +1,7 @@ "use client"; import React from "react"; -import {ApplicationBarView} from "@edition/dashboard/application/ApplicationBarView"; +import {ApplicationBarView} from "@edition/application/ApplicationBarView"; const Page = () => { return diff --git a/src/app/(dashboard)/@tab/namespace/[namespaceId]/members/default.tsx b/src/app/(dashboard)/@tab/namespace/[namespaceId]/members/default.tsx index 48890ba8..3881c19f 100644 --- a/src/app/(dashboard)/@tab/namespace/[namespaceId]/members/default.tsx +++ b/src/app/(dashboard)/@tab/namespace/[namespaceId]/members/default.tsx @@ -1,4 +1,4 @@ -import {NamespaceTabView} from "@edition/dashboard/namespace/NamespaceTabView"; +import {NamespaceTabView} from "@edition/namespace/views/NamespaceTabView"; export default function Page() { return diff --git a/src/app/(dashboard)/@tab/namespace/[namespaceId]/page.tsx b/src/app/(dashboard)/@tab/namespace/[namespaceId]/page.tsx index 48890ba8..3881c19f 100644 --- a/src/app/(dashboard)/@tab/namespace/[namespaceId]/page.tsx +++ b/src/app/(dashboard)/@tab/namespace/[namespaceId]/page.tsx @@ -1,4 +1,4 @@ -import {NamespaceTabView} from "@edition/dashboard/namespace/NamespaceTabView"; +import {NamespaceTabView} from "@edition/namespace/views/NamespaceTabView"; export default function Page() { return diff --git a/src/app/(dashboard)/@tab/namespace/[namespaceId]/projects/default.tsx b/src/app/(dashboard)/@tab/namespace/[namespaceId]/projects/default.tsx index 48890ba8..3881c19f 100644 --- a/src/app/(dashboard)/@tab/namespace/[namespaceId]/projects/default.tsx +++ b/src/app/(dashboard)/@tab/namespace/[namespaceId]/projects/default.tsx @@ -1,4 +1,4 @@ -import {NamespaceTabView} from "@edition/dashboard/namespace/NamespaceTabView"; +import {NamespaceTabView} from "@edition/namespace/views/NamespaceTabView"; export default function Page() { return diff --git a/src/app/(dashboard)/@tab/namespace/[namespaceId]/roles/default.tsx b/src/app/(dashboard)/@tab/namespace/[namespaceId]/roles/default.tsx index 48890ba8..3881c19f 100644 --- a/src/app/(dashboard)/@tab/namespace/[namespaceId]/roles/default.tsx +++ b/src/app/(dashboard)/@tab/namespace/[namespaceId]/roles/default.tsx @@ -1,4 +1,4 @@ -import {NamespaceTabView} from "@edition/dashboard/namespace/NamespaceTabView"; +import {NamespaceTabView} from "@edition/namespace/views/NamespaceTabView"; export default function Page() { return diff --git a/src/app/(dashboard)/@tab/namespace/[namespaceId]/runtimes/default.tsx b/src/app/(dashboard)/@tab/namespace/[namespaceId]/runtimes/default.tsx index 48890ba8..3881c19f 100644 --- a/src/app/(dashboard)/@tab/namespace/[namespaceId]/runtimes/default.tsx +++ b/src/app/(dashboard)/@tab/namespace/[namespaceId]/runtimes/default.tsx @@ -1,4 +1,4 @@ -import {NamespaceTabView} from "@edition/dashboard/namespace/NamespaceTabView"; +import {NamespaceTabView} from "@edition/namespace/views/NamespaceTabView"; export default function Page() { return diff --git a/src/app/(dashboard)/@tab/namespace/[namespaceId]/settings/default.tsx b/src/app/(dashboard)/@tab/namespace/[namespaceId]/settings/default.tsx index 48890ba8..3881c19f 100644 --- a/src/app/(dashboard)/@tab/namespace/[namespaceId]/settings/default.tsx +++ b/src/app/(dashboard)/@tab/namespace/[namespaceId]/settings/default.tsx @@ -1,4 +1,4 @@ -import {NamespaceTabView} from "@edition/dashboard/namespace/NamespaceTabView"; +import {NamespaceTabView} from "@edition/namespace/views/NamespaceTabView"; export default function Page() { return diff --git a/src/app/(dashboard)/@tab/organizations/default.tsx b/src/app/(dashboard)/@tab/organizations/default.tsx index fe103845..3ef9f84b 100644 --- a/src/app/(dashboard)/@tab/organizations/default.tsx +++ b/src/app/(dashboard)/@tab/organizations/default.tsx @@ -1,7 +1,7 @@ "use client" import React from "react"; -import {ApplicationTabView} from "@edition/dashboard/application/ApplicationTabView"; +import {ApplicationTabView} from "@edition/application/ApplicationTabView"; const Page: React.FC = () => { return diff --git a/src/app/(dashboard)/@tab/page.tsx b/src/app/(dashboard)/@tab/page.tsx index fe103845..3ef9f84b 100644 --- a/src/app/(dashboard)/@tab/page.tsx +++ b/src/app/(dashboard)/@tab/page.tsx @@ -1,7 +1,7 @@ "use client" import React from "react"; -import {ApplicationTabView} from "@edition/dashboard/application/ApplicationTabView"; +import {ApplicationTabView} from "@edition/application/ApplicationTabView"; const Page: React.FC = () => { return diff --git a/src/app/(dashboard)/@tab/runtimes/default.tsx b/src/app/(dashboard)/@tab/runtimes/default.tsx index fe103845..3ef9f84b 100644 --- a/src/app/(dashboard)/@tab/runtimes/default.tsx +++ b/src/app/(dashboard)/@tab/runtimes/default.tsx @@ -1,7 +1,7 @@ "use client" import React from "react"; -import {ApplicationTabView} from "@edition/dashboard/application/ApplicationTabView"; +import {ApplicationTabView} from "@edition/application/ApplicationTabView"; const Page: React.FC = () => { return diff --git a/src/app/(dashboard)/@tab/settings/page.tsx b/src/app/(dashboard)/@tab/settings/page.tsx index fe103845..3ef9f84b 100644 --- a/src/app/(dashboard)/@tab/settings/page.tsx +++ b/src/app/(dashboard)/@tab/settings/page.tsx @@ -1,7 +1,7 @@ "use client" import React from "react"; -import {ApplicationTabView} from "@edition/dashboard/application/ApplicationTabView"; +import {ApplicationTabView} from "@edition/application/ApplicationTabView"; const Page: React.FC = () => { return diff --git a/src/app/(dashboard)/@tab/users/page.tsx b/src/app/(dashboard)/@tab/users/page.tsx index fe103845..3ef9f84b 100644 --- a/src/app/(dashboard)/@tab/users/page.tsx +++ b/src/app/(dashboard)/@tab/users/page.tsx @@ -1,7 +1,7 @@ "use client" import React from "react"; -import {ApplicationTabView} from "@edition/dashboard/application/ApplicationTabView"; +import {ApplicationTabView} from "@edition/application/ApplicationTabView"; const Page: React.FC = () => { return diff --git a/src/app/(dashboard)/layout.tsx b/src/app/(dashboard)/layout.tsx index 07e3d497..3e15e148 100644 --- a/src/app/(dashboard)/layout.tsx +++ b/src/app/(dashboard)/layout.tsx @@ -3,28 +3,30 @@ import React from "react"; import {useApolloClient} from "@apollo/client/react"; import { - Container, + AuroraBackground, ContextStoreProvider, DLayout, - DNamespaceMemberView, DNamespaceProjectView, + DNamespaceMemberView, + DNamespaceProjectView, + DNamespaceRoleView, DNamespaceView, - DOrganizationView, DRuntimeView, + DOrganizationView, + DRuntimeView, DUserView, - ReactiveArrayStore, - useUserSession, - DNamespaceRoleView + Flex, + useUserSession } from "@code0-tech/pictor"; -import {UserService} from "@edition/user/User.service"; +import {UserService} from "@edition/user/services/User.service"; import {GraphqlClient} from "@core/util/graphql-client"; import {useRouter} from "next/navigation"; -import {OrganizationService} from "@edition/organization/Organization.service"; -import {MemberService} from "@edition/member/Member.service"; -import {NamespaceService} from "@edition/namespace/Namespace.service"; +import {OrganizationService} from "@edition/organization/services/Organization.service"; +import {MemberService} from "@edition/member/services/Member.service"; +import {NamespaceService} from "@edition/namespace/services/Namespace.service"; import {usePersistentReactiveArrayService} from "@/hooks/usePersistentReactiveArrayService"; -import {RuntimeService} from "@edition/runtime/Runtime.service"; -import {ProjectService} from "@edition/project/Project.service"; -import {RoleService} from "@edition/role/Role.service"; -import {Spacing} from "@code0-tech/pictor/dist/components/spacing/Spacing"; +import {RuntimeService} from "@edition/runtime/services/Runtime.service"; +import {ProjectService} from "@edition/project/services/Project.service"; +import {RoleService} from "@edition/role/services/Role.service"; +import Image from "next/image"; interface ApplicationLayoutProps { children: React.ReactNode @@ -40,28 +42,50 @@ const ApplicationLayout: React.FC = ({children, bar, tab const graphqlClient = React.useMemo(() => new GraphqlClient(client), [client]) - const user = usePersistentReactiveArrayService(`dashboard::users::${currentSession?.id}`, (store: ReactiveArrayStore) => new UserService(graphqlClient, store)) - const organization = usePersistentReactiveArrayService(`dashboard::organizations::${currentSession?.id}`, (store: ReactiveArrayStore) => new OrganizationService(graphqlClient, store)) - const member = usePersistentReactiveArrayService(`dashboard::members::${currentSession?.id}`, (store: ReactiveArrayStore) => new MemberService(graphqlClient, store)) - const namespace = usePersistentReactiveArrayService(`dashboard::namespaces::${currentSession?.id}`, (store: ReactiveArrayStore) => new NamespaceService(graphqlClient, store)) - const runtime = usePersistentReactiveArrayService(`dashboard::global_runtimes::${currentSession?.id}`, (store: ReactiveArrayStore) => new RuntimeService(graphqlClient, store)) - const project = usePersistentReactiveArrayService(`dashboard::projects::${currentSession?.id}`, (store: ReactiveArrayStore) => new ProjectService(graphqlClient, store)) - const role = usePersistentReactiveArrayService(`dashboard::roles::${currentSession?.id}`, (store: ReactiveArrayStore) => new RoleService(graphqlClient, store)) + const user = usePersistentReactiveArrayService(`dashboard::users::${currentSession?.id}`, (store) => new UserService(graphqlClient, store)) + const organization = usePersistentReactiveArrayService(`dashboard::organizations::${currentSession?.id}`, (store) => new OrganizationService(graphqlClient, store)) + const member = usePersistentReactiveArrayService(`dashboard::members::${currentSession?.id}`, (store) => new MemberService(graphqlClient, store)) + const namespace = usePersistentReactiveArrayService(`dashboard::namespaces::${currentSession?.id}`, (store) => new NamespaceService(graphqlClient, store)) + const runtime = usePersistentReactiveArrayService(`dashboard::global_runtimes::${currentSession?.id}`, (store) => new RuntimeService(graphqlClient, store)) + const project = usePersistentReactiveArrayService(`dashboard::projects::${currentSession?.id}`, (store) => new ProjectService(graphqlClient, store)) + const role = usePersistentReactiveArrayService(`dashboard::roles::${currentSession?.id}`, (store) => new RoleService(graphqlClient, store)) if (currentSession === null) router.push("/login") return - -
- {bar} - {tab} + +
+
+ +
- + {"CodeZero + {tab} + }> - - {children} - + {bar}}> + + <>{children} + + } diff --git a/src/app/(dashboard)/namespace/[namespaceId]/members/add/page.tsx b/src/app/(dashboard)/namespace/[namespaceId]/members/add/page.tsx index fafad442..a5186c72 100644 --- a/src/app/(dashboard)/namespace/[namespaceId]/members/add/page.tsx +++ b/src/app/(dashboard)/namespace/[namespaceId]/members/add/page.tsx @@ -1,6 +1,6 @@ "use client" -import {MemberAddPage} from "@edition/dashboard/member/MemberAddPage"; +import {MemberAddPage} from "@edition/member/pages/MemberAddPage"; export default function Page() { return diff --git a/src/app/(dashboard)/namespace/[namespaceId]/members/page.tsx b/src/app/(dashboard)/namespace/[namespaceId]/members/page.tsx index 7e92b720..3e37f24d 100644 --- a/src/app/(dashboard)/namespace/[namespaceId]/members/page.tsx +++ b/src/app/(dashboard)/namespace/[namespaceId]/members/page.tsx @@ -1,6 +1,6 @@ "use client" -import {MembersPage} from "@edition/dashboard/member/MembersPage"; +import {MembersPage} from "@edition/member/pages/MembersPage"; export default function Page() { return diff --git a/src/app/(dashboard)/namespace/[namespaceId]/page.tsx b/src/app/(dashboard)/namespace/[namespaceId]/page.tsx index a9a68513..dbfc7343 100644 --- a/src/app/(dashboard)/namespace/[namespaceId]/page.tsx +++ b/src/app/(dashboard)/namespace/[namespaceId]/page.tsx @@ -1,6 +1,6 @@ "use client" -import {NamespaceOverviewPage} from "@edition/dashboard/namespace/NamespaceOverviewPage"; +import {NamespaceOverviewPage} from "@edition/namespace/pages/NamespaceOverviewPage"; export default function Page() { return diff --git a/src/app/(dashboard)/namespace/[namespaceId]/projects/create/page.tsx b/src/app/(dashboard)/namespace/[namespaceId]/projects/create/page.tsx index 8211b5a4..9b9fff72 100644 --- a/src/app/(dashboard)/namespace/[namespaceId]/projects/create/page.tsx +++ b/src/app/(dashboard)/namespace/[namespaceId]/projects/create/page.tsx @@ -1,4 +1,4 @@ -import {NamespaceProjectsCreatePage} from "@edition/dashboard/namespace/NamespaceProjectsCreatePage"; +import {NamespaceProjectsCreatePage} from "@edition/namespace/pages/NamespaceProjectsCreatePage"; export default function Page() { return diff --git a/src/app/(dashboard)/namespace/[namespaceId]/projects/page.tsx b/src/app/(dashboard)/namespace/[namespaceId]/projects/page.tsx index 98e317e3..b6743871 100644 --- a/src/app/(dashboard)/namespace/[namespaceId]/projects/page.tsx +++ b/src/app/(dashboard)/namespace/[namespaceId]/projects/page.tsx @@ -1,4 +1,4 @@ -import {NamespaceProjectsPage} from "@edition/dashboard/namespace/NamespaceProjectsPage"; +import {NamespaceProjectsPage} from "@edition/namespace/pages/NamespaceProjectsPage"; export default function Page() { return diff --git a/src/app/(dashboard)/namespace/[namespaceId]/roles/[roleId]/settings/page.tsx b/src/app/(dashboard)/namespace/[namespaceId]/roles/[roleId]/settings/page.tsx index 4eed9bc3..db745576 100644 --- a/src/app/(dashboard)/namespace/[namespaceId]/roles/[roleId]/settings/page.tsx +++ b/src/app/(dashboard)/namespace/[namespaceId]/roles/[roleId]/settings/page.tsx @@ -1,6 +1,6 @@ "use client" -import {RoleSettingsPage} from "@edition/dashboard/role/RoleSettingsPage"; +import {RoleSettingsPage} from "@edition/role/pages/RoleSettingsPage"; export default function Page() { return diff --git a/src/app/(dashboard)/namespace/[namespaceId]/roles/create/page.tsx b/src/app/(dashboard)/namespace/[namespaceId]/roles/create/page.tsx index a4998c3c..320e44f5 100644 --- a/src/app/(dashboard)/namespace/[namespaceId]/roles/create/page.tsx +++ b/src/app/(dashboard)/namespace/[namespaceId]/roles/create/page.tsx @@ -1,6 +1,6 @@ "use client" -import {RoleCreatePage} from "@edition/dashboard/role/RoleCreatePage"; +import {RoleCreatePage} from "@edition/role/pages/RoleCreatePage"; export default function Page() { return diff --git a/src/app/(dashboard)/namespace/[namespaceId]/roles/page.tsx b/src/app/(dashboard)/namespace/[namespaceId]/roles/page.tsx index 1268e43b..68dd8172 100644 --- a/src/app/(dashboard)/namespace/[namespaceId]/roles/page.tsx +++ b/src/app/(dashboard)/namespace/[namespaceId]/roles/page.tsx @@ -1,5 +1,13 @@ -import {RolesPage} from "@edition/dashboard/role/RolesPage"; +import {RolesPage} from "@edition/role/pages/RolesPage"; export default function Page() { - return + return
+ +
} \ No newline at end of file diff --git a/src/app/(dashboard)/namespace/[namespaceId]/runtimes/[runtimeId]/settings/page.tsx b/src/app/(dashboard)/namespace/[namespaceId]/runtimes/[runtimeId]/settings/page.tsx index 94cdc737..1b30dce7 100644 --- a/src/app/(dashboard)/namespace/[namespaceId]/runtimes/[runtimeId]/settings/page.tsx +++ b/src/app/(dashboard)/namespace/[namespaceId]/runtimes/[runtimeId]/settings/page.tsx @@ -1,4 +1,4 @@ -import {RuntimeSettingsPage} from "@edition/dashboard/runtime/RuntimeSettingsPage"; +import {RuntimeSettingsPage} from "@edition/runtime/pages/RuntimeSettingsPage"; export default function Page() { return diff --git a/src/app/(dashboard)/namespace/[namespaceId]/runtimes/create/page.tsx b/src/app/(dashboard)/namespace/[namespaceId]/runtimes/create/page.tsx index 9063cb15..e149b9e1 100644 --- a/src/app/(dashboard)/namespace/[namespaceId]/runtimes/create/page.tsx +++ b/src/app/(dashboard)/namespace/[namespaceId]/runtimes/create/page.tsx @@ -1,4 +1,4 @@ -import {RuntimeCreatePage} from "@edition/dashboard/runtime/RuntimeCreatePage"; +import {RuntimeCreatePage} from "@edition/runtime/pages/RuntimeCreatePage"; export default function Page() { return diff --git a/src/app/(dashboard)/namespace/[namespaceId]/runtimes/page.tsx b/src/app/(dashboard)/namespace/[namespaceId]/runtimes/page.tsx index f9add133..27fcc879 100644 --- a/src/app/(dashboard)/namespace/[namespaceId]/runtimes/page.tsx +++ b/src/app/(dashboard)/namespace/[namespaceId]/runtimes/page.tsx @@ -1,4 +1,4 @@ -import {RuntimesPage} from "@edition/dashboard/runtime/RuntimesPage"; +import {RuntimesPage} from "@edition/runtime/pages/RuntimesPage"; export default function Page() { return diff --git a/src/app/(dashboard)/namespace/[namespaceId]/settings/page.tsx b/src/app/(dashboard)/namespace/[namespaceId]/settings/page.tsx index 201fd719..5421a642 100644 --- a/src/app/(dashboard)/namespace/[namespaceId]/settings/page.tsx +++ b/src/app/(dashboard)/namespace/[namespaceId]/settings/page.tsx @@ -1,6 +1,6 @@ "use client" -import {OrganizationSettingsPage} from "@edition/dashboard/organization/OrganizationSettingsPage"; +import {OrganizationSettingsPage} from "@edition/organization/pages/OrganizationSettingsPage"; export default function Page() { return diff --git a/src/app/(dashboard)/organizations/create/page.tsx b/src/app/(dashboard)/organizations/create/page.tsx index 70fbc55c..86e80fee 100644 --- a/src/app/(dashboard)/organizations/create/page.tsx +++ b/src/app/(dashboard)/organizations/create/page.tsx @@ -1,4 +1,4 @@ -import {OrganizationCreatePage} from "@edition/dashboard/organization/OrganizationCreatePage"; +import {OrganizationCreatePage} from "@edition/organization/pages/OrganizationCreatePage"; export default function Page() { return diff --git a/src/app/(dashboard)/organizations/page.tsx b/src/app/(dashboard)/organizations/page.tsx index d0aed06b..e49f829e 100644 --- a/src/app/(dashboard)/organizations/page.tsx +++ b/src/app/(dashboard)/organizations/page.tsx @@ -1,4 +1,4 @@ -import {OrganizationsPage} from "@edition/dashboard/organization/OrganizationsPage"; +import {OrganizationsPage} from "@edition/organization/pages/OrganizationsPage"; export default function Page() { return diff --git a/src/app/(dashboard)/page.tsx b/src/app/(dashboard)/page.tsx index 27103554..f3fe6f60 100644 --- a/src/app/(dashboard)/page.tsx +++ b/src/app/(dashboard)/page.tsx @@ -1,7 +1,7 @@ "use client" import React from "react"; -import {ApplicationPage} from "@edition/dashboard/application/ApplicationPage"; +import {ApplicationPage} from "@edition/application/ApplicationPage"; export default function Page() { return diff --git a/src/app/(dashboard)/runtimes/[runtimeId]/settings/page.tsx b/src/app/(dashboard)/runtimes/[runtimeId]/settings/page.tsx index 94cdc737..1b30dce7 100644 --- a/src/app/(dashboard)/runtimes/[runtimeId]/settings/page.tsx +++ b/src/app/(dashboard)/runtimes/[runtimeId]/settings/page.tsx @@ -1,4 +1,4 @@ -import {RuntimeSettingsPage} from "@edition/dashboard/runtime/RuntimeSettingsPage"; +import {RuntimeSettingsPage} from "@edition/runtime/pages/RuntimeSettingsPage"; export default function Page() { return diff --git a/src/app/(dashboard)/runtimes/create/page.tsx b/src/app/(dashboard)/runtimes/create/page.tsx index 9063cb15..e149b9e1 100644 --- a/src/app/(dashboard)/runtimes/create/page.tsx +++ b/src/app/(dashboard)/runtimes/create/page.tsx @@ -1,4 +1,4 @@ -import {RuntimeCreatePage} from "@edition/dashboard/runtime/RuntimeCreatePage"; +import {RuntimeCreatePage} from "@edition/runtime/pages/RuntimeCreatePage"; export default function Page() { return diff --git a/src/app/(dashboard)/runtimes/page.tsx b/src/app/(dashboard)/runtimes/page.tsx index 48bde090..b0f607f2 100644 --- a/src/app/(dashboard)/runtimes/page.tsx +++ b/src/app/(dashboard)/runtimes/page.tsx @@ -1,6 +1,6 @@ "use client" -import {RuntimesPage} from "@edition/dashboard/runtime/RuntimesPage"; +import {RuntimesPage} from "@edition/runtime/pages/RuntimesPage"; export default function Page() { return diff --git a/src/app/(dashboard)/settings/page.tsx b/src/app/(dashboard)/settings/page.tsx index 6c13d1d1..47813a23 100644 --- a/src/app/(dashboard)/settings/page.tsx +++ b/src/app/(dashboard)/settings/page.tsx @@ -1,7 +1,7 @@ "use client" import React from "react"; -import {ApplicationSettingsPage} from "@edition/dashboard/application/ApplicationSettingsPage"; +import {ApplicationSettingsPage} from "@edition/application/ApplicationSettingsPage"; export default function Page() { diff --git a/src/app/(dashboard)/users/page.tsx b/src/app/(dashboard)/users/page.tsx index 14e72354..57051d43 100644 --- a/src/app/(dashboard)/users/page.tsx +++ b/src/app/(dashboard)/users/page.tsx @@ -1,4 +1,4 @@ -import {UsersPage} from "@edition/dashboard/user/UsersPage"; +import {UsersPage} from "@edition/user/pages/UsersPage"; export default function Page() { return diff --git a/src/app/(flow)/@bar/default.tsx b/src/app/(flow)/@bar/default.tsx new file mode 100644 index 00000000..99055c6e --- /dev/null +++ b/src/app/(flow)/@bar/default.tsx @@ -0,0 +1,10 @@ +"use client"; + +import React from "react"; +import {ApplicationBarView} from "@edition/application/ApplicationBarView"; + +const Page = () => { + return +} + +export default Page \ No newline at end of file diff --git a/src/app/(flow)/@tab/default.tsx b/src/app/(flow)/@tab/default.tsx new file mode 100644 index 00000000..ac3dd7f7 --- /dev/null +++ b/src/app/(flow)/@tab/default.tsx @@ -0,0 +1,5 @@ +"use client" + +export default function Page() { + return null +} \ No newline at end of file diff --git a/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/default.tsx b/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/default.tsx new file mode 100644 index 00000000..d2a8b584 --- /dev/null +++ b/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/default.tsx @@ -0,0 +1,61 @@ +"use client" + +import {Tab, TabList, TabTrigger} from "@code0-tech/pictor/dist/components/tab/Tab"; +import {Button, Text, Tooltip, TooltipContent, TooltipPortal, TooltipTrigger} from "@code0-tech/pictor"; +import {IconBuilding, IconHome, IconSettings} from "@tabler/icons-react"; +import React from "react"; +import {useParams, usePathname, useRouter} from "next/navigation"; +import {hashToColor} from "@code0-tech/pictor/dist/components/d-flow/DFlow.util"; + +export default function Page() { + + + const pathname = usePathname() + const router = useRouter() + const params = useParams() + const defaultValue = pathname.includes("flow") ? "flow" + : "settings" + + const namespaceId = params.namespaceId as any + const projectId = params.projectId as any + const flowId = params.flowId as any + + return + + + + + + + + + + Flow builder + + + + + + + + + + + + Settings + + + + + +} \ No newline at end of file diff --git a/src/app/(flow)/layout.tsx b/src/app/(flow)/layout.tsx new file mode 100644 index 00000000..a2d853ff --- /dev/null +++ b/src/app/(flow)/layout.tsx @@ -0,0 +1,126 @@ +"use client" + +import {useApolloClient} from "@apollo/client/react"; +import {useParams, useRouter} from "next/navigation"; +import { + AuroraBackground, + ContextStoreProvider, + DataTypeView, + DLayout, + DNamespaceMemberView, + DNamespaceProjectView, + DNamespaceRoleView, + DNamespaceView, + DOrganizationView, + DRuntimeView, + DUserView, + Flex, + FlowTypeView, + FunctionDefinitionView, + useUserSession +} from "@code0-tech/pictor"; +import React from "react"; +import {GraphqlClient} from "@core/util/graphql-client"; +import {Flow, Namespace, NamespaceProject} from "@code0-tech/sagittarius-graphql-types"; +import {usePersistentReactiveArrayService} from "@/hooks/usePersistentReactiveArrayService"; +import {UserService} from "@edition/user/services/User.service"; +import {OrganizationService} from "@edition/organization/services/Organization.service"; +import {MemberService} from "@edition/member/services/Member.service"; +import {NamespaceService} from "@edition/namespace/services/Namespace.service"; +import {RuntimeService} from "@edition/runtime/services/Runtime.service"; +import {ProjectService} from "@edition/project/services/Project.service"; +import {RoleService} from "@edition/role/services/Role.service"; +import {FlowService} from "@edition/flow/services/Flow.service"; +import {FunctionService} from "@edition/function/services/Function.service"; +import {DatatypeService} from "@edition/datatype/services/Datatype.service"; +import {FlowTypeService} from "@edition/flowtype/services/FlowTypeService"; +import {FileTabsView} from "@code0-tech/pictor/dist/components/file-tabs/FileTabs.view"; +import {FileTabsService} from "@code0-tech/pictor/dist/components/file-tabs/FileTabs.service"; +import Image from "next/image"; + +export default function Layout({bar, tab, children}: { + bar: React.ReactNode, + tab: React.ReactNode, + children: React.ReactNode +}) { + const client = useApolloClient() + const router = useRouter() + const params = useParams() + const currentSession = useUserSession() + + const graphqlClient = React.useMemo(() => new GraphqlClient(client), [client]) + + const namespaceIndex = params.namespaceId as any as number + const projectIndex = params.projectId as any as number + const flowIndex = params.flowId as any as number + const namespaceId: Namespace['id'] = `gid://sagittarius/Namespace/${namespaceIndex}` + const projectId: NamespaceProject['id'] = `gid://sagittarius/NamespaceProject/${projectIndex}` + const flowId: Flow['id'] = `gid://sagittarius/Flow/${flowIndex}` + + if (currentSession === null) router.push("/login") + + const user = usePersistentReactiveArrayService(`dashboard::users::${currentSession?.id}`, (store) => new UserService(graphqlClient, store)) + const organization = usePersistentReactiveArrayService(`dashboard::organizations::${currentSession?.id}`, (store) => new OrganizationService(graphqlClient, store)) + const member = usePersistentReactiveArrayService(`dashboard::members::${currentSession?.id}`, (store) => new MemberService(graphqlClient, store)) + const namespace = usePersistentReactiveArrayService(`dashboard::namespaces::${currentSession?.id}`, (store) => new NamespaceService(graphqlClient, store)) + const runtime = usePersistentReactiveArrayService(`dashboard::global_runtimes::${currentSession?.id}`, (store) => new RuntimeService(graphqlClient, store)) + const project = usePersistentReactiveArrayService(`dashboard::projects::${currentSession?.id}`, (store) => new ProjectService(graphqlClient, store)) + const role = usePersistentReactiveArrayService(`dashboard::roles::${currentSession?.id}`, (store) => new RoleService(graphqlClient, store)) + const flow = usePersistentReactiveArrayService(`dashboard::flows::${currentSession?.id}`, (store) => new FlowService(graphqlClient, store)) + const functions = usePersistentReactiveArrayService(`dashboard::functions::${currentSession?.id}`, (store) => new FunctionService(graphqlClient, store)) + const datatype = usePersistentReactiveArrayService(`dashboard::datatypes::${currentSession?.id}`, (store) => new DatatypeService(graphqlClient, store)) + const flowtype = usePersistentReactiveArrayService(`dashboard::flowtypes::${currentSession?.id}`, (store) => new FlowTypeService(graphqlClient, store)) + const file = usePersistentReactiveArrayService(`dashboard::files::${flowId}`, FileTabsService, []) + + + const runtimeId = React.useMemo(() => project[1].getById(projectId, {namespaceId})?.primaryRuntime?.id, [projectId, project[0], namespaceId]) + + React.useEffect(() => { + if (!currentSession) return + + flow[1].values({namespaceId, projectId}) + functions[1].values({namespaceId, projectId, runtimeId}) + datatype[1].values({namespaceId, projectId, runtimeId}) + flowtype[1].values({namespaceId, projectId, runtimeId}) + }, [runtimeId, namespaceId, projectId, currentSession, flow, functions, datatype, flowtype]) + + return + +
+
+ + +
+ {"CodeZero + {tab} + + }> + {bar}}> + + <> + {children} + + + + + +} \ No newline at end of file diff --git a/src/app/(flow)/namespace/[namespaceId]/project/[projectId]/flow/[flowId]/page.tsx b/src/app/(flow)/namespace/[namespaceId]/project/[projectId]/flow/[flowId]/page.tsx new file mode 100644 index 00000000..3ac5b622 --- /dev/null +++ b/src/app/(flow)/namespace/[namespaceId]/project/[projectId]/flow/[flowId]/page.tsx @@ -0,0 +1,59 @@ +"use client" + +import { + Button, + DFlow, + DFlowTabs, + DLayout, + DResizableHandle, + DResizablePanel, + DResizablePanelGroup, + Flex, + Text +} from "@code0-tech/pictor"; +import React from "react"; +import {IconDatabase, IconFile, IconMessageChatbot} from "@tabler/icons-react"; +import {useParams} from "next/navigation"; +import {Flow} from "@code0-tech/sagittarius-graphql-types"; + +export default function Page() { + + const params = useParams() + + const flowIndex = params.flowId as any as number + const flowId: Flow['id'] = `gid://sagittarius/Flow/${flowIndex}` + + const [show, setShow] = React.useState(false); + + return + + + + + + }> + + + + + {show && ( + <> + + + + + + )} + + + +} \ No newline at end of file diff --git a/src/app/(flow)/namespace/[namespaceId]/project/[projectId]/flow/layout.tsx b/src/app/(flow)/namespace/[namespaceId]/project/[projectId]/flow/layout.tsx new file mode 100644 index 00000000..ae24ca0d --- /dev/null +++ b/src/app/(flow)/namespace/[namespaceId]/project/[projectId]/flow/layout.tsx @@ -0,0 +1,22 @@ +"use client" + +import React from "react"; +import {DResizableHandle, DResizablePanel, DResizablePanelGroup} from "@code0-tech/pictor"; +import {FlowFolderView} from "@edition/flow/views/FlowFolderView"; + +interface ApplicationLayoutProps { + children: React.ReactNode +} + +const ApplicationLayout: React.FC = ({children}) => { + + return + + + + + {children} + +} + +export default ApplicationLayout diff --git a/src/app/(flow)/namespace/[namespaceId]/project/[projectId]/flow/page.tsx b/src/app/(flow)/namespace/[namespaceId]/project/[projectId]/flow/page.tsx new file mode 100644 index 00000000..2022222c --- /dev/null +++ b/src/app/(flow)/namespace/[namespaceId]/project/[projectId]/flow/page.tsx @@ -0,0 +1,71 @@ +"use client" + +import { + Button, + Col, + DResizablePanel, + Flex, + ScrollArea, + ScrollAreaScrollbar, + ScrollAreaThumb, + ScrollAreaViewport, + Spacing, + Text +} from "@code0-tech/pictor"; +import React from "react"; +import Link from "next/link"; +import {useParams} from "next/navigation"; + +export default function Page() { + + const params = useParams() + + const namespaceIndex = params?.namespaceId as any as number + + return + + + + + Create or select a flow + + + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor + invidunt ut + labore et dolore magna aliquyam erat, sed diam voluptua. + + + + + + + + + + Or start from a template + + + + + + + +
+ +} \ No newline at end of file diff --git a/src/app/(flow)/namespace/[namespaceId]/project/[projectId]/settings/page.tsx b/src/app/(flow)/namespace/[namespaceId]/project/[projectId]/settings/page.tsx new file mode 100644 index 00000000..17a4168e --- /dev/null +++ b/src/app/(flow)/namespace/[namespaceId]/project/[projectId]/settings/page.tsx @@ -0,0 +1,8 @@ +"use client" + +import React from "react"; +import {ProjectSettingsPage} from "@edition/project/pages/ProjectSettingsPage"; + +export default function Page() { + return +} diff --git a/src/app/global.scss b/src/app/global.scss index 90ae320d..97d13f8e 100644 --- a/src/app/global.scss +++ b/src/app/global.scss @@ -3,7 +3,7 @@ } html, body { - background: #030014; + background: rgb(25.4, 23.6, 37.1); overflow-x: hidden; height: 100%; width: 100%; diff --git a/src/app/layout.tsx b/src/app/layout.tsx index e926e7a5..4e229cad 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -68,6 +68,7 @@ const ErrorCodeDescription: Record = { * Handles error toasts based on error type */ const toastHandler = (error: Error | GraphQLFormattedError) => { + console.error("[ERROR]", error) if (error && "errorCode" in error) { toast({ title: ErrorCodeDescription[(error.errorCode as string)], diff --git a/src/hooks/usePersistentReactiveArrayService.ts b/src/hooks/usePersistentReactiveArrayService.ts index a9e4d52c..0b4bf707 100644 --- a/src/hooks/usePersistentReactiveArrayService.ts +++ b/src/hooks/usePersistentReactiveArrayService.ts @@ -3,17 +3,18 @@ import React from "react"; import type {ArrayService} from "@code0-tech/pictor/dist/utils/arrayService"; import type {ReactiveArrayStore} from "@code0-tech/pictor/dist/utils/reactiveArrayService"; +import {Payload, View} from "@code0-tech/pictor/dist/utils/view"; -export type ArrayServiceCtor> = new (store: ReactiveArrayStore) => S; -export type ServiceFactory> = ArrayServiceCtor | ((store: ReactiveArrayStore) => S); -type InitialArg> = K[] | ((svc: S) => K[]); +export type ArrayServiceCtor, R>> = new (store: ReactiveArrayStore>) => S; +export type ServiceFactory, R>> = ArrayServiceCtor | ((store: ReactiveArrayStore>) => S); +type InitialArg, R>> = View[] | ((svc: S) => View[]); type Listener = () => void; -type PersistentEntry> = { +type PersistentEntry, R>> = { service: S; - store: ReactiveArrayStore; - getSnapshot: () => K[]; + store: ReactiveArrayStore>; + getSnapshot: () => View[]; listeners: Set; }; @@ -31,30 +32,30 @@ const registry = (): Registry => { return globalThis.__sculptorPersistentReactiveServices; }; -function isConstructor>(value: ServiceFactory): value is ArrayServiceCtor { +function isConstructor, R>>(value: ServiceFactory): value is ArrayServiceCtor { return typeof value === "function" && !!value.prototype && value.prototype.constructor === value; } -function instantiateService>(factory: ServiceFactory, store: ReactiveArrayStore): S { +function instantiateService, R>>(factory: ServiceFactory, store: ReactiveArrayStore>): S { return isConstructor(factory) ? new factory(store) : factory(store); } -function ensureEntry>(key: string, factory: ServiceFactory, initial: InitialArg): PersistentEntry { +function ensureEntry, R>>(key: string, factory: ServiceFactory, initial: InitialArg): PersistentEntry { const map = registry(); const existing = map.get(key); if (existing) { - return existing as PersistentEntry; + return existing as PersistentEntry; } const listeners = new Set(); - let snapshot: K[] = Array.isArray(initial) ? [...initial] : []; + let snapshot: View[] = Array.isArray(initial) ? [...initial] : []; - const store: ReactiveArrayStore = { + const store: ReactiveArrayStore> = { getState: () => snapshot, setState: (update) => { - snapshot = typeof update === "function" ? (update as (prev: K[]) => K[])(snapshot) : update; + snapshot = typeof update === "function" ? (update as (prev: View[]) => View[])(snapshot) : update; listeners.forEach((listener) => listener()); }, }; @@ -65,7 +66,7 @@ function ensureEntry>(key: string, factory: Service snapshot = initial(service); } - const entry: PersistentEntry = { + const entry: PersistentEntry = { service, store, getSnapshot: () => snapshot, @@ -76,11 +77,11 @@ function ensureEntry>(key: string, factory: Service return entry; } -export function usePersistentReactiveArrayService>( +export function usePersistentReactiveArrayService, R>>( key: string, - factory: ServiceFactory, - initial: InitialArg = [] -): [K[], S] { + factory: ServiceFactory, + initial: InitialArg = [] +): [View[], S] { const entry = React.useMemo(() => ensureEntry(key, factory, initial), [key, factory, initial]); const subscribe = React.useCallback((listener: Listener) => { diff --git a/src/packages/ce/src/dashboard/application/ApplicationBarView.tsx b/src/packages/ce/src/application/ApplicationBarView.tsx similarity index 56% rename from src/packages/ce/src/dashboard/application/ApplicationBarView.tsx rename to src/packages/ce/src/application/ApplicationBarView.tsx index 52822885..f16099f9 100644 --- a/src/packages/ce/src/dashboard/application/ApplicationBarView.tsx +++ b/src/packages/ce/src/application/ApplicationBarView.tsx @@ -1,35 +1,39 @@ "use client" import { + Avatar, Badge, - Breadcrumb, Button, - Container, + Button, Flex, MenuItem, MenuSeparator, - Text, TextInput, + TextInput, useService, + useStore, useUserSession } from "@code0-tech/pictor"; -import {UserService} from "@edition/user/User.service"; +import {UserService} from "@edition/user/services/User.service"; import {useRouter} from "next/navigation"; import React from "react"; import DUserMenu from "@code0-tech/pictor/dist/components/d-user/DUserMenu"; import Link from "next/link"; import {IconBuilding, IconFolders, IconInbox, IconLogout, IconSearch} from "@tabler/icons-react"; -import Image from "next/image"; -import {ApplicationBreadcrumbView} from "@edition/dashboard/application/ApplicationBreadcrumbView"; +import {ApplicationBreadcrumbView} from "@edition/application/ApplicationBreadcrumbView"; export const ApplicationBarView: React.FC = () => { + const currentSession = useUserSession() const userService = useService(UserService) + const userStore = useStore(UserService) const router = useRouter() const [loading, startTransition] = React.useTransition() + const currentUser = React.useMemo(() => userService.getById(currentSession?.user?.id), [userStore, currentSession]) + const namespaceIndex = React.useMemo(() => currentUser?.namespace?.id?.match(/Namespace\/(\d+)$/)?.[1], [currentUser]) const userMenu = React.useMemo(() => { - if (!currentSession?.token) { + if (!currentUser || !currentSession) { return null } @@ -44,8 +48,6 @@ export const ApplicationBarView: React.FC = () => { }) } - const namespaceIndex = currentSession.user?.namespace?.id?.match(/Namespace\/(\d+)$/)?.[1] - return @@ -62,25 +64,18 @@ export const ApplicationBarView: React.FC = () => { Logout - }, [currentSession]) + }, [currentUser, currentSession, namespaceIndex]) - return - - - - {"CodeZero - - - - } right={⌘K} rightType={"icon"} - placeholder={"Search..."}/> - - {userMenu} - - + return + + + + + {userMenu} - + } \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/application/ApplicationBreadcrumbView.tsx b/src/packages/ce/src/application/ApplicationBreadcrumbView.tsx similarity index 92% rename from src/packages/ce/src/dashboard/application/ApplicationBreadcrumbView.tsx rename to src/packages/ce/src/application/ApplicationBreadcrumbView.tsx index 19d1357c..e7320fd0 100644 --- a/src/packages/ce/src/dashboard/application/ApplicationBreadcrumbView.tsx +++ b/src/packages/ce/src/application/ApplicationBreadcrumbView.tsx @@ -4,12 +4,12 @@ import React from "react"; import {Badge, Breadcrumb, Text, useService, useStore} from "@code0-tech/pictor"; import {useParams, usePathname, useRouter} from "next/navigation"; import type {Namespace, NamespaceProject, NamespaceRole, Runtime, User} from "@code0-tech/sagittarius-graphql-types"; -import {NamespaceService} from "@edition/namespace/Namespace.service"; -import {RuntimeService} from "@edition/runtime/Runtime.service"; -import {UserService} from "@edition/user/User.service"; -import {ProjectService} from "@edition/project/Project.service"; -import {RoleService} from "@edition/role/Role.service"; -import {OrganizationService} from "@edition/organization/Organization.service"; +import {NamespaceService} from "@edition/namespace/services/Namespace.service"; +import {RuntimeService} from "@edition/runtime/services/Runtime.service"; +import {UserService} from "@edition/user/services/User.service"; +import {ProjectService} from "@edition/project/services/Project.service"; +import {RoleService} from "@edition/role/services/Role.service"; +import {OrganizationService} from "@edition/organization/services/Organization.service"; export const ApplicationBreadcrumbView: React.FC = () => { @@ -195,12 +195,13 @@ export const ApplicationBreadcrumbView: React.FC = () => { }, [pathSegments, collectionSegments, getSegmentLabel, resolveDestination]) return + router.push("/")}> + Home + {breadcrumbs.map((crumb, index) => { - return crumb.isBadge ? router.push(crumb.destination)}> - - {crumb.label} - - : router.push(crumb.destination)}> + return crumb.isBadge ? router.push(crumb.destination)}> + {crumb.label} + : router.push(crumb.destination)}> {crumb.label} })} diff --git a/src/packages/ce/src/application/ApplicationPage.tsx b/src/packages/ce/src/application/ApplicationPage.tsx new file mode 100644 index 00000000..4b2dc5f0 --- /dev/null +++ b/src/packages/ce/src/application/ApplicationPage.tsx @@ -0,0 +1,85 @@ +import {PersonalProjectsView} from "@edition/project/views/PersonalProjectsView"; +import {OrganizationsView} from "@edition/organization/views/OrganizationsView"; +import { + AuroraBackground, + Avatar, + Badge, + Card, + Col, + Flex, + Row, + ScrollArea, + ScrollAreaScrollbar, + ScrollAreaThumb, + ScrollAreaViewport, + Spacing, + Text, + useService, + useStore, + useUserSession +} from "@code0-tech/pictor"; +import {UserService} from "@edition/user/services/User.service"; +import React from "react"; +import {OrganizationsTopView} from "@edition/organization/views/OrganizationsTopView"; + +export const ApplicationPage = () => { + + const userStore = useStore(UserService) + const userService = useService(UserService) + + const userSession = useUserSession() + const currentUser = React.useMemo(() => userService.getById(userSession?.user?.id), [userStore, userSession]) + + return
+ + + + +
+ + + 👋 + +
+
+ + Hi, @{currentUser?.username ?? "user"}, + + let's write some flows +
+
+ + + + +
+ +
+ +
+ + + + + + +
+ +
+ + + +
+ + +
+ +} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/application/ApplicationSettingsPage.tsx b/src/packages/ce/src/application/ApplicationSettingsPage.tsx similarity index 66% rename from src/packages/ce/src/dashboard/application/ApplicationSettingsPage.tsx rename to src/packages/ce/src/application/ApplicationSettingsPage.tsx index c301b0c7..93c4a382 100644 --- a/src/packages/ce/src/dashboard/application/ApplicationSettingsPage.tsx +++ b/src/packages/ce/src/application/ApplicationSettingsPage.tsx @@ -5,9 +5,10 @@ import { Badge, Button, Card, - DLayout, + DResizableHandle, + DResizablePanel, + DResizablePanelGroup, Flex, - InputLabel, Spacing, SwitchInput, Text, @@ -15,10 +16,10 @@ import { useStore, useUserSession } from "@code0-tech/pictor"; -import {UserService} from "@edition/user/User.service"; +import {UserService} from "@edition/user/services/User.service"; import {notFound} from "next/navigation"; import {Tab, TabContent, TabList, TabTrigger} from "@code0-tech/pictor/dist/components/tab/Tab"; -import {IconGavel, IconSettings} from "@tabler/icons-react"; +import {IconLayoutSidebar} from "@tabler/icons-react"; import CardSection from "@code0-tech/pictor/dist/components/card/CardSection"; import process from "node:process"; @@ -32,33 +33,43 @@ export const ApplicationSettingsPage: React.FC = () => { notFound() } - return <> - - - - Application - - - - - - - - }> + + + General settings and restrictions for your Sculptor application. These settings affect all users + and organizations within the application. + + + + + + + + + + + + + <> General -
- - + @@ -94,10 +105,8 @@ export const ApplicationSettingsPage: React.FC = () => { Restrictions -
- - - + + Organization creation @@ -108,11 +117,8 @@ export const ApplicationSettingsPage: React.FC = () => { - - - Danger Zone -
- + + User registration @@ -121,12 +127,12 @@ export const ApplicationSettingsPage: React.FC = () => { - - + + - - - + + + } \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/application/ApplicationTabView.tsx b/src/packages/ce/src/application/ApplicationTabView.tsx similarity index 66% rename from src/packages/ce/src/dashboard/application/ApplicationTabView.tsx rename to src/packages/ce/src/application/ApplicationTabView.tsx index 5e1115d0..d0ab27c2 100644 --- a/src/packages/ce/src/dashboard/application/ApplicationTabView.tsx +++ b/src/packages/ce/src/application/ApplicationTabView.tsx @@ -5,9 +5,10 @@ import {Tab, TabList, TabTrigger} from "@code0-tech/pictor/dist/components/tab/T import {Badge, Button, Container, useService, useStore, useUserSession} from "@code0-tech/pictor"; import {IconBuilding, IconHome, IconServer, IconSettings, IconUser} from "@tabler/icons-react"; import {usePathname, useRouter} from "next/navigation"; -import {UserService} from "@edition/user/User.service"; -import {RuntimeService} from "@edition/runtime/Runtime.service"; -import {OrganizationService} from "@edition/organization/Organization.service"; +import {UserService} from "@edition/user/services/User.service"; +import {RuntimeService} from "@edition/runtime/services/Runtime.service"; +import {OrganizationService} from "@edition/organization/services/Organization.service"; +import {hashToColor} from "@code0-tech/pictor/dist/components/d-flow/DFlow.util"; export const ApplicationTabView: React.FC = () => { @@ -32,23 +33,18 @@ export const ApplicationTabView: React.FC = () => { return currentUser && currentUser.admin ? ( <> - - - @@ -56,24 +52,19 @@ export const ApplicationTabView: React.FC = () => { ) : null }, [currentUser, runtimeStore, organizationStore]) - return - + return - - {adminLinks} - } \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/application/ApplicationPage.tsx b/src/packages/ce/src/dashboard/application/ApplicationPage.tsx deleted file mode 100644 index 304d6e78..00000000 --- a/src/packages/ce/src/dashboard/application/ApplicationPage.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import {PersonalProjectsView} from "@edition/dashboard/personal-project/PersonalProjectsView"; -import {OrganizationsView} from "@edition/dashboard/organization/OrganizationsView"; -import {Spacing} from "@code0-tech/pictor"; - -export const ApplicationPage = () => { - - return <> - - - - - - - -} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/member/MemberAddPage.tsx b/src/packages/ce/src/dashboard/member/MemberAddPage.tsx deleted file mode 100644 index d7809127..00000000 --- a/src/packages/ce/src/dashboard/member/MemberAddPage.tsx +++ /dev/null @@ -1,96 +0,0 @@ -"use client" - -import React from "react"; -import { - Button, - Col, - DUserInput, - DUserView, - Flex, - InputSuggestion, - Spacing, - Text, - useForm, - useService, useStore -} from "@code0-tech/pictor"; -import {MemberService} from "@edition/member/Member.service"; -import {useParams, useRouter} from "next/navigation"; -import {Namespace} from "@code0-tech/sagittarius-graphql-types"; -import Link from "next/link"; -import {UserService} from "@edition/user/User.service"; - -export const MemberAddPage: React.FC = () => { - - const params = useParams() - const memberService = useService(MemberService) - const memberStore = useStore(MemberService) - const userService = useService(UserService) - const userStore = useStore(UserService) - const router = useRouter() - const [, startTransition] = React.useTransition() - - const namespaceIndex = params?.namespaceId as string - const namespaceId: Namespace['id'] = `gid://sagittarius/Namespace/${namespaceIndex as unknown as number}` - - const members = React.useMemo(() => memberService.values({namespaceId: namespaceId}), [memberStore, userStore]) - const formInitialValues = React.useMemo(() => ({ users: null }), []) - const filteredUsers = React.useMemo(() => { - return (user: DUserView) => { - return !members.find(m => m.user?.id === user.id) - } - }, [members]) - - const [inputs, validate] = useForm<{ users: null | InputSuggestion[] }>({ - initialValues: formInitialValues, - validate: { - users: (value) => { - if (!value) return "Please select at least one user" - if (value.length <= 0) return "Please select at least one user" - return null - } - }, - onSubmit: (values) => { - startTransition(async () => { - for (const value of values.users!!) { - await memberService.memberInvite({ - namespaceId: namespaceId!!, - userId: (value.valueData as DUserView).id!! - }) - } - router.push(`/namespace/${namespaceIndex}/members`) - }) - } - }) - - //TODO: user abilities for add user as member within namespace - - return - - - Add new members - - - - Global runtimes are shared runtimes that can be used across multiple organizations. - - - {/*@ts-ignore*/} - - - - - - - - - - -} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/member/MembersPage.tsx b/src/packages/ce/src/dashboard/member/MembersPage.tsx deleted file mode 100644 index a201120d..00000000 --- a/src/packages/ce/src/dashboard/member/MembersPage.tsx +++ /dev/null @@ -1,8 +0,0 @@ -"use client" - -import {MembersView} from "@edition/dashboard/member/MembersView"; -import React from "react"; - -export const MembersPage: React.FC = () => { - return -} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/member/MembersView.tsx b/src/packages/ce/src/dashboard/member/MembersView.tsx deleted file mode 100644 index 807a386e..00000000 --- a/src/packages/ce/src/dashboard/member/MembersView.tsx +++ /dev/null @@ -1,53 +0,0 @@ -"use client" - -import React from "react"; -import {useParams} from "next/navigation"; -import {Button, DNamespaceMemberList, Flex, Spacing, Text, useService, useStore} from "@code0-tech/pictor"; -import Link from "next/link"; -import {MemberService} from "@edition/member/Member.service"; - -export const MembersView: React.FC = () => { - - const params = useParams() - const namespaceId = params.namespaceId as any as number - const memberService = useService(MemberService) - const memberStore = useStore(MemberService) - const [, startTransition] = React.useTransition() - - const membersList = React.useMemo(() => { - return { - startTransition(() => { - memberService.memberAssignRoles({ - memberId: member.id!, - roleIds: roles.map(r => r.id!) - }) - }) - }} onRemove={(member) => { - startTransition(() => { - memberService.memberDelete({ - namespaceMemberId: member.id! - }) - }) - }} namespaceId={`gid://sagittarius/Namespace/${namespaceId}`}/> - }, [namespaceId, memberStore]) - - //TODO: user abilities for add user as member within namespace - - return <> - - - - Members - - - - - - - - - {membersList} - - - -} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/namespace/NamespaceOverviewLeftView.tsx b/src/packages/ce/src/dashboard/namespace/NamespaceOverviewLeftView.tsx deleted file mode 100644 index dd812519..00000000 --- a/src/packages/ce/src/dashboard/namespace/NamespaceOverviewLeftView.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import React from "react"; -import {Avatar, Badge, Button, Flex, Spacing, Text, useService, useStore, useUserSession} from "@code0-tech/pictor"; -import {UserService} from "@edition/user/User.service"; -import {IconMail, IconSparkles, IconUser, IconUserCog} from "@tabler/icons-react"; -import {OrganizationService} from "@edition/organization/Organization.service"; - -export const NamespaceOverviewLeftView: React.FC = () => { - - const userService = useService(UserService) - const userStore = useStore(UserService) - const organizationService = useService(OrganizationService) - const organizationStore = useStore(OrganizationService) - const currentSession = useUserSession() - - const currentUser = React.useMemo(() => userService.getById(currentSession?.user?.id), [userStore, currentSession]) - const organizations = React.useMemo(() => organizationService.values(), [organizationStore]) - - return - - - - - {currentUser?.firstname} {currentUser?.lastname} - {currentUser?.email} - - - - - - - @{currentUser?.username} - - - - {currentUser?.admin ? Admin : - User} - - - - {currentUser?.email} - - - - {currentUser?.admin ? PRO : BASIC} - - - - - -
- - Organizations - - - {organizations.map(organization => { - return - })} - -
- -} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/namespace/NamespaceOverviewPage.tsx b/src/packages/ce/src/dashboard/namespace/NamespaceOverviewPage.tsx deleted file mode 100644 index d09fceea..00000000 --- a/src/packages/ce/src/dashboard/namespace/NamespaceOverviewPage.tsx +++ /dev/null @@ -1,26 +0,0 @@ -"use client" - -import React from "react"; -import {NamespaceProjectsView} from "@edition/dashboard/namespace/NamespaceProjectsView"; -import {DLayout, useService, useStore, useUserSession} from "@code0-tech/pictor"; -import {NamespaceOverviewRightView} from "@edition/dashboard/namespace/NamespaceOverviewRightView"; -import {NamespaceOverviewLeftView} from "@edition/dashboard/namespace/NamespaceOverviewLeftView"; -import {useParams} from "next/navigation"; -import {UserService} from "@edition/user/User.service"; - -export const NamespaceOverviewPage: React.FC = () => { - - const params = useParams() - const userService = useService(UserService) - const userStore = useStore(UserService) - const currentSession = useUserSession() - - const currentUser = React.useMemo(() => userService.getById(currentSession?.user?.id), [userStore, currentSession]) - const namespaceIndexCurrentUser = currentUser?.namespace?.id?.match(/Namespace\/(\d+)$/)?.[1] - const namespaceId = params.namespaceId as any as string - - return : undefined} - rightContent={}> - - -} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/namespace/NamespaceProjectsPage.tsx b/src/packages/ce/src/dashboard/namespace/NamespaceProjectsPage.tsx deleted file mode 100644 index c66e04c2..00000000 --- a/src/packages/ce/src/dashboard/namespace/NamespaceProjectsPage.tsx +++ /dev/null @@ -1,8 +0,0 @@ -"use client" - -import {NamespaceProjectsView} from "@edition/dashboard/namespace/NamespaceProjectsView"; -import React from "react"; - -export const NamespaceProjectsPage: React.FC = () => { - return -} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/namespace/NamespaceProjectsView.tsx b/src/packages/ce/src/dashboard/namespace/NamespaceProjectsView.tsx deleted file mode 100644 index 5a72aa44..00000000 --- a/src/packages/ce/src/dashboard/namespace/NamespaceProjectsView.tsx +++ /dev/null @@ -1,36 +0,0 @@ -"use client" - - -import React from "react"; -import {Button, DNamespaceProjectList, Flex, Spacing, Text} from "@code0-tech/pictor"; -import Link from "next/link"; -import {useParams} from "next/navigation"; - -export const NamespaceProjectsView: React.FC = () => { - - const params = useParams() - const namespaceId = params.namespaceId as any as number - - const projectsList = React.useMemo(() => { - return - }, [namespaceId]) - - //TODO: user abilities for project creation within namespace - - return <> - - - - Projects - - - - - - - - - {projectsList} - - -} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/namespace/NamespaceTabView.tsx b/src/packages/ce/src/dashboard/namespace/NamespaceTabView.tsx deleted file mode 100644 index 8c21c806..00000000 --- a/src/packages/ce/src/dashboard/namespace/NamespaceTabView.tsx +++ /dev/null @@ -1,103 +0,0 @@ -"use client" - -import React from "react"; -import {Badge, Button, Container, useService, useStore} from "@code0-tech/pictor"; -import {Tab, TabList, TabTrigger} from "@code0-tech/pictor/dist/components/tab/Tab"; -import {IconFolders, IconHome, IconServer, IconSettings, IconUserCog, IconUsers} from "@tabler/icons-react"; -import {useParams, usePathname, useRouter} from "next/navigation"; -import {NamespaceService} from "@edition/namespace/Namespace.service"; -import {OrganizationService} from "@edition/organization/Organization.service"; -import {ProjectService} from "@edition/project/Project.service"; -import {RoleService} from "@edition/role/Role.service"; -import {MemberService} from "@edition/member/Member.service"; -import {RuntimeService} from "@edition/runtime/Runtime.service"; - -export const NamespaceTabView: React.FC = () => { - - const pathname = usePathname() - const router = useRouter() - const params = useParams() - const namespaceId = params.namespaceId as any - - const namespaceService = useService(NamespaceService) - const namespaceStore = useStore(NamespaceService) - const organizationService = useService(OrganizationService) - const organizationStore = useStore(OrganizationService) - const projectService = useService(ProjectService) - const roleService = useService(RoleService) - const memberService = useService(MemberService) - const runtimeService = useService(RuntimeService) - const runtimeStore = useStore(RuntimeService) - - const namespace = React.useMemo(() => namespaceService.getById(`gid://sagittarius/Namespace/${namespaceId}`), [namespaceStore, namespaceId]) - const parentOrganization = React.useMemo(() => namespace?.parent?.__typename === "Organization" ? organizationService.getById(namespace?.parent?.id) : null, [organizationStore, namespace]) - - const baseLink = `/namespace/${namespaceId}` - const defaultValue = pathname.includes("projects") ? "projects" - : pathname.includes("members") ? "members" - : pathname.includes("roles") ? "roles" - : pathname.includes("runtimes") ? "runtimes" - : pathname.includes("settings") ? "settings" - : "overview" - - const settings = React.useMemo(() => { - return namespace?.parent?.__typename == "Organization" - && parentOrganization - && ( - parentOrganization.userAbilities?.deleteOrganization - || parentOrganization?.userAbilities?.updateOrganization - //TODO add license check for enterprise features - ) ? ( - - - - ) : null - }, [namespace, parentOrganization]) - - return - - - - - - - - - - - - - - - - - - {settings} - - - -} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/organization/OrganizationCreatePage.tsx b/src/packages/ce/src/dashboard/organization/OrganizationCreatePage.tsx deleted file mode 100644 index 9970b594..00000000 --- a/src/packages/ce/src/dashboard/organization/OrganizationCreatePage.tsx +++ /dev/null @@ -1,66 +0,0 @@ -"use client" - -import {Button, Col, Flex, Spacing, Text, TextInput, useForm, useService} from "@code0-tech/pictor"; -import Link from "next/link"; -import {OrganizationService} from "@edition/organization/Organization.service"; -import React from "react"; -import {useRouter} from "next/navigation"; - -export const OrganizationCreatePage = () => { - - const organizationService = useService(OrganizationService) - const [, startTransition] = React.useTransition() - const router = useRouter() - - const [inputs, validate] = useForm({ - initialValues: { - name: null, - }, - validate: { - name: (value) => { - if (!value) return "Name is required" - return null - } - }, - onSubmit: (values) => { - startTransition(() => { - organizationService.organizationCreate({ - name: values.name as unknown as string - }).then(payload => { - if ((payload?.errors?.length ?? 0) <= 0) { - router.push("/organizations") - } - }) - }) - } - }) - - return - - - Create new organization - - - - Organizations are helpfully if managing a group of users and plenty of projects. - - - - - - - - - - - - -} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/organization/OrganizationSettingsPage.tsx b/src/packages/ce/src/dashboard/organization/OrganizationSettingsPage.tsx deleted file mode 100644 index 92c36b27..00000000 --- a/src/packages/ce/src/dashboard/organization/OrganizationSettingsPage.tsx +++ /dev/null @@ -1,117 +0,0 @@ -"use client" - -import React from "react"; -import {useParams} from "next/navigation"; -import {Namespace} from "@code0-tech/sagittarius-graphql-types"; -import { - AuroraBackground, - Avatar, - Badge, - Button, - DLayout, - Flex, - Spacing, - Text, - useService, - useStore -} from "@code0-tech/pictor"; -import {NamespaceService} from "@edition/namespace/Namespace.service"; -import {OrganizationService} from "@edition/organization/Organization.service"; -import {IconFolders, IconServer, IconUserCog, IconUsers} from "@tabler/icons-react"; -import {Tab, TabContent, TabList, TabTrigger} from "@code0-tech/pictor/dist/components/tab/Tab"; -import {UsageView} from "@edition/dashboard/usage/UsageView"; -import {OrganizationUpgradeView} from "@edition/dashboard/organization/OrganizationUpgradeView"; -import {OrganizationDeleteView} from "@edition/dashboard/organization/OrganizationDeleteView"; -import {OrganizationGeneralSettingsView} from "@edition/dashboard/organization/OrganizationGeneralSettingsView"; - -export const OrganizationSettingsPage: React.FC = () => { - - //TODO: add ability check for organization settings access for every settings tab - - const params = useParams() - const namespaceService = useService(NamespaceService) - const namespaceStore = useStore(NamespaceService) - const organizationService = useService(OrganizationService) - const organizationStore = useStore(OrganizationService) - - const namespaceIndex = params.namespaceId as any as number - const namespaceId: Namespace['id'] = `gid://sagittarius/Namespace/${namespaceIndex}` - const namespace = React.useMemo(() => namespaceService.getById(namespaceId), [namespaceStore, namespaceId]) - const parentOrganization = React.useMemo(() => namespace?.parent?.__typename === "Organization" ? organizationService.getById(namespace?.parent?.id) : null, [organizationStore, namespace]) - - return <> - - {React.useMemo(() => { - return - - - - {parentOrganization?.name} - - - - - {namespace?.members?.count} - - - - {namespace?.projects?.count} - - - - {namespace?.roles?.count} - - - - {namespace?.runtimes?.count} - - - - - }, [parentOrganization])} - - - - - - - - - - - - - - - - - }> - <> - - - - - - - - - - - - - - - - -} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/organization/OrganizationsPage.tsx b/src/packages/ce/src/dashboard/organization/OrganizationsPage.tsx deleted file mode 100644 index cf663f27..00000000 --- a/src/packages/ce/src/dashboard/organization/OrganizationsPage.tsx +++ /dev/null @@ -1,8 +0,0 @@ -"use client" - -import React from "react"; -import {OrganizationsView} from "@edition/dashboard/organization/OrganizationsView"; - -export const OrganizationsPage = () => { - return -} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/organization/OrganizationsView.tsx b/src/packages/ce/src/dashboard/organization/OrganizationsView.tsx deleted file mode 100644 index c43533f5..00000000 --- a/src/packages/ce/src/dashboard/organization/OrganizationsView.tsx +++ /dev/null @@ -1,32 +0,0 @@ -"use client" - -import {Button, DOrganizationList, Flex, Spacing, Text, TextInput} from "@code0-tech/pictor"; -import {IconSearch} from "@tabler/icons-react"; -import Link from "next/link"; -import React from "react"; -import {useRouter} from "next/navigation"; - -export const OrganizationsView = () => { - - const router = useRouter() - - return <> - - - Organizations - - - - - - - - - {/**TODO: use namespaceId*/} - { - const number = organization.namespace?.id?.match(/Namespace\/(\d+)$/)?.[1] - router.push(`/namespace/${number}`) - }}/> - - -} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/personal-project/PersonalProjectsView.tsx b/src/packages/ce/src/dashboard/personal-project/PersonalProjectsView.tsx deleted file mode 100644 index 9eeb08cd..00000000 --- a/src/packages/ce/src/dashboard/personal-project/PersonalProjectsView.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import React from "react"; -import { - Button, - DNamespaceProjectList, - Flex, - Spacing, - Text, - TextInput, - useService, - useStore, - useUserSession -} from "@code0-tech/pictor"; -import {UserService} from "@edition/user/User.service"; -import {IconSearch} from "@tabler/icons-react"; -import Link from "next/link"; - -export const PersonalProjectsView: React.FC = () => { - - const userSession = useUserSession() - const userStore = useStore(UserService) - const userService = useService(UserService) - - const currentUser = React.useMemo(() => userService.getById(userSession?.user?.id), [userStore, userSession]) - const namespaceId = currentUser?.namespace?.id - const namespaceIndex = namespaceId?.match(/Namespace\/(\d+)$/)?.[1] - - const projectsList = React.useMemo(() => { - if (!currentUser || !currentUser.namespace) return null - return - - }, [currentUser]) - - return <> - - - - Personal projects - - - - - - - - - {projectsList} - - - -} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/role/RoleCreatePage.tsx b/src/packages/ce/src/dashboard/role/RoleCreatePage.tsx deleted file mode 100644 index 0fa649b0..00000000 --- a/src/packages/ce/src/dashboard/role/RoleCreatePage.tsx +++ /dev/null @@ -1,38 +0,0 @@ -"use client" - -import React from "react"; -import {Button, Col, Flex, Spacing, Text, TextInput} from "@code0-tech/pictor"; -import Link from "next/link"; - -export const RoleCreatePage: React.FC = () => { - - //TODO: user abilities for add role within namespace - - return - - - Create new role - - - - Global runtimes are shared runtimes that can be used across multiple organizations. - - - - - - - - - - - - -} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/role/RoleSettingsPage.tsx b/src/packages/ce/src/dashboard/role/RoleSettingsPage.tsx deleted file mode 100644 index 3f0b5808..00000000 --- a/src/packages/ce/src/dashboard/role/RoleSettingsPage.tsx +++ /dev/null @@ -1,73 +0,0 @@ -"use client" - -import React from "react"; -import type {Namespace, NamespaceRole} from "@code0-tech/sagittarius-graphql-types"; -import {useParams} from "next/navigation"; -import {Button, DLayout, Flex, Spacing, Text, useService, useStore} from "@code0-tech/pictor"; -import {RoleService} from "@edition/role/Role.service"; -import {Tab, TabList, TabTrigger} from "@code0-tech/pictor/dist/components/tab/Tab"; -import {RoleProjectView} from "@edition/dashboard/role/RoleProjectView"; -import {RolePermissionView} from "@edition/dashboard/role/RolePermissionView"; -import {RoleGeneralAdjustmentView} from "@edition/dashboard/role/RoleGeneralAdjustmentView"; -import {RoleDeleteView} from "@edition/dashboard/role/RoleDeleteView"; - -export const RoleSettingsPage: React.FC = () => { - - //TODO: limit tabs based on user abilities for roles - //TODO: add general adjustments tab for role name update - //TODO: delete role functionality as tab - - const params = useParams() - const roleService = useService(RoleService) - const roleStore = useStore(RoleService) - - const namespaceIndex = params.namespaceId as any as number - const roleIndex = params.roleId as any as number - const namespaceId: Namespace['id'] = `gid://sagittarius/Namespace/${namespaceIndex}` - const roleId: NamespaceRole['id'] = `gid://sagittarius/NamespaceRole/${roleIndex}` - - const role = React.useMemo(() => roleService.getById(roleId, {namespaceId: namespaceId}), [roleStore, roleId, namespaceId]) - - return <> - - - - {role?.name} - - - - - - - - - - - - - - - - - - - }> - <> - - - - - - - - -} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/role/RolesView.tsx b/src/packages/ce/src/dashboard/role/RolesView.tsx deleted file mode 100644 index d157f5f8..00000000 --- a/src/packages/ce/src/dashboard/role/RolesView.tsx +++ /dev/null @@ -1,41 +0,0 @@ -"use client" - -import React from "react"; -import {useParams, useRouter} from "next/navigation"; -import {Button, DNamespaceMemberList, DNamespaceRoleList, Flex, Spacing, Text, TextInput} from "@code0-tech/pictor"; -import {IconSearch} from "@tabler/icons-react"; -import Link from "next/link"; - -export const RolesView: React.FC = () => { - - const params = useParams() - const router = useRouter() - const namespaceId = params.namespaceId as any as number - - const rolesList = React.useMemo(() => { - return { - const roleIndex = role.id?.match(/NamespaceRole\/(\d+)$/)?.[1] - router.push(`/namespace/${namespaceId}/roles/${roleIndex}/settings`) - }} namespaceId={`gid://sagittarius/Namespace/${namespaceId}`}/> - }, [namespaceId]) - - //TODO: user abilities for add role within namespace - - return <> - - - - Roles - - - - - - - - - {rolesList} - - - -} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/runtime/RuntimesPage.tsx b/src/packages/ce/src/dashboard/runtime/RuntimesPage.tsx deleted file mode 100644 index ce7dd952..00000000 --- a/src/packages/ce/src/dashboard/runtime/RuntimesPage.tsx +++ /dev/null @@ -1,42 +0,0 @@ -"use client" - -import React from "react"; -import {Button, DRuntimeList, Flex, Spacing, Text, useService, useStore, useUserSession} from "@code0-tech/pictor"; -import Link from "next/link"; -import {notFound, useParams, useRouter} from "next/navigation"; -import {UserService} from "@edition/user/User.service"; - -export const RuntimesPage: React.FC = () => { - - const currentSession = useUserSession() - const userStore = useStore(UserService) - const userService = useService(UserService) - const currentUser = React.useMemo(() => userService.getById(currentSession?.user?.id), [userStore, currentSession]) - - const params = useParams() - const namespaceIndex = params.namespaceId as any as number - - if (!namespaceIndex && currentUser && !currentUser.admin) { - notFound() - } - - const router = useRouter() - return <> - - - Runtimes - - - - - - - - - namespaceIndex ? true : !runtime?.namespace?.id} onSetting={(runtime) => { - const number = runtime.id?.match(/Runtime\/(\d+)$/)?.[1] - router.push(namespaceIndex ? `/namespace/${namespaceIndex}/runtimes/${number}/settings` : `/runtimes/${number}/settings`) - }}/> - -} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/user/UsersPage.tsx b/src/packages/ce/src/dashboard/user/UsersPage.tsx deleted file mode 100644 index d015ff55..00000000 --- a/src/packages/ce/src/dashboard/user/UsersPage.tsx +++ /dev/null @@ -1,38 +0,0 @@ -"use client" - -import React from "react"; -import { - Button, - DUserList, - Flex, - Spacing, - Text, - TextInput, useService, useStore, useUserSession, -} from "@code0-tech/pictor"; -import {IconSearch} from "@tabler/icons-react"; -import {UserService} from "@edition/user/User.service"; -import {notFound} from "next/navigation"; -export const UsersPage: React.FC = () => { - - const currentSession = useUserSession() - const userStore = useStore(UserService) - const userService = useService(UserService) - const currentUser = React.useMemo(() => userService.getById(currentSession?.user?.id), [userStore, currentSession]) - - if (currentUser && !currentUser.admin) { - notFound() - } - - return <> - - - Users - - - - - - - - -} \ No newline at end of file diff --git a/src/packages/ce/src/datatype/Datatype.service.ts b/src/packages/ce/src/datatype/Datatype.service.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/packages/ce/src/datatype/services/Datatype.service.ts b/src/packages/ce/src/datatype/services/Datatype.service.ts new file mode 100644 index 00000000..61f546ec --- /dev/null +++ b/src/packages/ce/src/datatype/services/Datatype.service.ts @@ -0,0 +1,64 @@ +import { + DataTypeView, DFlowDataTypeDependencies, + DFlowDataTypeReactiveService, + ReactiveArrayStore +} from "@code0-tech/pictor"; +import {GraphqlClient} from "@core/util/graphql-client"; +import {DataType, Query} from "@code0-tech/sagittarius-graphql-types"; +import dataTypeQuery from "@edition/datatype/services/queries/DataTypes.query.graphql" +import {View} from "@code0-tech/pictor/dist/utils/view"; + +export class DatatypeService extends DFlowDataTypeReactiveService { + + private readonly client: GraphqlClient + private i = 0 + + constructor(client: GraphqlClient, store: ReactiveArrayStore>) { + super(store) + this.client = client + } + + values(dependencies?: DFlowDataTypeDependencies): DataTypeView[] { + const dataTypes = super.values() + if (!dependencies?.namespaceId || !dependencies.projectId || !dependencies.runtimeId) return dataTypes + + const namespaceId = dependencies.namespaceId + const projectId = dependencies.projectId + const runtimeId = dependencies.runtimeId + const filtered = dataTypes.filter(dataType => dataType.runtime?.id === runtimeId) + + if (filtered.length <= 0) { + this.client.query({ + query: dataTypeQuery, + variables: { + namespaceId: namespaceId, + projectId: projectId, + + firstDataType: 50, + afterDataType: null, + + firstDataTypeIdentifier: 50, + afterDataTypeIdentifier: null, + + firstRule: 50, + afterRule: null, + } + }).then(res => { + const nodes = res.data?.namespace?.project?.primaryRuntime?.dataTypes?.nodes ?? [] + nodes.forEach(dataType => { + if (dataType && !this.hasById(dataType.id)) { + this.set(this.i++, new View(new DataTypeView(dataType))) + } + }) + }) + } + + return filtered + } + + hasById(id: DataType["id"]): boolean { + const dataType = super.values().find(d => d.id === id) + return dataType !== undefined + } + +} \ No newline at end of file diff --git a/src/packages/ce/src/datatype/services/fragments/DataType.basic.fragment.graphql b/src/packages/ce/src/datatype/services/fragments/DataType.basic.fragment.graphql new file mode 100644 index 00000000..161c9b35 --- /dev/null +++ b/src/packages/ce/src/datatype/services/fragments/DataType.basic.fragment.graphql @@ -0,0 +1,30 @@ +fragment BasicDataType on DataType { + __typename + id + createdAt + updatedAt + identifier + genericKeys + variant + + + name { + __typename + code + content + } + aliases { + __typename + code + content + } + displayMessages { + __typename + code + content + } + + runtime { + id + } +} \ No newline at end of file diff --git a/src/packages/ce/src/datatype/services/fragments/DataType.fragment.graphql b/src/packages/ce/src/datatype/services/fragments/DataType.fragment.graphql new file mode 100644 index 00000000..b2f6cc6e --- /dev/null +++ b/src/packages/ce/src/datatype/services/fragments/DataType.fragment.graphql @@ -0,0 +1,58 @@ +#import "@edition/function/services/fragments/DataTypeIdentifier.fragment.graphql" +#import "./DataTypeRule.fragment.graphql" + +fragment DataType on DataType { + __typename + id + createdAt + updatedAt + identifier + genericKeys + variant + + + name { + __typename + code + content + } + aliases { + __typename + code + content + } + displayMessages { + __typename + code + content + } + + runtime { + id + } + + dataTypeIdentifiers (first: $firstDataTypeIdentifier, after: $afterDataTypeIdentifier) { + __typename + count + nodes { + ...DataTypeIdentifier + } + pageInfo { + endCursor + hasNextPage + } + } + + rules (first: $firstRule, after: $afterRule) { + __typename + count + nodes { + ...DataTypeRule + } + pageInfo { + endCursor + hasNextPage + } + } + +} \ No newline at end of file diff --git a/src/packages/ce/src/datatype/services/fragments/DataTypeRule.fragment.graphql b/src/packages/ce/src/datatype/services/fragments/DataTypeRule.fragment.graphql new file mode 100644 index 00000000..ccfd5ba6 --- /dev/null +++ b/src/packages/ce/src/datatype/services/fragments/DataTypeRule.fragment.graphql @@ -0,0 +1,48 @@ +fragment DataTypeRule on DataTypeRule { + __typename + id + variant + updatedAt + createdAt + config { + ... on DataTypeRulesContainsKeyConfig { + __typename + dataTypeIdentifierId + key + } + ... on DataTypeRulesContainsTypeConfig { + __typename + dataTypeIdentifierId + } + ... on DataTypeRulesParentTypeConfig { + __typename + dataTypeIdentifierId + } + ... on DataTypeRulesReturnTypeConfig { + __typename + dataTypeIdentifierId + } + ... on DataTypeRulesInputTypesConfig { + __typename + inputTypes { + __typename + inputIdentifier + dataTypeIdentifierId + } + } + ... on DataTypeRulesItemOfCollectionConfig { + __typename + items + } + ... on DataTypeRulesNumberRangeConfig { + __typename + from + steps + to + } + ... on DataTypeRulesRegexConfig { + __typename + pattern + } + } +} \ No newline at end of file diff --git a/src/packages/ce/src/datatype/services/queries/DataTypes.query.graphql b/src/packages/ce/src/datatype/services/queries/DataTypes.query.graphql new file mode 100644 index 00000000..003e1255 --- /dev/null +++ b/src/packages/ce/src/datatype/services/queries/DataTypes.query.graphql @@ -0,0 +1,30 @@ +#import "../fragments/DataType.fragment.graphql" + +query DataTypes ( + $namespaceId: NamespaceID! + $projectId: NamespaceProjectID! + $firstDataType: Int! + $afterDataType: String + $firstDataTypeIdentifier: Int! + $afterDataTypeIdentifier: String + $firstRule: Int! + $afterRule: String +) { + namespace(id: $namespaceId) { + project(id: $projectId) { + primaryRuntime { + dataTypes (first: $firstDataType, after: $afterDataType) { + __typename + count + nodes { + ...DataType + } + pageInfo { + endCursor + hasNextPage + } + } + } + } + } +} \ No newline at end of file diff --git a/src/packages/ce/src/flow/Flow.service.ts b/src/packages/ce/src/flow/Flow.service.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/packages/ce/src/flow/components/FlowCreateDialogComponent.tsx b/src/packages/ce/src/flow/components/FlowCreateDialogComponent.tsx new file mode 100644 index 00000000..44f46e47 --- /dev/null +++ b/src/packages/ce/src/flow/components/FlowCreateDialogComponent.tsx @@ -0,0 +1,226 @@ +import React, {startTransition} from "react"; +import {FlowType, NamespaceProject} from "@code0-tech/sagittarius-graphql-types"; +import {IconArrowDown, IconArrowUp, IconCornerDownLeft, IconFile} from "@tabler/icons-react"; +import { + Badge, + Button, + Card, + Dialog, + DialogClose, + DialogContent, + DialogOverlay, + DialogPortal, + Flex, + InputDescription, + InputLabel, + InputMessage, + Menu, + MenuContent, + MenuItem, + MenuLabel, + MenuPortal, + MenuTrigger, + Spacing, + Text, + toast, + useForm, + useService, + useStore +} from "@code0-tech/pictor"; +import {hashToColor} from "@code0-tech/pictor/dist/components/d-flow/DFlow.util"; +import {FlowTypeService} from "@edition/flowtype/services/FlowTypeService"; +import {FlowNameInputComponent} from "@edition/flow/components/FlowNameInputComponent"; +import {ButtonGroup} from "@code0-tech/pictor/dist/components/button-group/ButtonGroup"; +import {useParams, useRouter} from "next/navigation"; +import {ProjectService} from "@edition/project/services/Project.service"; +import {RuntimeService} from "@edition/runtime/services/Runtime.service"; +import {FlowService} from "@edition/flow/services/Flow.service"; + +export interface FlowCreateDialogComponentProps { + open?: boolean + onOpenChange?: (open: boolean) => void + flowTypeId?: FlowType['id'] +} + +export const FlowCreateDialogComponent: React.FC = (props) => { + + const {open, onOpenChange, flowTypeId} = props + + const params = useParams() + const router = useRouter() + const flowService = useService(FlowService) + const flowTypeService = useService(FlowTypeService) + const flowTypeStore = useStore(FlowTypeService) + const projectService = useService(ProjectService) + const projectStore = useStore(ProjectService) + const runtimeService = useService(RuntimeService) + const runtimeStore = useStore(RuntimeService) + + const projectIndex = params.projectId as any as number + const projectId: NamespaceProject['id'] = `gid://sagittarius/NamespaceProject/${projectIndex}` + + const [createDialogOpen, setCreateDialogOpen] = React.useState(open) + const [selectedFlowTypeId, setSelectedFlowTypeId] = React.useState(flowTypeId) + + const selectedFlowType = React.useMemo(() => { + return flowTypeService.getById(selectedFlowTypeId) + }, [selectedFlowTypeId, flowTypeStore]) + + const initialValues = React.useMemo( + () => ({name: null, flowTypeId: flowTypeId ?? null}), + [] + ) + + const project = React.useMemo( + () => projectService.getById(projectId), + [projectStore, projectId] + ) + + const primaryRuntime = React.useMemo( + () => runtimeService.values({namespaceId: project?.namespace?.id}).find(runtime => runtime.id == project?.primaryRuntime?.id), + [project, runtimeStore] + ) + + const flowTypes = React.useMemo( + () => flowTypeService.values({runtimeId: primaryRuntime?.id, projectId: projectId, namespaceId: project?.namespace?.id}), + [flowTypeStore] + ) + + const createFlow = React.useCallback((name: string, type: FlowType['id']) => { + if (!type) return + startTransition(() => { + flowService.flowCreate({ + // @ts-ignore + flow: { + settings: [], + name: name, + type: type, + nodes: [], + }, + projectId: projectId + }).then(payload => { + if ((payload?.errors?.length ?? 0) <= 0) { + toast({ + title: "The flow was successfully created.", + color: "success", + dismissible: true, + }) + + } + }) + }) + }, []) + + React.useEffect(() => { + setCreateDialogOpen(open) + }, [open]) + + const [inputs, validate] = useForm({ + initialValues: initialValues, + validate: { + name: (value) => { + if (!value) return "Name is required" + return null + }, + flowTypeId: (value) => { + if (!value) return "Flow type is required" + return null + } + }, + onSubmit: (values) => { + createFlow?.(values.name!, values.flowTypeId) + onOpenChange?.(false) + } + }) + + return onOpenChange?.(open)}> + + + + + {!primaryRuntime ? <> + + You don't have a primary runtime yet, assign and/or create a runtime to be able to create flows. + + + + + + + + + + + + : ( + <> + Type of flow + You can choose a flow type here + + + + + + + + {flowTypes.map((flowType) => ( + { + inputs.getInputProps("flowTypeId").formValidation?.setValue(flowType.id) + setSelectedFlowTypeId(flowType.id) + }}> + {flowType.names?.[0].content} + + ))} + + + + + + + + + move + + + + + select + + + + + + + {!inputs.getInputProps("flowTypeId").formValidation?.valid ? + {inputs.getInputProps("flowTypeId").formValidation?.notValidMessage!} : null} + + + + + + + + + + + )} + + + +} \ No newline at end of file diff --git a/src/packages/ce/src/flow/components/FlowNameInputComponent.tsx b/src/packages/ce/src/flow/components/FlowNameInputComponent.tsx new file mode 100644 index 00000000..6aff18fc --- /dev/null +++ b/src/packages/ce/src/flow/components/FlowNameInputComponent.tsx @@ -0,0 +1,47 @@ +import React from "react"; +import {TextInputProps, InputSuggestion, InputSyntaxSegment, TextInput, Badge} from "@code0-tech/pictor" + +export interface FlowNameInputComponentProps extends TextInputProps { + +} + +export const FlowNameInputComponent: React.FC = (props) => { + + const {...rest} = props + + const transformSyntax = ( + value?: string | null, + _: (InputSuggestion | any)[] = [], + ): InputSyntaxSegment[] => { + + const normalizePath = (s: string) => { + const r = [], b = "" + let buf = b + s.split("").forEach(c => + c === "/" + ? (buf && r.push(buf), buf = "", r.push("/")) + : buf += c + ) + buf && r.push(buf) + return r + }; + const splitValue = normalizePath(value ?? "") + let cursor = 0 + + return splitValue.map((value, index) => { + const segment = { + type: splitValue.length - 1 !== index ? "block" : "text", + value: value, + start: cursor, + end: cursor + value.length, + visualLength: splitValue.length - 1 !== index ? 1 : value.length, + content: splitValue.length - 1 !== index ? {value} : value, + } + cursor += value.length + return [segment] + }).flat() as InputSyntaxSegment[] + + } + + return +} diff --git a/src/packages/ce/src/flow/services/Flow.service.ts b/src/packages/ce/src/flow/services/Flow.service.ts new file mode 100644 index 00000000..f7403d0a --- /dev/null +++ b/src/packages/ce/src/flow/services/Flow.service.ts @@ -0,0 +1,190 @@ +import {DFlowDependencies, DFlowReactiveService, ReactiveArrayStore} from "@code0-tech/pictor"; +import { + Flow, LiteralValue, + Mutation, + NamespacesProjectsFlowsCreateInput, + NamespacesProjectsFlowsCreatePayload, + NamespacesProjectsFlowsDeleteInput, + NamespacesProjectsFlowsDeletePayload, + NamespacesProjectsFlowsUpdateInput, + NamespacesProjectsFlowsUpdatePayload, + NodeFunction, NodeParameter, + Query, ReferenceValue +} from "@code0-tech/sagittarius-graphql-types"; +import {GraphqlClient} from "@core/util/graphql-client"; +import flowsQuery from "@edition/flow/services/queries/Flows.query.graphql"; +import flowCreateMutation from "@edition/flow/services/mutations/Flow.create.mutation.graphql"; +import flowDeleteMutation from "@edition/flow/services/mutations/Flow.delete.mutation.graphql"; +import flowUpdateMutation from "@edition/flow/services/mutations/Flow.update.mutation.graphql"; +import {View} from "@code0-tech/pictor/dist/utils/view"; + + +export class FlowService extends DFlowReactiveService { + + private readonly client: GraphqlClient + private flowUpdateQueue: Array + private i + + constructor(client: GraphqlClient, store: ReactiveArrayStore>) { + super(store) + this.client = client + this.flowUpdateQueue = [] + this.i = 0 + } + + values(dependencies?: DFlowDependencies): Flow[] { + const flows = super.values() + if (!dependencies?.namespaceId || !dependencies.projectId) return flows + + const namespaceId = dependencies.namespaceId + const projectId = dependencies.projectId + const filtered = flows.filter(flow => flow.project?.id === projectId) + + if (filtered.length <= 0) { + this.client.query({ + query: flowsQuery, + variables: { + namespaceId: namespaceId, + projectId: projectId, + + firstFlow: 50, + afterFlow: null, + + firstNode: 50, + afterNode: null, + + firstNodeParameter: 50, + afterNodeParameter: null, + + firstSetting: 50, + afterSetting: null, + + // firstInputDataTypeIdentifier: 50, + // afterInputDataTypeIdentifier: null, + // firstInputRule: 50, + // afterInputRule: null, + // + // firstReturnDataTypeIdentifier: 50, + // afterReturnDataTypeIdentifier: null, + // firstReturnRule: 50, + // afterReturnRule: null + } + }).then(res => { + const nodes = res.data?.namespace?.project?.flows?.nodes ?? [] + nodes.forEach(flow => { + if (flow && !this.hasById(flow.id)) { + this.set(this.i++, new View(flow)) + } + }) + }) + } + + return filtered + } + + hasById(id: Flow["id"]): boolean { + const flow = super.values().find(f => f.id === id) + return flow !== undefined + } + + + async addNextNodeById(flowId: Flow["id"], parentNodeId: NodeFunction["id"] | null, nextNode: NodeFunction): Promise { + await super.addNextNodeById(flowId, parentNodeId, nextNode) + await this.syncFlow(flowId) + } + + + async deleteNodeById(flowId: Flow["id"], nodeId: NodeFunction["id"]): Promise { + await super.deleteNodeById(flowId, nodeId) + await this.syncFlow(flowId) + } + + + async setParameterValue(flowId: Flow["id"], nodeId: NodeFunction["id"], parameterId: NodeParameter["id"], value?: LiteralValue | ReferenceValue | NodeFunction): Promise { + await super.setParameterValue(flowId, nodeId, parameterId, value) + await this.syncFlow(flowId) + } + + private async syncFlow(flowId: Flow["id"]) { + + const alreadyQueued = this.flowUpdateQueue.includes(flowId) + if (alreadyQueued) return Promise.resolve() + + this.flowUpdateQueue.push(flowId) + + setTimeout(async () => { + const flow = this.values().find(f => f.id === flowId) + const flowInput = this.getPayloadById(flowId) + + if (!flow || !flowInput || !flowId) return Promise.reject() + + await this.flowUpdate({ + flowId: flowId, + flowInput: flowInput + }) + + this.flowUpdateQueue.splice(this.flowUpdateQueue.indexOf(flowId), 1) + }, 1000*60) // 1 min + } + + async flowCreate(payload: NamespacesProjectsFlowsCreateInput): Promise { + const result = await this.client.mutate({ + mutation: flowCreateMutation, + variables: { + ...payload + } + }) + + if (result.data && result.data.namespacesProjectsFlowsCreate && result.data.namespacesProjectsFlowsCreate.flow) { + const flow = result.data.namespacesProjectsFlowsCreate.flow + if (!this.hasById(flow.id)) { + flow.nodes = {nodes: []} //TODO: to avoid issues, when fixed in pictor + this.add(new View(flow)) + } + } + + return result.data?.namespacesProjectsFlowsCreate ?? undefined + } + + async flowDelete(payload: NamespacesProjectsFlowsDeleteInput): Promise { + const result = await this.client.mutate({ + mutation: flowDeleteMutation, + variables: { + ...payload + } + }) + + if (result.data && result.data.namespacesProjectsFlowsDelete && result.data.namespacesProjectsFlowsDelete.flow) { + const flow = result.data.namespacesProjectsFlowsDelete.flow + const index = this.values().findIndex(f => f.id === flow.id) + this.delete(index) + + } + + return result.data?.namespacesProjectsFlowsDelete ?? undefined + } + + async flowUpdate(payload: NamespacesProjectsFlowsUpdateInput): Promise { + + const flow = this.getById(payload.flowId) + + if (!flow) return Promise.reject() + + const result = await this.client.mutate({ + mutation: flowUpdateMutation, + variables: { + ...payload + } + }) + + if (result.data && result.data.namespacesProjectsFlowsUpdate && result.data.namespacesProjectsFlowsUpdate.flow) { + const flowIndex = this.values().findIndex(f => f.id === payload.flowId) + flow.updatedAt = result.data.namespacesProjectsFlowsUpdate.flow.updatedAt + flow.editedAt = undefined + this.set(flowIndex, new View(flow)) + } + + return result.data?.namespacesProjectsFlowsUpdate ?? undefined + } + +} \ No newline at end of file diff --git a/src/packages/ce/src/flow/services/fragments/Flow.basic.fragment.graphql b/src/packages/ce/src/flow/services/fragments/Flow.basic.fragment.graphql new file mode 100644 index 00000000..3825a5a7 --- /dev/null +++ b/src/packages/ce/src/flow/services/fragments/Flow.basic.fragment.graphql @@ -0,0 +1,28 @@ +fragment BasicFlow on Flow { + __typename + id + createdAt + inputType { + id + } + name + project { + __typename + id + } + returnType { + __typename + id + } + settings { + __typename + } + startingNodeId + type { + id + } + updatedAt + userAbilities { + deleteFlow + } +} \ No newline at end of file diff --git a/src/packages/ce/src/flow/services/fragments/Flow.fragment.graphql b/src/packages/ce/src/flow/services/fragments/Flow.fragment.graphql new file mode 100644 index 00000000..4ee62d16 --- /dev/null +++ b/src/packages/ce/src/flow/services/fragments/Flow.fragment.graphql @@ -0,0 +1,96 @@ +fragment Flow on Flow { + __typename + id + createdAt + name + nodes (first: $firstNode, after: $afterNode) { + __typename + nodes { + __typename + id + nextNodeId + createdAt + updatedAt + parameters (first: $firstNodeParameter, after: $afterNodeParameter) { + __typename + count + nodes { + __typename + id + updatedAt + createdAt + parameterDefinition { + __typename + id + identifier + createdAt + updatedAt + } + value { + __typename + ... on LiteralValue { + __typename + value + } + ... on NodeFunctionIdWrapper { + __typename + id + } + ... on ReferenceValue { + __typename + id + updatedAt + createdAt + nodeFunctionId + referencePath { + __typename + id + createdAt + updatedAt + arrayIndex + path + } + } + } + } + pageInfo { + endCursor + hasNextPage + } + } + functionDefinition { + __typename + id + identifier + } + } + } + project { + __typename + id + } + settings (first: $firstSetting, after: $afterSetting) { + __typename + count + nodes { + __typename + id + createdAt + updatedAt + flowSettingIdentifier + value + } + pageInfo { + endCursor + hasNextPage + } + } + startingNodeId + type { + id + } + updatedAt + userAbilities { + deleteFlow + } +} \ No newline at end of file diff --git a/src/packages/ce/src/flow/services/mutations/Flow.create.mutation.graphql b/src/packages/ce/src/flow/services/mutations/Flow.create.mutation.graphql new file mode 100644 index 00000000..80230877 --- /dev/null +++ b/src/packages/ce/src/flow/services/mutations/Flow.create.mutation.graphql @@ -0,0 +1,20 @@ +#import "../fragments/Flow.basic.fragment.graphql" + +mutation flowCreate($flow: FlowInput!, $projectId: NamespaceProjectID!) { + namespacesProjectsFlowsCreate(input: { + flow: $flow, + projectId: $projectId + }) { + errors { + ...on Error { + errorCode, + details { + __typename + } + } + } + flow { + ...BasicFlow + } + } +} \ No newline at end of file diff --git a/src/packages/ce/src/flow/services/mutations/Flow.delete.mutation.graphql b/src/packages/ce/src/flow/services/mutations/Flow.delete.mutation.graphql new file mode 100644 index 00000000..4e35e339 --- /dev/null +++ b/src/packages/ce/src/flow/services/mutations/Flow.delete.mutation.graphql @@ -0,0 +1,19 @@ +#import "../fragments/Flow.basic.fragment.graphql" + +mutation flowDelete($flowId: FlowID!) { + namespacesProjectsFlowsDelete(input: { + flowId: $flowId + }) { + errors { + ...on Error { + errorCode, + details { + __typename + } + } + } + flow { + ...BasicFlow + } + } +} \ No newline at end of file diff --git a/src/packages/ce/src/flow/services/mutations/Flow.update.mutation.graphql b/src/packages/ce/src/flow/services/mutations/Flow.update.mutation.graphql new file mode 100644 index 00000000..c5a86084 --- /dev/null +++ b/src/packages/ce/src/flow/services/mutations/Flow.update.mutation.graphql @@ -0,0 +1,21 @@ +#import "../fragments/Flow.basic.fragment.graphql" + +mutation flowUpdate($flowId: FlowID!, $flowInput: FlowInput!) { + namespacesProjectsFlowsUpdate(input: { + flowId: $flowId + flowInput: $flowInput + }) { + errors { + ...on Error { + errorCode, + details { + ...on ActiveModelError { attribute type } + __typename + } + } + } + flow { + ...BasicFlow + } + } +} \ No newline at end of file diff --git a/src/packages/ce/src/flow/services/queries/Flows.query.graphql b/src/packages/ce/src/flow/services/queries/Flows.query.graphql new file mode 100644 index 00000000..a86754f9 --- /dev/null +++ b/src/packages/ce/src/flow/services/queries/Flows.query.graphql @@ -0,0 +1,40 @@ +#import "../fragments/Flow.fragment.graphql" + +query Flows ( + $namespaceId: NamespaceID! + $projectId: NamespaceProjectID! + $firstFlow: Int! + $afterFlow: String + $firstNode: Int!, + $afterNode: String, + $firstNodeParameter: Int!, + $afterNodeParameter: String, + + $firstSetting: Int!, + $afterSetting: String, + + #$firstInputDataTypeIdentifier: Int! + #$afterInputDataTypeIdentifier: String + #$firstInputRule: Int! + #$afterInputRule: String + + #$firstReturnDataTypeIdentifier: Int! + #$afterReturnDataTypeIdentifier: String + #$firstReturnRule: Int! + #$afterReturnRule: String +) { + namespace(id: $namespaceId) { + project(id: $projectId) { + flows (first: $firstFlow, after: $afterFlow) { + count + nodes { + ...Flow + } + pageInfo { + endCursor + hasNextPage + } + } + } + } +} \ No newline at end of file diff --git a/src/packages/ce/src/flow/views/FlowFolderView.tsx b/src/packages/ce/src/flow/views/FlowFolderView.tsx new file mode 100644 index 00000000..47f6638d --- /dev/null +++ b/src/packages/ce/src/flow/views/FlowFolderView.tsx @@ -0,0 +1,173 @@ +"use client" + +import React from "react"; +import { + Button, + DFlowFolder, + DFlowFolderDeleteDialog, + DFlowFolderHandle, + DLayout, + Flex, + Text, + toast, + Tooltip, + TooltipArrow, + TooltipContent, + TooltipPortal, + TooltipTrigger, + useService +} from "@code0-tech/pictor"; +import {IconArrowsMaximize, IconArrowsMinimize, IconCircleDot, IconLayoutSidebar, IconPlus} from "@tabler/icons-react"; +import {useParams, useRouter} from "next/navigation"; +import {Flow, FlowType} from "@code0-tech/sagittarius-graphql-types"; +import {FlowService} from "@edition/flow/services/Flow.service"; +import { + DFlowFolderContextMenuGroupData, + DFlowFolderContextMenuItemData +} from "@code0-tech/pictor/dist/components/d-flow-folder/DFlowFolderContextMenu"; +import {ButtonGroup} from "@code0-tech/pictor/dist/components/button-group/ButtonGroup"; +import {FlowCreateDialogComponent} from "@edition/flow/components/FlowCreateDialogComponent"; + +export const FlowFolderView: React.FC = () => { + + const router = useRouter() + const params = useParams() + const flowService = useService(FlowService) + + const namespaceIndex = params.namespaceId as any as number + const projectIndex = params.projectId as any as number + const flowIndex = params.flowId as any as number + const flowId: Flow['id'] = `gid://sagittarius/Flow/${flowIndex}` + + const [, startTransition] = React.useTransition() + const ref = React.useRef(null) + + const [createDialogOpen, setCreateDialogOpen] = React.useState(false) + const [flowTypeId, setFlowTypeId] = React.useState(undefined) + + const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false) + const [contextData, setContextData] = React.useState({ + flow: [], + name: "", + type: "folder" + }) + + const deleteFlow = React.useCallback((flow: Flow) => { + if (!flow?.id) return + startTransition(() => { + flowService.flowDelete({ + flowId: flow.id! + }).then(payload => { + if ((payload?.errors?.length ?? 0) <= 0) { + toast({ + title: "The flow was successfully deleted.", + color: "success", + dismissible: true, + }) + router.push(`/namespace/${namespaceIndex}/project/${projectIndex}/`) + } + }) + }) + }, []) + + return <> + + setCreateDialogOpen(open)} + flowTypeId={flowTypeId}/> + + setDeleteDialogOpen(open)} + contextData={contextData} + onDelete={deleteFlow}/> + + + + Explorer + + + + + + + + + + Add new flow + + + + + + + + + + + + Open active flow + + + + + + + + + + + Close all + + + + + + + + + + + Open all + + + + + + + + }> + { + const number = flow.id?.match(/Flow\/(\d+)$/)?.[1] + router.push(`/namespace/${namespaceIndex}/project/${projectIndex}/flow/${number}`) + }} + onCreate={flowTypeId => { + setCreateDialogOpen(true) + setFlowTypeId(flowTypeId) + }} + onDelete={contextData => { + setDeleteDialogOpen(true) + setContextData(contextData) + }} + namespaceId={`gid://sagittarius/Namespace/${namespaceIndex}`} + projectId={`gid://sagittarius/NamespaceProject/${projectIndex}`}/> + + +} \ No newline at end of file diff --git a/src/packages/ce/src/flowtype/Flowtype.service.ts b/src/packages/ce/src/flowtype/Flowtype.service.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/packages/ce/src/flowtype/services/FlowTypeService.ts b/src/packages/ce/src/flowtype/services/FlowTypeService.ts new file mode 100644 index 00000000..15824221 --- /dev/null +++ b/src/packages/ce/src/flowtype/services/FlowTypeService.ts @@ -0,0 +1,64 @@ +import {DFlowTypeDependencies, DFlowTypeReactiveService, FlowTypeView, ReactiveArrayStore} from "@code0-tech/pictor"; +import {GraphqlClient} from "@core/util/graphql-client"; +import {FlowType, Query} from "@code0-tech/sagittarius-graphql-types"; +import flowTypesQuery from "@edition/flowtype/services/queries/FlowTypes.query.graphql" +import {View} from "@code0-tech/pictor/dist/utils/view"; + +export class FlowTypeService extends DFlowTypeReactiveService { + + private readonly client: GraphqlClient + private i = 0 + + constructor(client: GraphqlClient, store: ReactiveArrayStore>) { + super(store) + this.client = client + } + + values(dependencies?: DFlowTypeDependencies): FlowTypeView[] { + const functions = super.values() + if (!dependencies?.runtimeId) return functions + + const namespaceId = dependencies.namespaceId + const projectId = dependencies.projectId + const runtimeId = dependencies.runtimeId + const filtered = functions.filter(flowType => flowType.runtime?.id === runtimeId) + + if (filtered.length <= 0 && namespaceId && projectId) { + this.client.query({ + query: flowTypesQuery, + variables: { + namespaceId: namespaceId, + projectId: projectId, + + firstFlowType: 50, + afterFlowType: null, + + firstInputDataTypeIdentifier: 50, + afterInputDataTypeIdentifier: null, + firstInputRule: 50, + afterInputRule: null, + + firstReturnDataTypeIdentifier: 50, + afterReturnDataTypeIdentifier: null, + firstReturnRule: 50, + afterReturnRule: null + } + }).then(res => { + const nodes = res.data?.namespace?.project?.primaryRuntime?.flowTypes?.nodes ?? [] + nodes.forEach(flowType => { + if (flowType && !this.hasById(flowType.id)) { + this.set(this.i++, new View(new FlowTypeView(flowType))) + } + }) + }) + } + + return filtered + } + + hasById(id: FlowType["id"]): boolean { + const flowType = super.values().find(f => f.id === id) + return flowType !== undefined + } + +} \ No newline at end of file diff --git a/src/packages/ce/src/flowtype/services/fragments/FlowType.fragment.graphql b/src/packages/ce/src/flowtype/services/fragments/FlowType.fragment.graphql new file mode 100644 index 00000000..b22d4754 --- /dev/null +++ b/src/packages/ce/src/flowtype/services/fragments/FlowType.fragment.graphql @@ -0,0 +1,112 @@ +#import "@edition/function/services/fragments/DataTypeIdentifier.fragment.graphql" +#import "@edition/datatype/services/fragments/DataType.basic.fragment.graphql" +#import "@edition/datatype/services/fragments/DataTypeRule.fragment.graphql" + +fragment FlowType on FlowType { + __typename + id + updatedAt + createdAt + identifier + names { + code + content + __typename + } + aliases { + code + content + __typename + } + displayMessages { + code + content + __typename + } + descriptions { + code + content + __typename + } + runtime { + id + } + inputType { + ...BasicDataType + dataTypeIdentifiers (first: $firstInputDataTypeIdentifier, after: $afterInputDataTypeIdentifier) { + __typename + count + nodes { + ...DataTypeIdentifier + } + pageInfo { + endCursor + hasNextPage + } + } + rules (first: $firstInputRule, after: $afterInputRule) { + __typename + count + nodes { + ...DataTypeRule + } + pageInfo { + endCursor + hasNextPage + } + } + + } + returnType { + ...BasicDataType + dataTypeIdentifiers (first: $firstReturnDataTypeIdentifier, after: $afterReturnDataTypeIdentifier) { + __typename + count + nodes { + ...DataTypeIdentifier + } + pageInfo { + endCursor + hasNextPage + } + } + rules (first: $firstReturnRule, after: $afterReturnRule) { + __typename + count + nodes { + ...DataTypeRule + } + pageInfo { + endCursor + hasNextPage + } + } + } + flowTypeSettings { + __typename + id + createdAt + updatedAt + identifier + unique + + + dataType { + id + } + + names { + __typename + code + content + } + descriptions { + __typename + code + content + } + + } + editable + +} \ No newline at end of file diff --git a/src/packages/ce/src/flowtype/services/queries/FlowTypes.query.graphql b/src/packages/ce/src/flowtype/services/queries/FlowTypes.query.graphql new file mode 100644 index 00000000..ef27cea5 --- /dev/null +++ b/src/packages/ce/src/flowtype/services/queries/FlowTypes.query.graphql @@ -0,0 +1,35 @@ +#import "../fragments/FlowType.fragment.graphql" + +query FlowTypes ( + $namespaceId: NamespaceID! + $projectId: NamespaceProjectID! + $firstFlowType: Int! + $afterFlowType: String + + $firstInputDataTypeIdentifier: Int! + $afterInputDataTypeIdentifier: String + $firstInputRule: Int! + $afterInputRule: String + + $firstReturnDataTypeIdentifier: Int! + $afterReturnDataTypeIdentifier: String + $firstReturnRule: Int! + $afterReturnRule: String +) { + namespace(id: $namespaceId) { + project(id: $projectId) { + primaryRuntime { + flowTypes (first: $firstFlowType, after: $afterFlowType) { + count + nodes { + ...FlowType + } + pageInfo { + endCursor + hasNextPage + } + } + } + } + } +} \ No newline at end of file diff --git a/src/packages/ce/src/function/Function.service.ts b/src/packages/ce/src/function/Function.service.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/packages/ce/src/function/services/Function.service.ts b/src/packages/ce/src/function/services/Function.service.ts new file mode 100644 index 00000000..c88beb79 --- /dev/null +++ b/src/packages/ce/src/function/services/Function.service.ts @@ -0,0 +1,65 @@ +import { + DFlowFunctionDependencies, + DFlowFunctionReactiveService, + FunctionDefinitionView, + ReactiveArrayStore +} from "@code0-tech/pictor"; +import {GraphqlClient} from "@core/util/graphql-client"; +import {FunctionDefinition, Query} from "@code0-tech/sagittarius-graphql-types"; +import functionsQuery from "@edition/function/services/queries/Functions.query.graphql"; +import {View} from "@code0-tech/pictor/dist/utils/view"; + +export class FunctionService extends DFlowFunctionReactiveService { + + private readonly client: GraphqlClient + private i = 0 + + constructor(client: GraphqlClient, store: ReactiveArrayStore>) { + super(store) + this.client = client + } + + values(dependencies?: DFlowFunctionDependencies): FunctionDefinitionView[] { + const functions = super.values() + if (!dependencies?.namespaceId || !dependencies.projectId || !dependencies.runtimeId) return functions + + const namespaceId = dependencies.namespaceId + const projectId = dependencies.projectId + const runtimeId = dependencies.runtimeId + const filtered = functions.filter(functionD => functionD.runtimeFunctionDefinition?.runtime?.id === runtimeId) + + if (filtered.length <= 0) { + this.client.query({ + query: functionsQuery, + variables: { + namespaceId: namespaceId, + projectId: projectId, + + firstFunction: 50, + afterFunction: null, + + firstDataTypeIdentifier: 50, + afterDataTypeIdentifier: null, + + firstParameterDefinition: 50, + afterParameterDefinition: null, + } + }).then(res => { + const nodes = res.data?.namespace?.project?.primaryRuntime?.functionDefinitions?.nodes ?? [] + nodes.forEach(functionD => { + if (functionD && !this.hasById(functionD.id)) { + this.set(this.i++, new View(new FunctionDefinitionView(functionD))) + } + }) + }) + } + + return filtered + } + + hasById(id: FunctionDefinition["id"]): boolean { + const functionD = super.values().find(f => f.id === id) + return functionD !== undefined + } + +} \ No newline at end of file diff --git a/src/packages/ce/src/function/services/fragments/DataTypeIdentifier.fragment.graphql b/src/packages/ce/src/function/services/fragments/DataTypeIdentifier.fragment.graphql new file mode 100644 index 00000000..22e34b04 --- /dev/null +++ b/src/packages/ce/src/function/services/fragments/DataTypeIdentifier.fragment.graphql @@ -0,0 +1,36 @@ +fragment DataTypeIdentifier on DataTypeIdentifier { + id + createdAt + updatedAt + genericKey + genericType { + id + updatedAt + createdAt + genericMappers { + id + target + sourceDataTypeIdentifierIds + updatedAt + createdAt + genericCombinationStrategies { + id + type + createdAt + updatedAt + __typename + } + __typename + } + dataType { + identifier + id + __typename + } + } + dataType { + id + identifier + } + __typename +} \ No newline at end of file diff --git a/src/packages/ce/src/function/services/fragments/Function.fragment.graphql b/src/packages/ce/src/function/services/fragments/Function.fragment.graphql new file mode 100644 index 00000000..47e49bd4 --- /dev/null +++ b/src/packages/ce/src/function/services/fragments/Function.fragment.graphql @@ -0,0 +1,126 @@ +fragment DataTypeIdentifier on DataTypeIdentifier { + id + createdAt + updatedAt + genericKey + genericType { + id + updatedAt + createdAt + genericMappers { + id + target + sourceDataTypeIdentifierIds + updatedAt + createdAt + genericCombinationStrategies { + id + type + createdAt + updatedAt + __typename + } + __typename + } + dataType { + identifier + id + __typename + } + } + dataType { + id + identifier + } + __typename +} + +fragment Function on FunctionDefinition { + id + createdAt + updatedAt + dataTypeIdentifiers (first: $firstDataTypeIdentifier, after: $afterDataTypeIdentifier) { + count + nodes { + ...DataTypeIdentifier + } + pageInfo { + endCursor + hasNextPage + } + __typename + } + aliases { + code + content + __typename + } + deprecationMessages { + code + content + __typename + } + descriptions { + code + content + __typename + } + documentations { + code + content + __typename + } + genericKeys + displayMessages { + code + content + __typename + } + identifier + names { + code + content + __typename + } + returnType { + ...DataTypeIdentifier + } + parameterDefinitions (first: $firstParameterDefinition, after: $afterParameterDefinition) { + nodes { + id + identifier + updatedAt + createdAt + identifier + names { + code + content + __typename + } + descriptions { + code + content + __typename + } + documentations { + code + content + __typename + } + dataTypeIdentifier { + ...DataTypeIdentifier + } + __typename + } + } + #throwsError + runtimeFunctionDefinition { + id + identifier + runtime { + id + } + __typename + } + __typename +} \ No newline at end of file diff --git a/src/packages/ce/src/function/services/queries/Functions.query.graphql b/src/packages/ce/src/function/services/queries/Functions.query.graphql new file mode 100644 index 00000000..55301aeb --- /dev/null +++ b/src/packages/ce/src/function/services/queries/Functions.query.graphql @@ -0,0 +1,29 @@ +#import "../fragments/Function.fragment.graphql" + +query Functions ( + $namespaceId: NamespaceID! + $projectId: NamespaceProjectID! + $firstFunction: Int! + $afterFunction: String + $firstDataTypeIdentifier: Int! + $afterDataTypeIdentifier: String + $firstParameterDefinition: Int! + $afterParameterDefinition: String +) { + namespace(id: $namespaceId) { + project(id: $projectId) { + primaryRuntime { + functionDefinitions (first: $firstFunction, after: $afterFunction) { + count + nodes { + ...Function + } + pageInfo { + endCursor + hasNextPage + } + } + } + } + } +} \ No newline at end of file diff --git a/src/packages/ce/src/member/components/MemberDataTableComponent.tsx b/src/packages/ce/src/member/components/MemberDataTableComponent.tsx new file mode 100644 index 00000000..b5278dfd --- /dev/null +++ b/src/packages/ce/src/member/components/MemberDataTableComponent.tsx @@ -0,0 +1,57 @@ +import React from "react"; +import {DataTable, DataTableColumn, Text, useService, useStore} from "@code0-tech/pictor"; +import {DataTableFilterProps, DataTableSortProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import { + Namespace, + NamespaceMember, + NamespaceProject, + NamespaceRole, + Runtime, + User +} from "@code0-tech/sagittarius-graphql-types"; +import {ProjectService} from "@edition/project/services/Project.service"; +import {ProjectDataTableRowComponent} from "@edition/project/components/ProjectDataTableRowComponent"; +import {RoleService} from "@edition/role/services/Role.service"; +import {RoleDataTableRowComponent} from "@edition/role/components/RoleDataTableRowComponent"; +import {RuntimeService} from "@edition/runtime/services/Runtime.service"; +import {RuntimeDataTableRowComponent} from "@edition/runtime/components/RuntimeDataTableRowComponent"; +import {UserDataTableRowComponent} from "@edition/user/components/UserDataTableRowComponent"; +import {UserService} from "@edition/user/services/User.service"; +import {MemberService} from "@edition/member/services/Member.service"; +import {MemberDataTableRowComponent} from "@edition/member/components/MemberDataTableRowComponent"; + +export interface MemberDataTableComponentProps { + namespaceId: Namespace['id'] + sort?: DataTableSortProps + filter?: DataTableFilterProps + preFilter?: (project: NamespaceMember, index: number) => boolean + onSelect?: (item: NamespaceMember | undefined) => void +} + +export const MemberDataTableComponent: React.FC = (props) => { + + const {namespaceId, sort, filter, preFilter = () => true, onSelect} = props + + const memberService = useService(MemberService) + const memberStore = useStore(MemberService) + + const members = React.useMemo( + () => memberService.values({namespaceId: namespaceId}), + [memberStore] + ) + + return + + No member found. Create one to get started. + + } + onSelect={(item) => item && onSelect?.(item)} + data={members.map(u => u.json()).filter(preFilter)}> + {(member, index) => { + return + }} + + +} \ No newline at end of file diff --git a/src/packages/ce/src/member/components/MemberDataTableFilterInputComponent.tsx b/src/packages/ce/src/member/components/MemberDataTableFilterInputComponent.tsx new file mode 100644 index 00000000..d62858f3 --- /dev/null +++ b/src/packages/ce/src/member/components/MemberDataTableFilterInputComponent.tsx @@ -0,0 +1,102 @@ +import React from "react"; +import { + DataTableFilterInput, + DataTableFilterSuggestionMenu, DRuntimeView, + MenuCheckboxItem, + useService, + useStore +} from "@code0-tech/pictor"; +import {IconCheck} from "@tabler/icons-react"; +import {Namespace, Runtime} from "@code0-tech/sagittarius-graphql-types"; +import {DataTableFilterProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import {RoleService} from "@edition/role/services/Role.service"; +import {RuntimeService} from "@edition/runtime/services/Runtime.service"; +import {UserService} from "@edition/user/services/User.service"; +import {MemberService} from "@edition/member/services/Member.service"; + +export interface MemberDataTableFilterInputComponentProps { + namespaceId: Namespace['id'] + onChange: (filter: DataTableFilterProps) => void +} + +export const MemberDataTableFilterInputComponent: React.FC = (props) => { + + const {namespaceId, onChange} = props + + const memberService = useService(MemberService) + const memberStore = useStore(MemberService) + const roleService = useService(RoleService) + const roleStore = useStore(RoleService) + + const members = React.useMemo( + () => memberService.values({namespaceId: namespaceId}), + [memberStore] + ) + + const roles = React.useMemo( + () => { + const roleIds = members.map(m => m.roles?.nodes?.map(r => r?.id)).flat() + return roleIds.map(id => roleService.getById(id)).filter(Boolean) + }, + [roleStore] + ) + + return { + + const split = currentValue.split(",").map(s => s.trim()).filter(Boolean) + + return + {members.map(member => { + + const isChecked = split.includes(member?.user?.username!) + + return { + e.preventDefault(); + e.stopPropagation(); + const updated = isChecked + ? split.filter(name => name !== member?.user?.username) + : [...split, member?.user?.username]; + applySuggestion(updated.join(","), true); + }}> + {isChecked ? : } + @{member?.user?.username} + + })} + + } + }, + { + token: "Roles", + key: "roles.nodes.name", + operators: ["isOneOf"], + suggestion: (context, operator, currentValue, applySuggestion) => { + + const split = currentValue.split(",").map(s => s.trim()).filter(Boolean) + + return + {roles.map(role => { + + const isChecked = split.includes(role?.name!) + + return { + e.preventDefault(); + e.stopPropagation(); + const updated = isChecked + ? split.filter(name => name !== role?.name) + : [...split, role?.name]; + applySuggestion(updated.join(","), true); + }}> + {isChecked ? : } + {role?.name} + + })} + + } + } + ]}/> +} \ No newline at end of file diff --git a/src/packages/ce/src/member/components/MemberDataTableRowComponent.tsx b/src/packages/ce/src/member/components/MemberDataTableRowComponent.tsx new file mode 100644 index 00000000..aa769778 --- /dev/null +++ b/src/packages/ce/src/member/components/MemberDataTableRowComponent.tsx @@ -0,0 +1,252 @@ +import React, {startTransition} from "react"; +import {NamespaceMember} from "@code0-tech/sagittarius-graphql-types"; +import { + Avatar, + Badge, + Button, + Card, + DataTableColumn, + Dialog, + DialogClose, + DialogContent, + DialogOverlay, + DialogPortal, + Flex, + Menu, + MenuContent, + MenuItem, + MenuPortal, + MenuTrigger, + Spacing, + Text, + Tooltip, + TooltipContent, + TooltipPortal, + TooltipTrigger, + useService, + useStore +} from "@code0-tech/pictor"; +import {formatDistanceToNow} from "date-fns"; +import {UserService} from "@edition/user/services/User.service"; +import {MemberService} from "@edition/member/services/Member.service"; +import {RoleService} from "@edition/role/services/Role.service"; +import {RolePermissionComponent} from "@edition/role/components/RolePermissionComponent"; +import {IconDotsVertical, IconUserCog, IconUserOff, IconX} from "@tabler/icons-react"; + +export interface MemberDataTableRowComponentProps { + memberId: NamespaceMember['id'] +} + +export const MemberDataTableRowComponent: React.FC = (props) => { + + const {memberId} = props + + const memberService = useService(MemberService) + const memberStore = useStore(MemberService) + const userService = useService(UserService) + const userStore = useStore(UserService) + const roleService = useService(RoleService) + const roleStore = useStore(RoleService) + + const member = React.useMemo( + () => memberService.getById(memberId), + [memberStore, memberId] + ) + + const user = React.useMemo( + () => userService.getById(member?.user?.id), + [userStore, member] + ) + + const assignedRoles = React.useMemo( + () => member?.roles?.nodes?.map(role => roleService.getById(role?.id, {namespaceId: member?.namespace?.id})) || [], + [roleStore, member] + ) + + const [localAssignedRoles, setLocalAssignedRoles] = React.useState(assignedRoles) + const [openRemovedMemberDialog, setOpenRemovedMemberDialog] = React.useState(false) + const [openAssignRolesDialog, setOpenAssignRolesDialog] = React.useState(false) + + const rolesToAssign = roleService + .values({namespaceId: member?.namespace?.id}) + .filter(role => !localAssignedRoles.find(aRole => aRole?.id === role.id)) + + React.useEffect(() => { + setLocalAssignedRoles(assignedRoles) + }, [assignedRoles]) + + + const memberAssignRoles = React.useCallback(() => { + startTransition(() => { + memberService.memberAssignRoles({ + memberId: member?.id!, + roleIds: localAssignedRoles.map(r => r?.id!) + }) + }) + }, [localAssignedRoles, member]) + + const memberDelete = React.useCallback(() => { + startTransition(() => { + memberService.memberDelete({ + namespaceMemberId: member?.id! + }) + }) + }, [member]) + + return <> + setOpenRemovedMemberDialog(open)}> + + + + + + Are you sure you want to remove {" "} + + @{user?.username} + {" "} + from this organization/workspace? + + + + + + + + + + + + + + setOpenAssignRolesDialog(open)}> + + + + + + Assign, remove and manage the roles of a active + member + + + + + + + {rolesToAssign.map((role, index) => { + return <> + { + setLocalAssignedRoles(prevState => [...prevState, role]) + }}> + + {role?.name} + + + + + })} + + + + + + + {localAssignedRoles.map(role => { + return + + {role?.name} + + + + + + })} + + + + + + + + + + + + + + + + + + + + + + @{user?.username} + + {user?.admin ? Owner : null} + {user?.emailVerifiedAt ? Email verified : null} + + + {user?.email ?? ""} + + + + + Member since {formatDistanceToNow(member?.createdAt!)} ago + + + + + + {assignedRoles.map(role => { + return + + + {role?.name} + + + + + + + + + })} + + + + {member?.userAbilities?.deleteMember || member?.userAbilities?.assignMemberRoles ? ( + + + + + + + {member?.userAbilities?.deleteMember && ( + setOpenRemovedMemberDialog(true)}> + + Remove member + + )} + {member?.userAbilities?.assignMemberRoles && ( + setOpenAssignRolesDialog(true)}> + + Assign role + + )} + + + + ) : null} + + +} \ No newline at end of file diff --git a/src/packages/ce/src/member/pages/MemberAddPage.tsx b/src/packages/ce/src/member/pages/MemberAddPage.tsx new file mode 100644 index 00000000..980136ea --- /dev/null +++ b/src/packages/ce/src/member/pages/MemberAddPage.tsx @@ -0,0 +1,105 @@ +"use client" + +import React from "react"; +import { + Button, + Col, + DUserInput, + DUserView, + Flex, + Spacing, + Text, + useForm, + useService, + useStore +} from "@code0-tech/pictor"; +import {MemberService} from "@edition/member/services/Member.service"; +import {useParams, useRouter} from "next/navigation"; +import {Namespace} from "@code0-tech/sagittarius-graphql-types"; +import Link from "next/link"; +import {UserService} from "@edition/user/services/User.service"; +import {InputSyntaxSegment} from "@code0-tech/pictor/dist/components/form/Input.syntax.hook"; + +export const MemberAddPage: React.FC = () => { + + const params = useParams() + const memberService = useService(MemberService) + const memberStore = useStore(MemberService) + const userService = useService(UserService) + const userStore = useStore(UserService) + const router = useRouter() + const [, startTransition] = React.useTransition() + + const namespaceIndex = params?.namespaceId as string + const namespaceId: Namespace['id'] = `gid://sagittarius/Namespace/${namespaceIndex as unknown as number}` + + const members = React.useMemo(() => memberService.values({namespaceId: namespaceId}), [memberStore, userStore]) + const formInitialValues = React.useMemo(() => ({users: null}), []) + const filteredUsers = React.useMemo(() => { + return (user: DUserView) => { + return !members.find(m => m.user?.id === user.id) + } + }, [members]) + + const [inputs, validate] = useForm<{ users: null | InputSyntaxSegment[] }>({ + initialValues: formInitialValues, + validate: { + users: (value) => { + if (!value) return "Please select at least one user" + if (value.length <= 0) return "Please select at least one user" + return null + } + }, + onSubmit: (values) => { + startTransition(async () => { + for (const value of values.users!!) { + await memberService.memberInvite({ + namespaceId: namespaceId!!, + userId: (value.value)._id!! + }) + } + router.push(`/namespace/${namespaceIndex}/members`) + }) + } + }) + + //TODO: user abilities for add user as member within namespace + + return
+ + + + Add new members + + + + Global runtimes are shared runtimes that can be used across multiple organizations. + + + {/*@ts-ignore*/} + + + + + + + + + + +
+} \ No newline at end of file diff --git a/src/packages/ce/src/member/pages/MembersPage.tsx b/src/packages/ce/src/member/pages/MembersPage.tsx new file mode 100644 index 00000000..8aea85be --- /dev/null +++ b/src/packages/ce/src/member/pages/MembersPage.tsx @@ -0,0 +1,16 @@ +"use client" + +import {MembersView} from "@edition/member/views/MembersView"; +import React from "react"; + +export const MembersPage: React.FC = () => { + return
+ +
+} \ No newline at end of file diff --git a/src/packages/ce/src/member/Member.service.ts b/src/packages/ce/src/member/services/Member.service.ts similarity index 93% rename from src/packages/ce/src/member/Member.service.ts rename to src/packages/ce/src/member/services/Member.service.ts index 08f6c42e..4838c579 100644 --- a/src/packages/ce/src/member/Member.service.ts +++ b/src/packages/ce/src/member/services/Member.service.ts @@ -20,13 +20,14 @@ import membersQuery from "./queries/Members.query.graphql" import memberAssignRoleMutation from "./mutations/Member.assignRoles.mutation.graphql" import memberDeleteMutation from "./mutations/Member.delete.mutation.graphql" import memberInviteMutation from "./mutations/Member.invite.mutation.graphql" +import {View} from "@code0-tech/pictor/dist/utils/view"; export class MemberService extends DNamespaceMemberReactiveService { private readonly client: GraphqlClient private i = 0 - constructor(client: GraphqlClient, store: ReactiveArrayStore) { + constructor(client: GraphqlClient, store: ReactiveArrayStore>) { super(store) this.client = client } @@ -52,7 +53,7 @@ export class MemberService extends DNamespaceMemberReactiveService { const nodes = res.data?.namespace?.members?.nodes ?? [] nodes.forEach(member => { if (member && !this.hasById(member.id)) { - this.set(this.i++, new DNamespaceMemberView(member)) + this.set(this.i++, new View(new DNamespaceMemberView(member))) } }) }) @@ -87,7 +88,7 @@ export class MemberService extends DNamespaceMemberReactiveService { } }) - this.set(index, newMember) + this.set(index, new View(newMember)) } return result.data?.namespacesMembersAssignRoles ?? undefined @@ -120,7 +121,7 @@ export class MemberService extends DNamespaceMemberReactiveService { if (result.data && result.data.namespacesMembersInvite && result.data.namespacesMembersInvite.namespaceMember) { const member = result.data.namespacesMembersInvite.namespaceMember - this.set(this.i++, new DNamespaceMemberView(member)) + this.set(this.i++, new View(new DNamespaceMemberView(member))) } return result.data?.namespacesMembersInvite ?? undefined diff --git a/src/packages/ce/src/member/fragments/Member.basic.fragment.graphql b/src/packages/ce/src/member/services/fragments/Member.basic.fragment.graphql similarity index 61% rename from src/packages/ce/src/member/fragments/Member.basic.fragment.graphql rename to src/packages/ce/src/member/services/fragments/Member.basic.fragment.graphql index e5643d88..f68783d2 100644 --- a/src/packages/ce/src/member/fragments/Member.basic.fragment.graphql +++ b/src/packages/ce/src/member/services/fragments/Member.basic.fragment.graphql @@ -1,5 +1,5 @@ -#import "../../user/fragments/User.id.fragment.graphql" -#import "../../namespace/fragments/Namespace.id.fragment.graphql" +#import "@edition/user/services/fragments/User.id.fragment.graphql" +#import "@edition/namespace/services/fragments/Namespace.id.fragment.graphql" fragment BasicMember on NamespaceMember { id roles { @@ -7,6 +7,7 @@ fragment BasicMember on NamespaceMember { } user { ...UserId + username } namespace { ...NamespaceId diff --git a/src/packages/ce/src/member/fragments/Member.fragment.graphql b/src/packages/ce/src/member/services/fragments/Member.fragment.graphql similarity index 70% rename from src/packages/ce/src/member/fragments/Member.fragment.graphql rename to src/packages/ce/src/member/services/fragments/Member.fragment.graphql index 2ff63a7d..647cf062 100644 --- a/src/packages/ce/src/member/fragments/Member.fragment.graphql +++ b/src/packages/ce/src/member/services/fragments/Member.fragment.graphql @@ -1,5 +1,5 @@ -#import "../../user/fragments/User.id.fragment.graphql" -#import "../../namespace/fragments/Namespace.id.fragment.graphql" +#import "@edition/user/services/fragments/User.id.fragment.graphql" +#import "@edition/namespace/services/fragments/Namespace.id.fragment.graphql" fragment Member on NamespaceMember { id roles (first: $firstRole, after: $afterRole) { @@ -7,6 +7,7 @@ fragment Member on NamespaceMember { nodes { __typename id + name } pageInfo { endCursor @@ -16,6 +17,7 @@ fragment Member on NamespaceMember { } user { ...UserId + username } namespace { ...NamespaceId diff --git a/src/packages/ce/src/member/mutations/Member.assignRoles.mutation.graphql b/src/packages/ce/src/member/services/mutations/Member.assignRoles.mutation.graphql similarity index 100% rename from src/packages/ce/src/member/mutations/Member.assignRoles.mutation.graphql rename to src/packages/ce/src/member/services/mutations/Member.assignRoles.mutation.graphql diff --git a/src/packages/ce/src/member/mutations/Member.delete.mutation.graphql b/src/packages/ce/src/member/services/mutations/Member.delete.mutation.graphql similarity index 100% rename from src/packages/ce/src/member/mutations/Member.delete.mutation.graphql rename to src/packages/ce/src/member/services/mutations/Member.delete.mutation.graphql diff --git a/src/packages/ce/src/member/mutations/Member.invite.mutation.graphql b/src/packages/ce/src/member/services/mutations/Member.invite.mutation.graphql similarity index 100% rename from src/packages/ce/src/member/mutations/Member.invite.mutation.graphql rename to src/packages/ce/src/member/services/mutations/Member.invite.mutation.graphql diff --git a/src/packages/ce/src/member/queries/Members.query.graphql b/src/packages/ce/src/member/services/queries/Members.query.graphql similarity index 100% rename from src/packages/ce/src/member/queries/Members.query.graphql rename to src/packages/ce/src/member/services/queries/Members.query.graphql diff --git a/src/packages/ce/src/member/views/MembersView.tsx b/src/packages/ce/src/member/views/MembersView.tsx new file mode 100644 index 00000000..41a4fa67 --- /dev/null +++ b/src/packages/ce/src/member/views/MembersView.tsx @@ -0,0 +1,110 @@ +"use client" + +import React from "react"; +import {useParams} from "next/navigation"; +import {Button, DataTableFilterProps, DataTableSortProps, Flex, Spacing, Text, ButtonGroup, Menu, MenuTrigger, MenuPortal, MenuContent, MenuCheckboxItem} from "@code0-tech/pictor"; +import Link from "next/link"; +import {MemberDataTableComponent} from "@edition/member/components/MemberDataTableComponent"; +import {MemberDataTableFilterInputComponent} from "@edition/member/components/MemberDataTableFilterInputComponent"; +import {IconMinus, IconSortAscending, IconSortDescending} from "@tabler/icons-react"; + +//TODO: user abilities for add user as member within namespace +export const MembersView: React.FC = () => { + + const params = useParams() + const namespaceId = params.namespaceId as any as number + + const [filter, setFilter] = React.useState({}) + const [sort, setSort] = React.useState({}) + + return <> + + + + + Members + + + Manage members that belong to this namespace. You can add new members and manage their permissions. + + + + + + + + + + + + + { + if (sort["user.username"] === undefined) + setSort(prev => ({...prev, "user.username": "asc"})) + else if (sort["user.username"] === "asc") + setSort(prev => ({...prev, "user.username": "desc"})) + else + setSort(prev => ({...prev, "user.username": undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["user.username"] === undefined ? : sort["user.username"] === "asc" ? + : } + Username + + { + if (sort["createdAt"] === undefined) + setSort(prev => ({...prev, createdAt: "asc"})) + else if (sort["createdAt"] === "asc") + setSort(prev => ({...prev, createdAt: "desc"})) + else + setSort(prev => ({...prev, createdAt: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["createdAt"] === undefined ? + : sort["createdAt"] === "asc" ? + : } + Created At + + { + if (sort["updatedAt"] === undefined) + setSort(prev => ({...prev, updatedAt: "asc"})) + else if (sort["updatedAt"] === "asc") + setSort(prev => ({...prev, updatedAt: "desc"})) + else + setSort(prev => ({...prev, updatedAt: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["updatedAt"] === undefined ? + : sort["updatedAt"] === "asc" ? + : } + Updated At + + + + + + + +
+ setFilter(filter)}/> +
+ + + + + +} \ No newline at end of file diff --git a/src/packages/ce/src/namespace/pages/NamespaceOverviewPage.tsx b/src/packages/ce/src/namespace/pages/NamespaceOverviewPage.tsx new file mode 100644 index 00000000..c4f8bdf4 --- /dev/null +++ b/src/packages/ce/src/namespace/pages/NamespaceOverviewPage.tsx @@ -0,0 +1,42 @@ +"use client" + +import React from "react"; +import {ProjectsView} from "@edition/project/views/ProjectsView"; +import {DLayout, useService, useStore, useUserSession, ScrollArea, ScrollAreaScrollbar, ScrollAreaThumb, ScrollAreaViewport} from "@code0-tech/pictor"; +import {NamespaceOverviewPersonalLeftView} from "@edition/namespace/views/NamespaceOverviewPersonalLeftView"; +import {useParams} from "next/navigation"; +import {UserService} from "@edition/user/services/User.service"; +import {NamespaceOverviewOrganizationLeftView} from "@edition/namespace/views/NamespaceOverviewOrganizationLeftView"; + +export const NamespaceOverviewPage: React.FC = () => { + + const params = useParams() + const userService = useService(UserService) + const userStore = useStore(UserService) + const currentSession = useUserSession() + + const currentUser = React.useMemo(() => userService.getById(currentSession?.user?.id), [userStore, currentSession]) + const namespaceIndexCurrentUser = currentUser?.namespace?.id?.match(/Namespace\/(\d+)$/)?.[1] + const namespaceId = params.namespaceId as any as string + + return : + }> +
+ + + + + + + + +
+
+} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/namespace/NamespaceProjectsCreatePage.tsx b/src/packages/ce/src/namespace/pages/NamespaceProjectsCreatePage.tsx similarity index 51% rename from src/packages/ce/src/dashboard/namespace/NamespaceProjectsCreatePage.tsx rename to src/packages/ce/src/namespace/pages/NamespaceProjectsCreatePage.tsx index 0135fedc..cab32b00 100644 --- a/src/packages/ce/src/dashboard/namespace/NamespaceProjectsCreatePage.tsx +++ b/src/packages/ce/src/namespace/pages/NamespaceProjectsCreatePage.tsx @@ -4,7 +4,7 @@ import React from "react"; import {Button, Col, Flex, Spacing, Text, TextInput, toast, useForm, useService} from "@code0-tech/pictor"; import Link from "next/link"; import {useParams, useRouter} from "next/navigation"; -import {ProjectService} from "@edition/project/Project.service"; +import {ProjectService} from "@edition/project/services/Project.service"; import {Namespace} from "@code0-tech/sagittarius-graphql-types"; export const NamespaceProjectsCreatePage: React.FC = () => { @@ -57,38 +57,46 @@ export const NamespaceProjectsCreatePage: React.FC = () => { } }) - return - - - Create new project - - - - Global runtimes are shared runtimes that can be used across multiple organizations. - - - - - - - - - + + - - - - - + + + +
} \ No newline at end of file diff --git a/src/packages/ce/src/namespace/pages/NamespaceProjectsPage.tsx b/src/packages/ce/src/namespace/pages/NamespaceProjectsPage.tsx new file mode 100644 index 00000000..ea4da2bd --- /dev/null +++ b/src/packages/ce/src/namespace/pages/NamespaceProjectsPage.tsx @@ -0,0 +1,16 @@ +"use client" + +import {ProjectsView} from "@edition/project/views/ProjectsView"; +import React from "react"; + +export const NamespaceProjectsPage: React.FC = () => { + return
+ +
+} \ No newline at end of file diff --git a/src/packages/ce/src/namespace/Namespace.service.ts b/src/packages/ce/src/namespace/services/Namespace.service.ts similarity index 86% rename from src/packages/ce/src/namespace/Namespace.service.ts rename to src/packages/ce/src/namespace/services/Namespace.service.ts index 5a7a1f5f..532587df 100644 --- a/src/packages/ce/src/namespace/Namespace.service.ts +++ b/src/packages/ce/src/namespace/services/Namespace.service.ts @@ -2,12 +2,13 @@ import {DNamespaceReactiveService, DNamespaceView, ReactiveArrayStore} from "@co import {GraphqlClient} from "@core/util/graphql-client"; import {Namespace, Query} from "@code0-tech/sagittarius-graphql-types"; import namespaceQuery from "./queries/Namespace.query.graphql"; +import {View} from "@code0-tech/pictor/dist/utils/view"; export class NamespaceService extends DNamespaceReactiveService { private readonly client: GraphqlClient - constructor(client: GraphqlClient, store: ReactiveArrayStore) { + constructor(client: GraphqlClient, store: ReactiveArrayStore>) { super(store); this.client = client } @@ -24,7 +25,7 @@ export class NamespaceService extends DNamespaceReactiveService { if (!data) return if (data.namespace) { - this.add(new DNamespaceView(data.namespace)) + this.add(new View(new DNamespaceView(data.namespace))) } }) diff --git a/src/packages/ce/src/namespace/fragments/Namespace.fragment.graphql b/src/packages/ce/src/namespace/services/fragments/Namespace.fragment.graphql similarity index 81% rename from src/packages/ce/src/namespace/fragments/Namespace.fragment.graphql rename to src/packages/ce/src/namespace/services/fragments/Namespace.fragment.graphql index 3e54c883..26755415 100644 --- a/src/packages/ce/src/namespace/fragments/Namespace.fragment.graphql +++ b/src/packages/ce/src/namespace/services/fragments/Namespace.fragment.graphql @@ -1,5 +1,5 @@ -#import "../../organization/fragments/Organization.id.fragment.graphql" -#import "../../user/fragments/User.id.fragment.graphql" +#import "@edition/organization/services/fragments/Organization.id.fragment.graphql" +#import "@edition/user/services/fragments/User.id.fragment.graphql" fragment Namespace on Namespace { __typename id diff --git a/src/packages/ce/src/namespace/fragments/Namespace.id.fragment.graphql b/src/packages/ce/src/namespace/services/fragments/Namespace.id.fragment.graphql similarity index 100% rename from src/packages/ce/src/namespace/fragments/Namespace.id.fragment.graphql rename to src/packages/ce/src/namespace/services/fragments/Namespace.id.fragment.graphql diff --git a/src/packages/ce/src/namespace/queries/Namespace.query.graphql b/src/packages/ce/src/namespace/services/queries/Namespace.query.graphql similarity index 100% rename from src/packages/ce/src/namespace/queries/Namespace.query.graphql rename to src/packages/ce/src/namespace/services/queries/Namespace.query.graphql diff --git a/src/packages/ce/src/namespace/views/NamespaceOverviewOrganizationLeftView.tsx b/src/packages/ce/src/namespace/views/NamespaceOverviewOrganizationLeftView.tsx new file mode 100644 index 00000000..3aa6c1e3 --- /dev/null +++ b/src/packages/ce/src/namespace/views/NamespaceOverviewOrganizationLeftView.tsx @@ -0,0 +1,116 @@ +import React from "react"; +import { + AuroraBackground, + Avatar, + Button, + Flex, + hashToColor, + ScrollArea, + ScrollAreaScrollbar, + ScrollAreaThumb, + ScrollAreaViewport, + Spacing, + Text, + Tooltip, + TooltipContent, + TooltipPortal, + TooltipTrigger, + useService, + useStore +} from "@code0-tech/pictor"; +import {UserService} from "@edition/user/services/User.service"; +import {OrganizationService} from "@edition/organization/services/Organization.service"; +import Link from "next/link"; +import {useParams} from "next/navigation"; +import {MemberService} from "@edition/member/services/Member.service"; +import {NamespaceService} from "@edition/namespace/services/Namespace.service"; +import {RuntimeDataTableComponent} from "@edition/runtime/components/RuntimeDataTableComponent"; + +export const NamespaceOverviewOrganizationLeftView: React.FC = () => { + + const params = useParams() + const userService = useService(UserService) + const userStore = useStore(UserService) + const organizationService = useService(OrganizationService) + const organizationStore = useStore(OrganizationService) + const memberService = useService(MemberService) + const memberStore = useStore(MemberService) + const namespaceService = useService(NamespaceService) + const namespaceStore = useStore(NamespaceService) + + const namespaceIndex = params.namespaceId as any as number + + const namespace = React.useMemo( + () => namespaceService.getById(`gid://sagittarius/Namespace/${namespaceIndex}`), + [namespaceStore, namespaceIndex] + ) + const parentOrganization = React.useMemo( + () => namespace?.parent?.__typename === "Organization" ? organizationService.getById(namespace?.parent?.id) : null, + [organizationStore, namespace] + ) + + const members = React.useMemo( + () => memberService.values({namespaceId: `gid://sagittarius/Namespace/${namespaceIndex}`}), + [memberStore, userStore] + ) + + return + + + + + {parentOrganization?.name} + + + + + +
+ + Members + + + {members.map(member => { + const user = userService.getById(member.user?.id!!) + return + + + + + + + + @{user?.username} + + + {user?.email} + + + + + + })} + {members.length <= 0 && + + + } + + +
+ + Runtimes + + +
+
+ + + +
+ +} \ No newline at end of file diff --git a/src/packages/ce/src/namespace/views/NamespaceOverviewPersonalLeftView.tsx b/src/packages/ce/src/namespace/views/NamespaceOverviewPersonalLeftView.tsx new file mode 100644 index 00000000..13775728 --- /dev/null +++ b/src/packages/ce/src/namespace/views/NamespaceOverviewPersonalLeftView.tsx @@ -0,0 +1,147 @@ +import React from "react"; +import { + AuroraBackground, + Avatar, + Badge, + Button, + Flex, + hashToColor, + ScrollArea, + ScrollAreaScrollbar, + ScrollAreaThumb, + ScrollAreaViewport, + Spacing, + Text, + Tooltip, + TooltipContent, + TooltipPortal, + TooltipTrigger, + useService, + useStore, + useUserSession +} from "@code0-tech/pictor"; +import {UserService} from "@edition/user/services/User.service"; +import {IconMail, IconSparkles, IconUser, IconUserCog} from "@tabler/icons-react"; +import {OrganizationService} from "@edition/organization/services/Organization.service"; +import Link from "next/link"; +import {useParams} from "next/navigation"; +import {MemberService} from "@edition/member/services/Member.service"; + +export const NamespaceOverviewPersonalLeftView: React.FC = () => { + + const params = useParams() + const userService = useService(UserService) + const userStore = useStore(UserService) + const organizationService = useService(OrganizationService) + const organizationStore = useStore(OrganizationService) + const memberService = useService(MemberService) + const memberStore = useStore(MemberService) + + const namespaceIndex = params.namespaceId as any as number + + const currentSession = useUserSession() + const currentUser = React.useMemo( + () => userService.getById(currentSession?.user?.id), + [userStore, currentSession] + ) + const organizations = React.useMemo( + () => organizationService.values(), + [organizationStore] + ) + + const members = React.useMemo( + () => memberService.values({namespaceId: `gid://sagittarius/Namespace/${namespaceIndex}`}), + [memberStore, userStore] + ) + + return + + +
+ + + 👋 + +
+ + {currentUser?.firstname} {currentUser?.lastname} + + + + + @{currentUser?.username} + + + + {currentUser?.admin ? Admin : + User} + + + + {currentUser?.email} + + + + BASIC + + + + + + + +
+ + Organizations + + + {organizations.map(organization => { + return + })} + {organizations.length <= 0 && You aren't a member of any organization} + + +
+ + Members + + + {members.map(member => { + const user = userService.getById(member.user?.id!!) + return + + + + + + + + @{user?.username} + + + {user?.email} + + + + + + })} + {members.length <= 0 && + + + } + + +
+
+ + + +
+ +} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/namespace/NamespaceOverviewRightView.tsx b/src/packages/ce/src/namespace/views/NamespaceOverviewRightView.tsx similarity index 87% rename from src/packages/ce/src/dashboard/namespace/NamespaceOverviewRightView.tsx rename to src/packages/ce/src/namespace/views/NamespaceOverviewRightView.tsx index 5698f9df..445f145a 100644 --- a/src/packages/ce/src/dashboard/namespace/NamespaceOverviewRightView.tsx +++ b/src/packages/ce/src/namespace/views/NamespaceOverviewRightView.tsx @@ -18,10 +18,10 @@ import { useService, useStore } from "@code0-tech/pictor"; -import {MemberService} from "@edition/member/Member.service"; +import {MemberService} from "@edition/member/services/Member.service"; import {useParams} from "next/navigation"; -import {NamespaceService} from "@edition/namespace/Namespace.service"; -import {UserService} from "@edition/user/User.service"; +import {NamespaceService} from "@edition/namespace/services/Namespace.service"; +import {UserService} from "@edition/user/services/User.service"; import Link from "next/link"; export const NamespaceOverviewRightView: React.FC = () => { @@ -38,7 +38,7 @@ export const NamespaceOverviewRightView: React.FC = () => { const namespace = React.useMemo(() => namespaceService.getById(`gid://sagittarius/Namespace/${namespaceId}`), [namespaceStore, namespaceId]) const members = React.useMemo(() => memberService.values({namespaceId: `gid://sagittarius/Namespace/${namespaceId}`}), [memberStore, userStore]) - return + return + + ) : null + }, [namespace, parentOrganization]) + + return + + + + + + + + + + + + + + + + + {settings} + + +} \ No newline at end of file diff --git a/src/packages/ce/src/organization/components/OrganizationDataTableComponent.tsx b/src/packages/ce/src/organization/components/OrganizationDataTableComponent.tsx new file mode 100644 index 00000000..1c79ae32 --- /dev/null +++ b/src/packages/ce/src/organization/components/OrganizationDataTableComponent.tsx @@ -0,0 +1,64 @@ +import React from "react"; +import {DataTable, DataTableColumn, Text, useService, useStore} from "@code0-tech/pictor"; +import {DataTableFilterProps, DataTableSortProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import {Organization} from "@code0-tech/sagittarius-graphql-types"; +import {OrganizationDataTableRowComponent} from "@edition/organization/components/OrganizationDataTableRowComponent"; +import {OrganizationService} from "@edition/organization/services/Organization.service"; +import {MemberService} from "@edition/member/services/Member.service"; + +export interface OrganizationDataTableComponentProps { + sort?: DataTableSortProps + filter?: DataTableFilterProps + preFilter?: (project: Organization, index: number) => boolean + onSelect?: (item: Organization | undefined) => void + minimized?: boolean +} + +export const OrganizationDataTableComponent: React.FC = (props) => { + + const {sort, filter, preFilter = () => true, onSelect, minimized} = props + + const organizationService = useService(OrganizationService) + const organizationStore = useStore(OrganizationService) + const memberService = useService(MemberService) + const memberStore = useStore(MemberService) + + const organizations = React.useMemo( + () => organizationService.values(), + [organizationStore] + ) + + const data = React.useMemo( + () => organizations.map( + o => o.json() + ).filter(preFilter).map(o => { + const members = memberService.values({namespaceId: o.namespace?.id}) + const organization: Organization = { + ...o, + namespace: { + ...o.namespace, + members: { + nodes: members.map(m => m.json()), + } + } + } + return organization + }), + [organizations, memberStore, preFilter] + ) + + return + + No organization found. Create one to get started. + + } + onSelect={(item) => item && onSelect?.(item)} + data={data}> + {(organization, index) => { + return + }} + + +} \ No newline at end of file diff --git a/src/packages/ce/src/organization/components/OrganizationDataTableFilterInputComponent.tsx b/src/packages/ce/src/organization/components/OrganizationDataTableFilterInputComponent.tsx new file mode 100644 index 00000000..4abd5813 --- /dev/null +++ b/src/packages/ce/src/organization/components/OrganizationDataTableFilterInputComponent.tsx @@ -0,0 +1,106 @@ +import React from "react"; +import { + DataTableFilterInput, + DataTableFilterSuggestionMenu, + MenuCheckboxItem, + useService, + useStore +} from "@code0-tech/pictor"; +import {IconCheck} from "@tabler/icons-react"; +import {DataTableFilterProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import {OrganizationService} from "@edition/organization/services/Organization.service"; +import {NamespaceService} from "@edition/namespace/services/Namespace.service"; +import {MemberService} from "@edition/member/services/Member.service"; + +export interface OrganizationDataTableFilterInputComponentProps { + onChange: (filter: DataTableFilterProps) => void +} + +export const OrganizationDataTableFilterInputComponent: React.FC = (props) => { + + const {onChange} = props + + const organizationService = useService(OrganizationService) + const organizationStore = useStore(OrganizationService) + const namespaceStore = useStore(NamespaceService) + const namespaceService = useService(NamespaceService) + const memberService = useService(MemberService) + const memberStore = useStore(MemberService) + + const organizations = React.useMemo( + () => organizationService.values(), + [organizationStore] + ) + + const namespaces = React.useMemo( + () => organizations.map( + organization => namespaceService.getById(organization?.namespace?.id) + ), + [namespaceStore, organizations] + ) + + const members = React.useMemo( + () => namespaces.map( + namespace => memberService.values({namespaceId: namespace?.id}) + ).flat(), + [namespaces, memberStore, organizations] + ) + + return { + + const split = currentValue.split(",").map(s => s.trim()).filter(Boolean) + + return + {organizations.map(organization => { + + const isChecked = split.includes(organization?.name!) + + return { + e.preventDefault(); + e.stopPropagation(); + const updated = isChecked + ? split.filter(name => name !== organization?.name) + : [...split, organization?.name]; + applySuggestion(updated.join(","), true); + }}> + {isChecked ? : } + {organization?.name} + + })} + + } + }, { + token: "Member", + key: "namespace.members.nodes.user.username", + operators: ["isOneOf"], + suggestion: (context, operator, currentValue, applySuggestion) => { + + const split = currentValue.split(",").map(s => s.trim()).filter(Boolean) + + return + {members.map(member => { + + const isChecked = split.includes(member?.user?.username!) + + return { + e.preventDefault(); + e.stopPropagation(); + const updated = isChecked + ? split.filter(name => name !== member?.user?.username) + : [...split, member?.user?.username]; + applySuggestion(updated.join(","), true); + }}> + {isChecked ? : } + {member?.user?.username} + + })} + + } + } + ]}/> +} \ No newline at end of file diff --git a/src/packages/ce/src/organization/components/OrganizationDataTableRowComponent.tsx b/src/packages/ce/src/organization/components/OrganizationDataTableRowComponent.tsx new file mode 100644 index 00000000..f51c8553 --- /dev/null +++ b/src/packages/ce/src/organization/components/OrganizationDataTableRowComponent.tsx @@ -0,0 +1,129 @@ +import React from "react"; +import {Organization} from "@code0-tech/sagittarius-graphql-types"; +import { + Avatar, + Button, + DataTableColumn, + DOrganizationView, + Flex, + hashToColor, + Text, + useService, + useStore, + useUserSession +} from "@code0-tech/pictor"; +import {IconLogout} from "@tabler/icons-react"; +import {OrganizationService} from "@edition/organization/services/Organization.service"; +import {NamespaceService} from "@edition/namespace/services/Namespace.service"; +import {MemberService} from "@edition/member/services/Member.service"; +import {UserService} from "@edition/user/services/User.service"; +import {formatDistanceToNow} from "date-fns"; + +export interface OrganizationDataTableRowComponentProps { + organizationId: Organization['id'] + onLeave?: (organization: DOrganizationView) => void + minimized?: boolean +} + +export const OrganizationDataTableRowComponent: React.FC = (props) => { + + const {organizationId, onLeave, minimized} = props + + const organizationService = useService(OrganizationService) + const organizationStore = useStore(OrganizationService) + const namespaceStore = useStore(NamespaceService) + const namespaceService = useService(NamespaceService) + const memberService = useService(MemberService) + const memberStore = useStore(MemberService) + const userService = useService(UserService) + const userStore = useStore(UserService) + + const currentSession = useUserSession() + + const currentUser = React.useMemo( + () => userService.getById(currentSession?.user?.id), + [userStore, currentSession] + ) + + const organization = React.useMemo( + () => organizationService.getById(organizationId), + [organizationStore, organizationId] + ) + + const namespace = React.useMemo( + () => organization ? namespaceService.getById(organization.namespace?.id) : null, + [namespaceStore, organization] + ) + + const namespaceMember = React.useMemo( + () => namespace && currentUser ? memberService.getByNamespaceIdAndUserId(namespace.id, currentUser.id) : null, + [memberStore, namespace, currentUser] + ) + + const namespaceMembers = React.useMemo( + () => memberService.values({namespaceId: namespace?.id}), + [memberStore, userStore, namespace] + ) + + return <> + + + + + + + {organization?.name} + + + + {!minimized && ( + + Updated {formatDistanceToNow(organization?.updatedAt!)} ago + + )} + + + + {!minimized && ( + <> + + + {namespace?.projects?.count ? ( + + {namespace?.projects?.count ?? 0} {" "} + projects + + ) : null} + + {namespace?.members?.count ? ( + + {namespace?.members?.count ?? 0}{" "} + members + + ) : null} + + {namespace?.runtimes?.count ? ( + + {namespace?.runtimes?.count ?? 0}{" "} + connected runtimes + + ) : null} + + + {onLeave && namespaceMember && namespaceMember.userAbilities?.deleteMember ? ( + + + + ) : null} + + )} + + +} \ No newline at end of file diff --git a/src/packages/ce/src/organization/pages/OrganizationCreatePage.tsx b/src/packages/ce/src/organization/pages/OrganizationCreatePage.tsx new file mode 100644 index 00000000..03bcf7d1 --- /dev/null +++ b/src/packages/ce/src/organization/pages/OrganizationCreatePage.tsx @@ -0,0 +1,68 @@ +"use client" + +import {Button, Col, Flex, Spacing, Text, TextInput, useForm, useService} from "@code0-tech/pictor"; +import Link from "next/link"; +import {OrganizationService} from "@edition/organization/services/Organization.service"; +import React from "react"; +import {useRouter} from "next/navigation"; + +export const OrganizationCreatePage = () => { + + const organizationService = useService(OrganizationService) + const [, startTransition] = React.useTransition() + const router = useRouter() + + const [inputs, validate] = useForm({ + initialValues: { + name: null, + }, + validate: { + name: (value) => { + if (!value) return "Name is required" + return null + } + }, + onSubmit: (values) => { + startTransition(() => { + organizationService.organizationCreate({ + name: values.name as unknown as string + }).then(payload => { + if ((payload?.errors?.length ?? 0) <= 0) { + router.push("/organizations") + } + }) + }) + } + }) + + return
+ + + + Create new organization + + + + Organizations are helpfully if managing a group of users and plenty of projects. + + + + + + + + + + + + +
+} \ No newline at end of file diff --git a/src/packages/ce/src/organization/pages/OrganizationSettingsPage.tsx b/src/packages/ce/src/organization/pages/OrganizationSettingsPage.tsx new file mode 100644 index 00000000..063e30a3 --- /dev/null +++ b/src/packages/ce/src/organization/pages/OrganizationSettingsPage.tsx @@ -0,0 +1,94 @@ +"use client" + +import React from "react"; +import {useParams} from "next/navigation"; +import {Namespace} from "@code0-tech/sagittarius-graphql-types"; +import { + AuroraBackground, + Badge, + Button, + DResizableHandle, + DResizablePanel, + DResizablePanelGroup, + Flex, + Text, + useService, + useStore +} from "@code0-tech/pictor"; +import {NamespaceService} from "@edition/namespace/services/Namespace.service"; +import {OrganizationService} from "@edition/organization/services/Organization.service"; +import {IconLayoutSidebar} from "@tabler/icons-react"; +import {Tab, TabContent, TabList, TabTrigger} from "@code0-tech/pictor/dist/components/tab/Tab"; +import {UsageView} from "@edition/runtime/views/UsageView"; +import {OrganizationUpgradeView} from "@edition/organization/views/OrganizationUpgradeView"; +import {OrganizationDeleteView} from "@edition/organization/views/OrganizationDeleteView"; +import {OrganizationGeneralSettingsView} from "@edition/organization/views/OrganizationGeneralSettingsView"; + +export const OrganizationSettingsPage: React.FC = () => { + + //TODO: add ability check for organization settings access for every settings tab + + return + + + + + Organization settings + + + + + General settings and restrictions for your Sculptor application. These settings affect all users + and organizations within the application. + + + + + + + + + + + + + + + + + + + + <> + + + + + + + + + + + + + + + + +} \ No newline at end of file diff --git a/src/packages/ce/src/organization/pages/OrganizationsPage.tsx b/src/packages/ce/src/organization/pages/OrganizationsPage.tsx new file mode 100644 index 00000000..5717f34d --- /dev/null +++ b/src/packages/ce/src/organization/pages/OrganizationsPage.tsx @@ -0,0 +1,17 @@ +"use client" + +import React from "react"; +import {OrganizationsView} from "@edition/organization/views/OrganizationsView"; + +export const OrganizationsPage = () => { + return
+ +
+ +} \ No newline at end of file diff --git a/src/packages/ce/src/organization/Organization.service.ts b/src/packages/ce/src/organization/services/Organization.service.ts similarity index 92% rename from src/packages/ce/src/organization/Organization.service.ts rename to src/packages/ce/src/organization/services/Organization.service.ts index 50063f9e..3247504d 100644 --- a/src/packages/ce/src/organization/Organization.service.ts +++ b/src/packages/ce/src/organization/services/Organization.service.ts @@ -15,13 +15,14 @@ import createOrganizationMutation from "./mutations/Organization.create.mutation import updateOrganizationMutation from "./mutations/Organization.update.mutation.graphql"; import deleteOrganizationMutation from "./mutations/Organization.delete.mutation.graphql"; import organizationQuery from "./queries/Organization.query.graphql"; +import {View} from "@code0-tech/pictor/dist/utils/view"; export class OrganizationService extends DOrganizationReactiveService { private readonly client: GraphqlClient private i = 0; - constructor(client: GraphqlClient, store: ReactiveArrayStore) { + constructor(client: GraphqlClient, store: ReactiveArrayStore>) { super(store); this.client = client } @@ -36,7 +37,7 @@ export class OrganizationService extends DOrganizationReactiveService { if (data.organizations && data.organizations.nodes) { data.organizations.nodes.forEach((organization) => { - if (organization && !this.hasById(organization.id)) this.set(this.i++, new DOrganizationView(organization)) + if (organization && !this.hasById(organization.id)) this.set(this.i++, new View(new DOrganizationView(organization))) }) } }) @@ -59,7 +60,7 @@ export class OrganizationService extends DOrganizationReactiveService { if (result.data && result.data.organizationsCreate && result.data.organizationsCreate.organization) { const organization = result.data.organizationsCreate.organization if (!this.hasById(organization.id)) { - this.add(new DOrganizationView(organization)) + this.add(new View(new DOrganizationView(organization))) } } @@ -95,7 +96,7 @@ export class OrganizationService extends DOrganizationReactiveService { if (result.data && result.data.organizationsUpdate && result.data.organizationsUpdate.organization) { const organization = result.data.organizationsUpdate.organization const index = this.values().findIndex(o => o.id === organization.id) - this.set(index, new DOrganizationView(organization)) + this.set(index, new View(new DOrganizationView(organization))) } diff --git a/src/packages/ce/src/organization/fragments/Organization.fragment.graphql b/src/packages/ce/src/organization/services/fragments/Organization.fragment.graphql similarity index 100% rename from src/packages/ce/src/organization/fragments/Organization.fragment.graphql rename to src/packages/ce/src/organization/services/fragments/Organization.fragment.graphql diff --git a/src/packages/ce/src/organization/fragments/Organization.id.fragment.graphql b/src/packages/ce/src/organization/services/fragments/Organization.id.fragment.graphql similarity index 100% rename from src/packages/ce/src/organization/fragments/Organization.id.fragment.graphql rename to src/packages/ce/src/organization/services/fragments/Organization.id.fragment.graphql diff --git a/src/packages/ce/src/organization/mutations/Organization.create.mutation.graphql b/src/packages/ce/src/organization/services/mutations/Organization.create.mutation.graphql similarity index 100% rename from src/packages/ce/src/organization/mutations/Organization.create.mutation.graphql rename to src/packages/ce/src/organization/services/mutations/Organization.create.mutation.graphql diff --git a/src/packages/ce/src/organization/mutations/Organization.delete.mutation.graphql b/src/packages/ce/src/organization/services/mutations/Organization.delete.mutation.graphql similarity index 100% rename from src/packages/ce/src/organization/mutations/Organization.delete.mutation.graphql rename to src/packages/ce/src/organization/services/mutations/Organization.delete.mutation.graphql diff --git a/src/packages/ce/src/organization/mutations/Organization.update.mutation.graphql b/src/packages/ce/src/organization/services/mutations/Organization.update.mutation.graphql similarity index 100% rename from src/packages/ce/src/organization/mutations/Organization.update.mutation.graphql rename to src/packages/ce/src/organization/services/mutations/Organization.update.mutation.graphql diff --git a/src/packages/ce/src/organization/queries/Organization.query.graphql b/src/packages/ce/src/organization/services/queries/Organization.query.graphql similarity index 100% rename from src/packages/ce/src/organization/queries/Organization.query.graphql rename to src/packages/ce/src/organization/services/queries/Organization.query.graphql diff --git a/src/packages/ce/src/dashboard/organization/OrganizationDeleteView.tsx b/src/packages/ce/src/organization/views/OrganizationDeleteView.tsx similarity index 85% rename from src/packages/ce/src/dashboard/organization/OrganizationDeleteView.tsx rename to src/packages/ce/src/organization/views/OrganizationDeleteView.tsx index b261e1d6..9dbd5118 100644 --- a/src/packages/ce/src/dashboard/organization/OrganizationDeleteView.tsx +++ b/src/packages/ce/src/organization/views/OrganizationDeleteView.tsx @@ -3,8 +3,8 @@ import React from "react"; import {Button, Card, Flex, Spacing, Text, useService, useStore, toast} from "@code0-tech/pictor"; import {useParams, useRouter} from "next/navigation"; -import {NamespaceService} from "@edition/namespace/Namespace.service"; -import {OrganizationService} from "@edition/organization/Organization.service"; +import {NamespaceService} from "@edition/namespace/services/Namespace.service"; +import {OrganizationService} from "@edition/organization/services/Organization.service"; import {Namespace} from "@code0-tech/sagittarius-graphql-types"; export const OrganizationDeleteView: React.FC = () => { @@ -44,18 +44,17 @@ export const OrganizationDeleteView: React.FC = () => { return <> - Delete organization forever + Delete organization - Delete organization - + This will delete the organization and cannot be undone. - diff --git a/src/packages/ce/src/dashboard/organization/OrganizationGeneralSettingsView.tsx b/src/packages/ce/src/organization/views/OrganizationGeneralSettingsView.tsx similarity index 83% rename from src/packages/ce/src/dashboard/organization/OrganizationGeneralSettingsView.tsx rename to src/packages/ce/src/organization/views/OrganizationGeneralSettingsView.tsx index b7d7d5c6..2b32ed3b 100644 --- a/src/packages/ce/src/dashboard/organization/OrganizationGeneralSettingsView.tsx +++ b/src/packages/ce/src/organization/views/OrganizationGeneralSettingsView.tsx @@ -4,8 +4,8 @@ import React from "react"; import CardSection from "@code0-tech/pictor/dist/components/card/CardSection"; import {Button, Card, Flex, Spacing, Text, TextInput, toast, useForm, useService, useStore} from "@code0-tech/pictor"; import {useParams} from "next/navigation"; -import {NamespaceService} from "@edition/namespace/Namespace.service"; -import {OrganizationService} from "@edition/organization/Organization.service"; +import {NamespaceService} from "@edition/namespace/services/Namespace.service"; +import {OrganizationService} from "@edition/organization/services/Organization.service"; import {Namespace} from "@code0-tech/sagittarius-graphql-types"; export const OrganizationGeneralSettingsView: React.FC = () => { @@ -55,23 +55,24 @@ export const OrganizationGeneralSettingsView: React.FC = () => { }) return <> - - General adjustments + + + General + + - + - Name + + Name + - - - - } \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/organization/OrganizationUpgradeView.tsx b/src/packages/ce/src/organization/views/OrganizationUpgradeView.tsx similarity index 68% rename from src/packages/ce/src/dashboard/organization/OrganizationUpgradeView.tsx rename to src/packages/ce/src/organization/views/OrganizationUpgradeView.tsx index 8f4f84f8..80121499 100644 --- a/src/packages/ce/src/dashboard/organization/OrganizationUpgradeView.tsx +++ b/src/packages/ce/src/organization/views/OrganizationUpgradeView.tsx @@ -21,8 +21,8 @@ export const OrganizationUpgradeView: React.FC = () => { const [value, setValue] = React.useState("annually") return <> - Upgrade to team - + Upgrade to Team + Upgrade your organization to the Team plan to unlock advanced features, enhanced collaboration tools, and priority support. Elevate your team's productivity and take advantage of exclusive benefits designed to help @@ -46,21 +46,18 @@ export const OrganizationUpgradeView: React.FC = () => { - - - Team self-hosted - - - 7,95€ - per member / month billed monthly - - - - + Team self-hosted + + + 7,95€ + per member / month billed monthly + + + @@ -88,26 +85,24 @@ export const OrganizationUpgradeView: React.FC = () => { - - - Team cloud - - - -
- 3,95€ - - -27% - -
- per member / month - billed annually -
- - -
+ + Team cloud + + + +
+ 3,95€ + + -27% + +
+ per member / month + billed annually +
+ + @@ -136,16 +131,14 @@ export const OrganizationUpgradeView: React.FC = () => { - - Team cloud (pay as you go) - - - 3,95€ - per member / month billed monthly - - - - + Team cloud (pay as you go) + + + 3,95€ + per member / month billed monthly + + + diff --git a/src/packages/ce/src/organization/views/OrganizationsTopView.tsx b/src/packages/ce/src/organization/views/OrganizationsTopView.tsx new file mode 100644 index 00000000..60a36763 --- /dev/null +++ b/src/packages/ce/src/organization/views/OrganizationsTopView.tsx @@ -0,0 +1,31 @@ +"use client" + +import {Flex, Spacing, Text} from "@code0-tech/pictor"; +import React from "react"; +import {useRouter} from "next/navigation"; +import {OrganizationDataTableComponent} from "@edition/organization/components/OrganizationDataTableComponent"; + +export const OrganizationsTopView = () => { + + const router = useRouter() + + return <> + + + Top organizations + + + Manage organizations that you belong to. You can create new organizations and switch between them. + + + + {/**TODO: use namespaceId*/} + index < 5} onSelect={(organization) => { + const number = organization?.namespace?.id?.match(/Namespace\/(\d+)$/)?.[1] + router.push(`/namespace/${number}`) + }}/> + + +} \ No newline at end of file diff --git a/src/packages/ce/src/organization/views/OrganizationsView.tsx b/src/packages/ce/src/organization/views/OrganizationsView.tsx new file mode 100644 index 00000000..03e6c5d1 --- /dev/null +++ b/src/packages/ce/src/organization/views/OrganizationsView.tsx @@ -0,0 +1,122 @@ +"use client" + +import { + Button, + Flex, + Menu, + MenuCheckboxItem, + MenuContent, + MenuPortal, + MenuTrigger, + Spacing, + Text +} from "@code0-tech/pictor"; +import Link from "next/link"; +import React from "react"; +import {useRouter} from "next/navigation"; +import {OrganizationDataTableComponent} from "@edition/organization/components/OrganizationDataTableComponent"; +import { + OrganizationDataTableFilterInputComponent +} from "@edition/organization/components/OrganizationDataTableFilterInputComponent"; +import {DataTableFilterProps, DataTableSortProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import {ButtonGroup} from "@code0-tech/pictor/dist/components/button-group/ButtonGroup"; +import {IconMinus, IconSortAscending, IconSortDescending} from "@tabler/icons-react"; + +export const OrganizationsView = () => { + + const router = useRouter() + + const [filter, setFilter] = React.useState({}) + const [sort, setSort] = React.useState({}) + + return <> + + + + Organizations + + + Manage organizations that you belong to. You can create new organizations and switch between them. + + + + + + + + + + + + + { + if (sort["name"] === undefined) + setSort(prev => ({...prev, name: "asc"})) + else if (sort["name"] === "asc") + setSort(prev => ({...prev, name: "desc"})) + else + setSort(prev => ({...prev, name: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["name"] === undefined ? : sort["name"] === "asc" ? + : } + Name + + { + if (sort["createdAt"] === undefined) + setSort(prev => ({...prev, createdAt: "asc"})) + else if (sort["createdAt"] === "asc") + setSort(prev => ({...prev, createdAt: "desc"})) + else + setSort(prev => ({...prev, createdAt: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["createdAt"] === undefined ? + : sort["createdAt"] === "asc" ? + : } + Created At + + { + if (sort["updatedAt"] === undefined) + setSort(prev => ({...prev, updatedAt: "asc"})) + else if (sort["updatedAt"] === "asc") + setSort(prev => ({...prev, updatedAt: "desc"})) + else + setSort(prev => ({...prev, updatedAt: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["updatedAt"] === undefined ? + : sort["updatedAt"] === "asc" ? + : } + Updated At + + + + + + + +
+ setFilter(filter)}/> +
+ + {/**TODO: use namespaceId*/} + { + const number = organization?.namespace?.id?.match(/Namespace\/(\d+)$/)?.[1] + router.push(`/namespace/${number}`) + }}/> + + +} \ No newline at end of file diff --git a/src/packages/ce/src/project/Project.service.ts b/src/packages/ce/src/project/Project.service.ts deleted file mode 100644 index ab94b329..00000000 --- a/src/packages/ce/src/project/Project.service.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { - DNamespaceProjectReactiveService, - DNamespaceProjectView, - DProjectDependencies, - ReactiveArrayStore -} from "@code0-tech/pictor"; -import { - Mutation, - NamespaceProject, - NamespacesProjectsAssignRuntimesInput, - NamespacesProjectsAssignRuntimesPayload, - NamespacesProjectsCreateInput, - NamespacesProjectsCreatePayload, - NamespacesProjectsDeleteInput, - NamespacesProjectsDeletePayload, - Query -} from "@code0-tech/sagittarius-graphql-types"; -import {GraphqlClient} from "@core/util/graphql-client"; -import projectsQuery from "./queries/Projects.query.graphql" -import projectCreateMutation from "./mutations/Project.create.mutation.graphql" - -export class ProjectService extends DNamespaceProjectReactiveService { - - private readonly client: GraphqlClient - private i = 0; - - constructor(client: GraphqlClient, store: ReactiveArrayStore) { - super(store); - this.client = client - } - - values(dependencies: DProjectDependencies): DNamespaceProjectView[] { - const projects = super.values() - if (!dependencies?.namespaceId) return projects - - const namespaceId = dependencies.namespaceId - const filtered = projects.filter(p => p.namespace?.id === namespaceId) - - if (filtered.length === 0) { - this.client.query({ - query: projectsQuery, - variables: { - namespaceId, - firstProject: 50, - afterProject: null, - }, - }).then(res => { - const nodes = res.data?.namespace?.projects?.nodes ?? [] - nodes.forEach(project => { - if ( - project && - project.namespace?.id === namespaceId && - !this.hasById(project.id) - ) { - this.set(this.i++, new DNamespaceProjectView(project)) - } - }) - }) - } - - return filtered - } - - hasById(id: NamespaceProject["id"]): boolean { - const project = super.values().find(p => p.id === id) - return project !== undefined - } - - async projectAssignRuntimes(payload: NamespacesProjectsAssignRuntimesInput): Promise { - return Promise.resolve(undefined); - } - - async projectCreate(payload: NamespacesProjectsCreateInput): Promise { - const result = await this.client.mutate({ - mutation: projectCreateMutation, - variables: { - ...payload - } - }) - - if (result.data && result.data.namespacesProjectsCreate && result.data.namespacesProjectsCreate.namespaceProject) { - const project = result.data.namespacesProjectsCreate.namespaceProject - if (!this.hasById(project.id)) { - this.add(new DNamespaceProjectView(project)) - } - } - - return result.data?.namespacesProjectsCreate ?? undefined - } - - async projectDelete(payload: NamespacesProjectsDeleteInput): Promise { - return Promise.resolve(undefined); - } - -} \ No newline at end of file diff --git a/src/packages/ce/src/project/components/ProjectDataTableComponent.tsx b/src/packages/ce/src/project/components/ProjectDataTableComponent.tsx new file mode 100644 index 00000000..78ce332b --- /dev/null +++ b/src/packages/ce/src/project/components/ProjectDataTableComponent.tsx @@ -0,0 +1,38 @@ +import React from "react"; +import {DataTable, DataTableColumn, Text, useService, useStore} from "@code0-tech/pictor"; +import {DataTableFilterProps, DataTableSortProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import {Namespace, NamespaceProject} from "@code0-tech/sagittarius-graphql-types"; +import {ProjectService} from "@edition/project/services/Project.service"; +import {ProjectDataTableRowComponent} from "@edition/project/components/ProjectDataTableRowComponent"; + +export interface ProjectDataTableComponentProps { + namespaceId: Namespace["id"] + sort?: DataTableSortProps + filter?: DataTableFilterProps + preFilter?: (project: NamespaceProject, index: number) => boolean + onSelect?: (item: NamespaceProject | undefined) => void +} + +export const ProjectDataTableComponent: React.FC = (props) => { + + const {namespaceId, sort, filter, preFilter = () => true, onSelect} = props + + const projectService = useService(ProjectService) + const projectStore = useStore(ProjectService) + const projects = React.useMemo(() => projectService.values({namespaceId: namespaceId}), [projectStore, namespaceId]) + + return + + No project found. Create one to get started. + + } + onSelect={(item) => item && onSelect?.(item)} + data={projects.map(p => p.json()).filter(preFilter)}> + {(project, index) => { + return + }} + + +} \ No newline at end of file diff --git a/src/packages/ce/src/project/components/ProjectDataTableFilterInputComponent.tsx b/src/packages/ce/src/project/components/ProjectDataTableFilterInputComponent.tsx new file mode 100644 index 00000000..ea640a80 --- /dev/null +++ b/src/packages/ce/src/project/components/ProjectDataTableFilterInputComponent.tsx @@ -0,0 +1,99 @@ +import React from "react"; +import { + DataTableFilterInput, + DataTableFilterSuggestionMenu, + MenuCheckboxItem, + useService, + useStore +} from "@code0-tech/pictor"; +import {IconCheck} from "@tabler/icons-react"; +import {Namespace} from "@code0-tech/sagittarius-graphql-types"; +import {DataTableFilterProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import {ProjectService} from "@edition/project/services/Project.service"; +import {RuntimeService} from "@edition/runtime/services/Runtime.service"; + +export interface ProjectDataTableFilterInputComponentProps { + namespaceId: Namespace['id'] + onChange: (filter: DataTableFilterProps) => void +} + +export const ProjectDataTableFilterInputComponent: React.FC = (props) => { + + const {namespaceId, onChange} = props + + const projectService = useService(ProjectService) + const projectStore = useStore(ProjectService) + const runtimeService = useService(RuntimeService) + const runtimeStore = useStore(RuntimeService) + + const projects = React.useMemo( + () => projectService.values({namespaceId: namespaceId}), + [projectStore, namespaceId] + ) + + const allPrimaryRuntimes = React.useMemo( + () => { + const runtimeIds = projects.map(p => p.primaryRuntime?.id) + return runtimeIds.map(id => runtimeService.getById(id)).filter(Boolean) + }, + [projects, runtimeStore] + ) + + return { + + const split = currentValue.split(",").map(s => s.trim()).filter(Boolean) + + return + {projects.map(project => { + + const isChecked = split.includes(project?.name!) + + return { + e.preventDefault(); + e.stopPropagation(); + const updated = isChecked + ? split.filter(name => name !== project?.name) + : [...split, project?.name]; + applySuggestion(updated.join(","), true); + }}> + {isChecked ? : } + {project?.name} + + })} + + } + }, { + token: "Primary Runtime", + key: "primaryRuntime.name", + operators: ["isOneOf"], + suggestion: (context, operator, currentValue, applySuggestion) => { + + const split = currentValue.split(",").map(s => s.trim()).filter(Boolean) + + return + {allPrimaryRuntimes.map(runtime => { + + const isChecked = split.includes(runtime?.name!) + + return { + e.preventDefault(); + e.stopPropagation(); + const updated = isChecked + ? split.filter(name => name !== runtime?.name) + : [...split, runtime?.name]; + applySuggestion(updated.join(","), true); + }}> + {isChecked ? : } + {runtime?.name} + + })} + + } + } + ]}/> +} \ No newline at end of file diff --git a/src/packages/ce/src/project/components/ProjectDataTableRowComponent.tsx b/src/packages/ce/src/project/components/ProjectDataTableRowComponent.tsx new file mode 100644 index 00000000..a2ef403b --- /dev/null +++ b/src/packages/ce/src/project/components/ProjectDataTableRowComponent.tsx @@ -0,0 +1,78 @@ +import React from "react"; +import {NamespaceProject} from "@code0-tech/sagittarius-graphql-types"; +import {Avatar, DataTableColumn, Flex, Text, useService, useStore, hashToColor} from "@code0-tech/pictor"; +import {ProjectService} from "@edition/project/services/Project.service"; +import {RuntimeService} from "@edition/runtime/services/Runtime.service"; +import {formatDistanceToNow} from "date-fns"; + +export interface ProjectDataTableRowComponentProps { + projectId: NamespaceProject['id'] +} + +export const ProjectDataTableRowComponent: React.FC = (props) => { + + const {projectId} = props + + const projectService = useService(ProjectService) + const projectStore = useStore(ProjectService) + const runtimeService = useService(RuntimeService) + const runtimeStore = useStore(RuntimeService) + + const project = React.useMemo( + () => projectService.getById(projectId), + [projectStore, projectId] + ) + + const runtimes = React.useMemo( + () => project?.runtimes?.nodes?.map( + runtime => runtimeService.getById(runtime?.id) + ), + [runtimeStore, project] + ) + + const primaryRuntime = React.useMemo( + () => runtimes?.find( + runtime => runtime?.id === project?.primaryRuntime?.id + ), + [runtimes, project] + ) + + return <> + + + + + + + {project?.name} + + + {project?.description} + + + + + Updated {formatDistanceToNow(project?.updatedAt!)} ago + + + + + + {project?.flows?.count ? ( + + {project?.flows?.count ?? 0}{" "} + flows + + ) : null} + {project?.runtimes?.count ? ( + + {project?.runtimes?.count ?? 0}{" "} + assigned runtimes + + ) : null} + + + +} \ No newline at end of file diff --git a/src/packages/ce/src/project/pages/ProjectSettingsPage.tsx b/src/packages/ce/src/project/pages/ProjectSettingsPage.tsx new file mode 100644 index 00000000..edec0b74 --- /dev/null +++ b/src/packages/ce/src/project/pages/ProjectSettingsPage.tsx @@ -0,0 +1,59 @@ +import {Tab, TabList, TabTrigger} from "@code0-tech/pictor/dist/components/tab/Tab"; + +"use clients" + +import React from "react"; +import {Button, DResizableHandle, DResizablePanel, DResizablePanelGroup, Flex, Text} from "@code0-tech/pictor"; +import {IconLayoutSidebar} from "@tabler/icons-react"; +import {ProjectSettingsGeneralView} from "@edition/project/views/ProjectSettingsGeneralView"; +import {ProjectSettingsRuntimesView} from "@edition/project/views/ProjectSettingsRuntimesView"; +import {ProjectSettingsDeleteView} from "@edition/project/views/ProjectSettingsDeleteView"; + +export const ProjectSettingsPage: React.FC = () => { + return + + + + + Project settings + + + + + General settings and restrictions for your Sculptor application. These settings affect all users + and organizations within the application. + + + + + + + + + + + + + + + + + <> + + + + + + + +} \ No newline at end of file diff --git a/src/packages/ce/src/project/services/Project.service.ts b/src/packages/ce/src/project/services/Project.service.ts new file mode 100644 index 00000000..a3cb0668 --- /dev/null +++ b/src/packages/ce/src/project/services/Project.service.ts @@ -0,0 +1,161 @@ +import { + DNamespaceProjectReactiveService, + DNamespaceProjectView, + DProjectDependencies, + ReactiveArrayStore +} from "@code0-tech/pictor"; +import { + Mutation, + NamespaceProject, + NamespacesProjectsAssignRuntimesInput, + NamespacesProjectsAssignRuntimesPayload, + NamespacesProjectsCreateInput, + NamespacesProjectsCreatePayload, + NamespacesProjectsDeleteInput, + NamespacesProjectsDeletePayload, + NamespacesProjectsUpdateInput, + NamespacesProjectsUpdatePayload, + Query +} from "@code0-tech/sagittarius-graphql-types"; +import {GraphqlClient} from "@core/util/graphql-client"; +import projectsQuery from "./queries/Projects.query.graphql" +import projectCreateMutation from "./mutations/Project.create.mutation.graphql" +import projectDeleteMutation from "./mutations/Project.delete.mutation.graphql" +import projectUpdateMutation from "./mutations/Project.update.mutation.graphql" +import projectAssignRuntimesMutation from "./mutations/Project.assignRuntimes.mutation.graphql" +import {View} from "@code0-tech/pictor/dist/utils/view"; + +export class ProjectService extends DNamespaceProjectReactiveService { + + private readonly client: GraphqlClient + private i = 0; + + constructor(client: GraphqlClient, store: ReactiveArrayStore>) { + super(store); + this.client = client + } + + values(dependencies: DProjectDependencies): DNamespaceProjectView[] { + const projects = super.values() + if (!dependencies?.namespaceId) return projects + + const namespaceId = dependencies.namespaceId + const filtered = projects.filter(p => p.namespace?.id === namespaceId) + + if (filtered.length === 0) { + this.client.query({ + query: projectsQuery, + variables: { + namespaceId, + firstProject: 50, + afterProject: null, + }, + }).then(res => { + const nodes = res.data?.namespace?.projects?.nodes ?? [] + nodes.forEach(project => { + if ( + project && + project.namespace?.id === namespaceId && + !this.hasById(project.id) + ) { + this.set(this.i++, new View(new DNamespaceProjectView(project))) + } + }) + }) + } + + return filtered + } + + hasById(id: NamespaceProject["id"]): boolean { + const project = super.values().find(p => p.id === id) + return project !== undefined + } + + async projectAssignRuntimes(payload: NamespacesProjectsAssignRuntimesInput): Promise { + const result = await this.client.mutate({ + mutation: projectAssignRuntimesMutation, + variables: { + ...payload + } + }) + + if (result.data && result.data.namespacesProjectsAssignRuntimes && result.data.namespacesProjectsAssignRuntimes.namespaceProject) { + const project = result.data.namespacesProjectsAssignRuntimes.namespaceProject + const index = this.values({namespaceId: project?.namespace?.id}).findIndex(o => o.id === project.id) + const projectStored = this.values({namespaceId: project?.namespace?.id}).find(o => o.id === project.id) + this.set(index, new View(new DNamespaceProjectView({ + ...projectStored?.json(), + runtimes: { + count: payload.runtimeIds.length, + nodes: payload.runtimeIds.map(runtimeId => ({ id: runtimeId })) + } + }))) + + } + + return result.data?.namespacesProjectsAssignRuntimes ?? undefined + } + + async projectCreate(payload: NamespacesProjectsCreateInput): Promise { + const result = await this.client.mutate({ + mutation: projectCreateMutation, + variables: { + ...payload + } + }) + + if (result.data && result.data.namespacesProjectsCreate && result.data.namespacesProjectsCreate.namespaceProject) { + const project = result.data.namespacesProjectsCreate.namespaceProject + if (!this.hasById(project.id)) { + this.add(new View(new DNamespaceProjectView(project))) + } + } + + return result.data?.namespacesProjectsCreate ?? undefined + } + + async projectDelete(payload: NamespacesProjectsDeleteInput): Promise { + const result = await this.client.mutate({ + mutation: projectDeleteMutation, + variables: { + ...payload + } + }) + + if (result.data && result.data.namespacesProjectsDelete && result.data.namespacesProjectsDelete.namespaceProject) { + const project = result.data.namespacesProjectsDelete.namespaceProject + const index = this.values({namespaceId: project?.namespace?.id}).findIndex(o => o.id === project.id) + this.delete(index) + + } + + return result.data?.namespacesProjectsDelete ?? undefined + } + + async projectUpdate(payload: NamespacesProjectsUpdateInput): Promise { + const result = await this.client.mutate({ + mutation: projectUpdateMutation, + variables: { + ...payload + } + }) + + if (result.data && result.data.namespacesProjectsUpdate && result.data.namespacesProjectsUpdate.namespaceProject) { + const project = result.data.namespacesProjectsUpdate.namespaceProject + const index = this.values({namespaceId: project?.namespace?.id}).findIndex(o => o.id === project.id) + const projectStored = this.values({namespaceId: project?.namespace?.id}).find(o => o.id === project.id) + this.set(index, new View(new DNamespaceProjectView({ + ...projectStored?.json(), + ...(payload.name ? {name: payload.name} : {}), + ...(payload.description ? {description: payload.description} : {}), + ...(payload.slug ? {slug: payload.slug} : {}), + ...(payload.primaryRuntimeId ? {primaryRuntime: {id: payload.primaryRuntimeId}} : {}), + }))) + + } + + return result.data?.namespacesProjectsUpdate ?? undefined + } + +} \ No newline at end of file diff --git a/src/packages/ce/src/project/fragments/Project.fragment.graphql b/src/packages/ce/src/project/services/fragments/Project.basic.fragment.graphql similarity index 66% rename from src/packages/ce/src/project/fragments/Project.fragment.graphql rename to src/packages/ce/src/project/services/fragments/Project.basic.fragment.graphql index 64fbbfc5..7cc10685 100644 --- a/src/packages/ce/src/project/fragments/Project.fragment.graphql +++ b/src/packages/ce/src/project/services/fragments/Project.basic.fragment.graphql @@ -1,5 +1,5 @@ -#import "../../runtime/fragments/Runtime.fragment.graphql" -fragment Project on NamespaceProject { +#import "@edition/runtime/services/fragments/Runtime.id.fragment.graphql" +fragment BasicProject on NamespaceProject { __typename id name @@ -16,8 +16,12 @@ fragment Project on NamespaceProject { count } primaryRuntime { - ...Runtime + ...RuntimeId } + roles { + count + } + slug userAbilities { assignProjectRuntimes createFlow diff --git a/src/packages/ce/src/project/services/fragments/Project.fragment.graphql b/src/packages/ce/src/project/services/fragments/Project.fragment.graphql new file mode 100644 index 00000000..48911624 --- /dev/null +++ b/src/packages/ce/src/project/services/fragments/Project.fragment.graphql @@ -0,0 +1,65 @@ +#import "@edition/runtime/services/fragments/Runtime.id.fragment.graphql" +fragment Project on NamespaceProject { + __typename + id + name + description + createdAt + updatedAt + slug + namespace { + __typename + id + } + flows { + __typename + count + nodes { + __typename + id + } + pageInfo { + __typename + endCursor + hasNextPage + } + } + runtimes { + __typename + count + nodes { + __typename + id + } + pageInfo { + __typename + endCursor + hasNextPage + } + } + roles { + __typename + count + nodes { + __typename + id + } + pageInfo { + __typename + endCursor + hasNextPage + } + } + primaryRuntime { + __typename + ...RuntimeId + name + } + userAbilities { + assignProjectRuntimes + createFlow + deleteNamespaceProject + updateNamespaceProject + __typename + } +} \ No newline at end of file diff --git a/src/packages/ce/src/project/fragments/Project.id.fragment.graphql b/src/packages/ce/src/project/services/fragments/Project.id.fragment.graphql similarity index 100% rename from src/packages/ce/src/project/fragments/Project.id.fragment.graphql rename to src/packages/ce/src/project/services/fragments/Project.id.fragment.graphql diff --git a/src/packages/ce/src/project/services/mutations/Project.assignRuntimes.mutation.graphql b/src/packages/ce/src/project/services/mutations/Project.assignRuntimes.mutation.graphql new file mode 100644 index 00000000..2df58ad8 --- /dev/null +++ b/src/packages/ce/src/project/services/mutations/Project.assignRuntimes.mutation.graphql @@ -0,0 +1,20 @@ +#import "../fragments/Project.basic.fragment.graphql" +mutation projectAssignRuntimes ($namespaceProjectId: NamespaceProjectID!, $runtimeIds: [RuntimeID!]!) { + namespacesProjectsAssignRuntimes(input: { + namespaceProjectId: $namespaceProjectId, + runtimeIds: $runtimeIds + }) { + errors { + ...on Error { + errorCode, + details { + ...on ActiveModelError { attribute type } + __typename + } + } + } + namespaceProject { + ...BasicProject + } + } +} \ No newline at end of file diff --git a/src/packages/ce/src/project/mutations/Project.create.mutation.graphql b/src/packages/ce/src/project/services/mutations/Project.create.mutation.graphql similarity index 75% rename from src/packages/ce/src/project/mutations/Project.create.mutation.graphql rename to src/packages/ce/src/project/services/mutations/Project.create.mutation.graphql index 51a9bbb7..42f16f9f 100644 --- a/src/packages/ce/src/project/mutations/Project.create.mutation.graphql +++ b/src/packages/ce/src/project/services/mutations/Project.create.mutation.graphql @@ -1,4 +1,4 @@ -#import "../fragments/Project.fragment.graphql" +#import "../fragments/Project.basic.fragment.graphql" mutation projectCreate ($name: String!, $description: String, $namespaceId: NamespaceID!) { namespacesProjectsCreate(input: { name: $name, @@ -9,12 +9,13 @@ mutation projectCreate ($name: String!, $description: String, $namespaceId: Name ...on Error { errorCode, details { + ...on ActiveModelError { attribute type } __typename } } } namespaceProject { - ...Project + ...BasicProject } } } \ No newline at end of file diff --git a/src/packages/ce/src/project/services/mutations/Project.delete.mutation.graphql b/src/packages/ce/src/project/services/mutations/Project.delete.mutation.graphql new file mode 100644 index 00000000..6d7af7da --- /dev/null +++ b/src/packages/ce/src/project/services/mutations/Project.delete.mutation.graphql @@ -0,0 +1,19 @@ +#import "../fragments/Project.basic.fragment.graphql" +mutation projectDelete ($namespaceProjectId: NamespaceProjectID!) { + namespacesProjectsDelete(input: { + namespaceProjectId: $namespaceProjectId + }) { + errors { + ...on Error { + errorCode, + details { + ...on ActiveModelError { attribute type } + __typename + } + } + } + namespaceProject { + ...BasicProject + } + } +} \ No newline at end of file diff --git a/src/packages/ce/src/project/services/mutations/Project.update.mutation.graphql b/src/packages/ce/src/project/services/mutations/Project.update.mutation.graphql new file mode 100644 index 00000000..cb4d2a13 --- /dev/null +++ b/src/packages/ce/src/project/services/mutations/Project.update.mutation.graphql @@ -0,0 +1,23 @@ +#import "../fragments/Project.basic.fragment.graphql" +mutation projectUpdate ($namespaceProjectId: NamespaceProjectID!, $name: String, $description: String, $slug: String, $primaryRuntimeId: RuntimeID) { + namespacesProjectsUpdate(input: { + namespaceProjectId: $namespaceProjectId + name: $name + description: $description + slug: $slug + primaryRuntimeId: $primaryRuntimeId + }) { + errors { + ...on Error { + errorCode, + details { + ...on ActiveModelError { attribute type } + __typename + } + } + } + namespaceProject { + ...BasicProject + } + } +} \ No newline at end of file diff --git a/src/packages/ce/src/project/queries/Projects.query.graphql b/src/packages/ce/src/project/services/queries/Projects.query.graphql similarity index 85% rename from src/packages/ce/src/project/queries/Projects.query.graphql rename to src/packages/ce/src/project/services/queries/Projects.query.graphql index f938e1b2..e728f530 100644 --- a/src/packages/ce/src/project/queries/Projects.query.graphql +++ b/src/packages/ce/src/project/services/queries/Projects.query.graphql @@ -8,11 +8,14 @@ query Projects ( ) { namespace(id: $namespaceId) { projects (first: $firstProject, after: $afterProject) { + __typename count nodes { + __typename ...Project } pageInfo { + __typename endCursor hasNextPage } diff --git a/src/packages/ce/src/project/views/PersonalProjectsView.tsx b/src/packages/ce/src/project/views/PersonalProjectsView.tsx new file mode 100644 index 00000000..57b96325 --- /dev/null +++ b/src/packages/ce/src/project/views/PersonalProjectsView.tsx @@ -0,0 +1,138 @@ +import React from "react"; +import { + Button, + Flex, + Menu, + MenuCheckboxItem, + MenuContent, + MenuPortal, + MenuTrigger, + Spacing, + Text, + useService, + useStore, + useUserSession +} from "@code0-tech/pictor"; +import {UserService} from "@edition/user/services/User.service"; +import Link from "next/link"; +import {useRouter} from "next/navigation"; +import {ProjectDataTableComponent} from "@edition/project/components/ProjectDataTableComponent"; +import {DataTableFilterProps, DataTableSortProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import {ProjectDataTableFilterInputComponent} from "@edition/project/components/ProjectDataTableFilterInputComponent"; +import {ButtonGroup} from "@code0-tech/pictor/dist/components/button-group/ButtonGroup"; +import {IconMinus, IconSortAscending, IconSortDescending} from "@tabler/icons-react"; + +export const PersonalProjectsView: React.FC = () => { + + const router = useRouter() + const userSession = useUserSession() + const userStore = useStore(UserService) + const userService = useService(UserService) + + const currentUser = React.useMemo(() => userService.getById(userSession?.user?.id), [userStore, userSession]) + const namespaceId = currentUser?.namespace?.id + const namespaceIndex = namespaceId?.match(/Namespace\/(\d+)$/)?.[1] + + const [filter, setFilter] = React.useState({}) + const [sort, setSort] = React.useState({}) + + const projectsList = React.useMemo(() => { + if (!currentUser || !currentUser.namespace) return null + return { + const number = project?.id?.match(/NamespaceProject\/(\d+)$/)?.[1] + router.push(`/namespace/${namespaceIndex}/project/${number}/flow`) + }} namespaceId={currentUser.namespace.id}/> + + }, [currentUser, filter, sort]) + + return <> + + + + + Personal projects + + + Projects created in your personal namespace. You can also create organization projects if you are a + member of any organization. + + + + + + + + + + + + + { + if (sort["name"] === undefined) + setSort(prev => ({...prev, name: "asc"})) + else if (sort["name"] === "asc") + setSort(prev => ({...prev, name: "desc"})) + else + setSort(prev => ({...prev, name: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["name"] === undefined ? : sort["name"] === "asc" ? + : } + Name + + { + if (sort["createdAt"] === undefined) + setSort(prev => ({...prev, createdAt: "asc"})) + else if (sort["createdAt"] === "asc") + setSort(prev => ({...prev, createdAt: "desc"})) + else + setSort(prev => ({...prev, createdAt: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["createdAt"] === undefined ? + : sort["createdAt"] === "asc" ? + : } + Created At + + { + if (sort["updatedAt"] === undefined) + setSort(prev => ({...prev, updatedAt: "asc"})) + else if (sort["updatedAt"] === "asc") + setSort(prev => ({...prev, updatedAt: "desc"})) + else + setSort(prev => ({...prev, updatedAt: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["updatedAt"] === undefined ? + : sort["updatedAt"] === "asc" ? + : } + Updated At + + + + + + + +
+ setFilter(filter)}/> +
+ + {projectsList} + + + +} \ No newline at end of file diff --git a/src/packages/ce/src/project/views/ProjectSettingsDeleteView.tsx b/src/packages/ce/src/project/views/ProjectSettingsDeleteView.tsx new file mode 100644 index 00000000..092bb139 --- /dev/null +++ b/src/packages/ce/src/project/views/ProjectSettingsDeleteView.tsx @@ -0,0 +1,54 @@ +"use client" + +import React, {startTransition} from "react"; +import {Button, Card, Flex, Spacing, Text, toast, useService, useStore} from "@code0-tech/pictor"; +import {TabContent} from "@code0-tech/pictor/dist/components/tab/Tab"; +import {useParams, useRouter} from "next/navigation"; +import {ProjectService} from "@edition/project/services/Project.service"; + +export const ProjectSettingsDeleteView: React.FC = () => { + + const params = useParams() + const router = useRouter() + const projectService = useService(ProjectService) + + const projectId = params.projectId as any as number + const namespaceId = params.namespaceId as any as number + + const deleteProject = React.useCallback(() => { + startTransition(() => { + projectService.projectDelete({ + namespaceProjectId: `gid://sagittarius/NamespaceProject/${projectId}` + }).then(payload => { + if ((payload?.errors?.length ?? 0) <= 0) { + toast({ + title: "The project was successfully deleted.", + color: "success", + dismissible: true, + }) + } + router.push(`/namespace/${namespaceId}`) + }) + }) + }, [projectId]) + + + return + + Delete + + + + + + + This will delete the project and cannot be undone. + + + + + + +} \ No newline at end of file diff --git a/src/packages/ce/src/project/views/ProjectSettingsGeneralView.tsx b/src/packages/ce/src/project/views/ProjectSettingsGeneralView.tsx new file mode 100644 index 00000000..63710b0a --- /dev/null +++ b/src/packages/ce/src/project/views/ProjectSettingsGeneralView.tsx @@ -0,0 +1,105 @@ +"use client" + +import React, {startTransition} from "react"; +import { + Button, + Card, + Flex, + Spacing, + TabContent, + Text, + TextInput, + useForm, + useService, + useStore, + toast +} from "@code0-tech/pictor"; +import CardSection from "@code0-tech/pictor/dist/components/card/CardSection"; +import {useParams} from "next/navigation"; +import {ProjectService} from "@edition/project/services/Project.service"; + +export const ProjectSettingsGeneralView: React.FC = () => { + + const params = useParams() + const projectService = useService(ProjectService) + const projectStore = useStore(ProjectService) + + const projectId = params.projectId as any as number + + const project = React.useMemo( + () => projectService.getById(`gid://sagittarius/NamespaceProject/${projectId}`), + [projectStore, projectId] + ) + + const initialValues = React.useMemo( + () => ({ + name: project?.name, + description: project?.description, + slug: project?.slug, + }), + [project] + ) + + const [inputs, validate] = useForm({ + initialValues: initialValues, + validate: { + name: (value) => { + if (!value) return "Name is required" + return null + }, + slug: (value) => { + if (!value) return "Slug is required" + return null + } + }, + onSubmit: (values) => { + startTransition(() => { + projectService.projectUpdate({ + slug: values.slug, + name: values.name, + description: values.description, + namespaceProjectId: `gid://sagittarius/NamespaceProject/${projectId}` + }).then(payload => { + if ((payload?.errors?.length ?? 0) <= 0) { + toast({ + title: "The project was successfully deleted.", + color: "success", + dismissible: true, + }) + } + }) + }) + } + }) + + return + + General + + + + + + + Name + + + + + + Description + + + + + + Slug + + + + + + +} \ No newline at end of file diff --git a/src/packages/ce/src/project/views/ProjectSettingsRuntimesView.tsx b/src/packages/ce/src/project/views/ProjectSettingsRuntimesView.tsx new file mode 100644 index 00000000..694a4ae1 --- /dev/null +++ b/src/packages/ce/src/project/views/ProjectSettingsRuntimesView.tsx @@ -0,0 +1,117 @@ +"use client" + +import React, {startTransition} from "react" +import { + Avatar, + Button, + Flex, + hashToColor, + Menu, + MenuContent, + MenuItem, + MenuPortal, + MenuSeparator, + MenuTrigger, + Spacing, + Badge, + Text, + useService, + useStore +} from "@code0-tech/pictor"; +import {TabContent} from "@code0-tech/pictor/dist/components/tab/Tab"; +import {useParams} from "next/navigation"; +import {RuntimeProjectDataTableComponent} from "@edition/runtime/components/RuntimeProjectDataTableComponent"; +import {RuntimeService} from "@edition/runtime/services/Runtime.service"; +import {ProjectService} from "@edition/project/services/Project.service"; +import {Runtime} from "@code0-tech/sagittarius-graphql-types"; +import {formatDistanceToNow} from "date-fns"; + +export const ProjectSettingsRuntimesView: React.FC = () => { + + const params = useParams() + const runtimeService = useService(RuntimeService) + const runtimeStore = useStore(RuntimeService) + const projectService = useService(ProjectService) + const projectStore = useStore(ProjectService) + + const projectId = params.projectId as any as number + const namespaceId = params.namespaceId as any as number + + const availableRuntimes = React.useMemo( + () => { + const globalRuntimes = runtimeService.values().filter(runtime => !runtime?.namespace?.id) + const namespaceRuntimes = runtimeService.values({namespaceId: `gid://sagittarius/Namespace/${namespaceId}`}) + return [...globalRuntimes, ...namespaceRuntimes] + }, + [runtimeStore, projectId] + ) + + const project = React.useMemo( + () => projectService.getById(`gid://sagittarius/NamespaceProject/${projectId}`), + [projectStore, projectId] + ) + + const assignRuntime = React.useCallback((runtimeId: Runtime['id']) => { + const runtimeIds = project?.runtimes?.nodes?.map(r => r?.id!) ?? [] + + if (!runtimeId) return + if (runtimeIds.includes(runtimeId)) return + + startTransition(() => { + projectService.projectAssignRuntimes({ + runtimeIds: [...runtimeIds, runtimeId], + namespaceProjectId: `gid://sagittarius/NamespaceProject/${projectId}` + }) + }) + }, [projectService, projectId, project]) + + return + + Runtimes + + + + + + + {availableRuntimes.map((runtime, index) => { + return <> + assignRuntime(runtime.id)}> + + + + + + {runtime?.name} + + + + {runtime?.status} + + + + + + + Updated {formatDistanceToNow(runtime?.updatedAt!)} ago + + + + {index < availableRuntimes.length - 1 ? + : null} + + })} + + + + + + + + +} \ No newline at end of file diff --git a/src/packages/ce/src/project/views/ProjectsView.tsx b/src/packages/ce/src/project/views/ProjectsView.tsx new file mode 100644 index 00000000..65c76a19 --- /dev/null +++ b/src/packages/ce/src/project/views/ProjectsView.tsx @@ -0,0 +1,132 @@ +"use client" + + +import React from "react"; +import { + Button, + Flex, + Menu, + MenuCheckboxItem, + MenuContent, + MenuPortal, + MenuTrigger, + Spacing, + Text +} from "@code0-tech/pictor"; +import Link from "next/link"; +import {useParams, useRouter} from "next/navigation"; +import {ProjectDataTableComponent} from "@edition/project/components/ProjectDataTableComponent"; +import {DataTableFilterProps, DataTableSortProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import {ButtonGroup} from "@code0-tech/pictor/dist/components/button-group/ButtonGroup"; +import {IconMinus, IconSortAscending, IconSortDescending} from "@tabler/icons-react"; +import {ProjectDataTableFilterInputComponent} from "@edition/project/components/ProjectDataTableFilterInputComponent"; + +//TODO: user abilities for project creation within namespace +export const ProjectsView: React.FC = () => { + + const params = useParams() + const router = useRouter() + const namespaceId = params.namespaceId as any as number + + const [filter, setFilter] = React.useState({}) + const [sort, setSort] = React.useState({}) + + const projectsList = React.useMemo(() => { + return { + const number = project?.id?.match(/NamespaceProject\/(\d+)$/)?.[1] + router.push(`/namespace/${namespaceId}/project/${number}/flow`) + }}/> + }, [namespaceId, filter, sort]) + + return <> + + + + + Projects + + + Manage projects that you belong to. You can create new projects and switch between them. + + + + + + + + + + + + + { + if (sort["name"] === undefined) + setSort(prev => ({...prev, name: "asc"})) + else if (sort["name"] === "asc") + setSort(prev => ({...prev, name: "desc"})) + else + setSort(prev => ({...prev, name: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["name"] === undefined ? : sort["name"] === "asc" ? + : } + Name + + { + if (sort["createdAt"] === undefined) + setSort(prev => ({...prev, createdAt: "asc"})) + else if (sort["createdAt"] === "asc") + setSort(prev => ({...prev, createdAt: "desc"})) + else + setSort(prev => ({...prev, createdAt: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["createdAt"] === undefined ? + : sort["createdAt"] === "asc" ? + : } + Created At + + { + if (sort["updatedAt"] === undefined) + setSort(prev => ({...prev, updatedAt: "asc"})) + else if (sort["updatedAt"] === "asc") + setSort(prev => ({...prev, updatedAt: "desc"})) + else + setSort(prev => ({...prev, updatedAt: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["updatedAt"] === undefined ? + : sort["updatedAt"] === "asc" ? + : } + Updated At + + + + + + + +
+ setFilter(filter)}/> +
+ + {projectsList} + + +} \ No newline at end of file diff --git a/src/packages/ce/src/role/components/RoleDataTableComponent.tsx b/src/packages/ce/src/role/components/RoleDataTableComponent.tsx new file mode 100644 index 00000000..4f2703dd --- /dev/null +++ b/src/packages/ce/src/role/components/RoleDataTableComponent.tsx @@ -0,0 +1,44 @@ +import React from "react"; +import {DataTable, DataTableColumn, Text, useService, useStore} from "@code0-tech/pictor"; +import {DataTableFilterProps, DataTableSortProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import {Namespace, NamespaceProject, NamespaceRole} from "@code0-tech/sagittarius-graphql-types"; +import {ProjectService} from "@edition/project/services/Project.service"; +import {ProjectDataTableRowComponent} from "@edition/project/components/ProjectDataTableRowComponent"; +import {RoleService} from "@edition/role/services/Role.service"; +import {RoleDataTableRowComponent} from "@edition/role/components/RoleDataTableRowComponent"; + +export interface ProjectDataTableComponentProps { + namespaceId: Namespace["id"] + sort?: DataTableSortProps + filter?: DataTableFilterProps + preFilter?: (project: NamespaceRole, index: number) => boolean + onSelect?: (item: NamespaceRole | undefined) => void +} + +export const RoleDataTableComponent: React.FC = (props) => { + + const {namespaceId, sort, filter, preFilter = () => true, onSelect} = props + + const roleService = useService(RoleService) + const roleStore = useStore(RoleService) + + const roles = React.useMemo( + () => roleService.values({namespaceId: namespaceId}), + [roleStore, namespaceId] + ) + + return + + No role found. Create one to get started. + + } + onSelect={(item) => item && onSelect?.(item)} + data={roles.map(r => r.json()).filter(preFilter)}> + {(role, index) => { + return + }} + + +} \ No newline at end of file diff --git a/src/packages/ce/src/role/components/RoleDataTableFilterInputComponent.tsx b/src/packages/ce/src/role/components/RoleDataTableFilterInputComponent.tsx new file mode 100644 index 00000000..353a20c8 --- /dev/null +++ b/src/packages/ce/src/role/components/RoleDataTableFilterInputComponent.tsx @@ -0,0 +1,94 @@ +import React from "react"; +import { + DataTableFilterInput, + DataTableFilterSuggestionMenu, + MenuCheckboxItem, + useService, + useStore +} from "@code0-tech/pictor"; +import {IconCheck} from "@tabler/icons-react"; +import {Namespace} from "@code0-tech/sagittarius-graphql-types"; +import {DataTableFilterProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import {RoleService} from "@edition/role/services/Role.service"; + +export interface RoleDataTableFilterInputComponentProps { + namespaceId: Namespace['id'] + onChange: (filter: DataTableFilterProps) => void +} + +export const RoleDataTableFilterInputComponent: React.FC = (props) => { + + const {namespaceId, onChange} = props + + const roleService = useService(RoleService) + const roleStore = useStore(RoleService) + + const roles = React.useMemo( + () => roleService.values({namespaceId: namespaceId}), + [roleStore, namespaceId] + ) + + const abilities = React.useMemo(() => { + const all = new Set() + roles.forEach(role => role.abilities?.forEach(ability => all.add(ability))) + return Array.from(all) + }, [roles]) + + return { + + const split = currentValue.split(",").map(s => s.trim()).filter(Boolean) + + return + {roles.map(role => { + + const isChecked = split.includes(role?.name!) + + return { + e.preventDefault(); + e.stopPropagation(); + const updated = isChecked + ? split.filter(name => name !== role?.name) + : [...split, role?.name]; + applySuggestion(updated.join(","), true); + }}> + {isChecked ? : } + {role?.name} + + })} + + } + }, { + token: "Permissions", + key: "abilities", + operators: ["isOneOf"], + suggestion: (context, operator, currentValue, applySuggestion) => { + + const split = currentValue.split(",").map(s => s.trim()).filter(Boolean) + + return + {abilities.map(ability => { + + const isChecked = split.includes(ability) + + return { + e.preventDefault(); + e.stopPropagation(); + const updated = isChecked + ? split.filter(name => name !== ability) + : [...split, ability]; + applySuggestion(updated.join(","), true); + }}> + {isChecked ? : } + {ability} + + })} + + } + } + ]}/> +} \ No newline at end of file diff --git a/src/packages/ce/src/role/components/RoleDataTableRowComponent.tsx b/src/packages/ce/src/role/components/RoleDataTableRowComponent.tsx new file mode 100644 index 00000000..5a9a69b1 --- /dev/null +++ b/src/packages/ce/src/role/components/RoleDataTableRowComponent.tsx @@ -0,0 +1,47 @@ +import React from "react"; +import {NamespaceRole} from "@code0-tech/sagittarius-graphql-types"; +import {DataTableColumn, Flex, Text, useService, useStore} from "@code0-tech/pictor"; +import {formatDistanceToNow} from "date-fns"; +import {RoleService} from "@edition/role/services/Role.service"; +import {RolePermissionComponent} from "@edition/role/components/RolePermissionComponent"; + +export interface ProjectDataTableRowComponentProps { + roleId: NamespaceRole['id'] +} + +export const RoleDataTableRowComponent: React.FC = (props) => { + + const {roleId} = props + + const roleService = useService(RoleService) + const roleStore = useStore(RoleService) + + const role = React.useMemo( + () => roleService.getById(roleId), + [roleStore, roleId] + ) + + return <> + + + + + {role?.name} + + + + + Updated {formatDistanceToNow(role?.updatedAt!)} ago + + + + + + + {role?.assignedProjects?.count ?? 0}{" "} + assigned projects + + + + +} \ No newline at end of file diff --git a/src/packages/ce/src/role/components/RolePermissionComponent.tsx b/src/packages/ce/src/role/components/RolePermissionComponent.tsx new file mode 100644 index 00000000..6131e221 --- /dev/null +++ b/src/packages/ce/src/role/components/RolePermissionComponent.tsx @@ -0,0 +1,179 @@ +import React from "react"; +import {IconCheck} from "@tabler/icons-react"; +import {Tooltip, TooltipArrow, TooltipContent, TooltipPortal, TooltipTrigger, Badge, Flex, Text} from "@code0-tech/pictor"; + +type AbilityCategory = + | "members" + | "projects" + | "roles" + | "runtimes" + | "flows" + | "license" + | "organization" + | "admin" + +const abilityCategoryByAbility: Record = { + ASSIGN_MEMBER_ROLES: "members", + INVITE_MEMBER: "members", + DELETE_MEMBER: "members", + + CREATE_NAMESPACE_PROJECT: "projects", + UPDATE_NAMESPACE_PROJECT: "projects", + DELETE_NAMESPACE_PROJECT: "projects", + ASSIGN_ROLE_PROJECTS: "projects", + READ_NAMESPACE_PROJECT: "projects", + + CREATE_NAMESPACE_ROLE: "roles", + UPDATE_NAMESPACE_ROLE: "roles", + ASSIGN_ROLE_ABILITIES: "roles", + + CREATE_RUNTIME: "runtimes", + UPDATE_RUNTIME: "runtimes", + DELETE_RUNTIME: "runtimes", + ROTATE_RUNTIME_TOKEN: "runtimes", + ASSIGN_PROJECT_RUNTIMES: "runtimes", + + CREATE_FLOW: "flows", + UPDATE_FLOW: "flows", + DELETE_FLOW: "flows", + + CREATE_NAMESPACE_LICENSE: "license", + READ_NAMESPACE_LICENSE: "license", + DELETE_NAMESPACE_LICENSE: "license", + + UPDATE_ORGANIZATION: "organization", + DELETE_ORGANIZATION: "organization", + + NAMESPACE_ADMINISTRATOR: "admin", +} + +const abilityCategoryLabels: Record = { + members: "members", + projects: "projects", + roles: "roles", + runtimes: "runtimes", + flows: "flows", + license: "licenses", + organization: "the organization", + admin: "everything", +} + +type AbilityAction = "create" | "update" | "delete" | "assign" | "read" | "manage" + +type AbilityCategoryInfo = { + category: AbilityCategory + label: string + abilities: string[] + action: AbilityAction +} + +function getAbilityAction(ability: string): AbilityAction { + if (ability.startsWith("CREATE_")) return "create" + if (ability.startsWith("UPDATE_")) return "update" + if (ability.startsWith("DELETE_")) return "delete" + if (ability.startsWith("ASSIGN_")) return "assign" + if (ability.startsWith("READ_")) return "read" + return "manage" +} + +function mergeAbilityActions(actions: AbilityAction[]): AbilityAction { + const uniqueActions = Array.from(new Set(actions)) + if (uniqueActions.length === 1) return uniqueActions[0] + return "manage" +} + +function buildAbilityCategories(abilities: string[] | undefined): AbilityCategoryInfo[] { + if (!abilities || abilities.length === 0) return [] + + const bucket = new Map() + + for (const ability of abilities) { + const category = abilityCategoryByAbility[ability] + if (!category) continue + + const list = bucket.get(category) ?? [] + list.push(ability) + bucket.set(category, list) + } + + return Array.from(bucket.entries()).map(([category, categoryAbilities]) => { + const actions = categoryAbilities.map(getAbilityAction) + const action = mergeAbilityActions(actions) + + return { + category, + label: abilityCategoryLabels[category], + abilities: categoryAbilities, + action, + } + }) +} + +function renderPermissionSummary(categories: AbilityCategoryInfo[]) { + if (categories.length === 0) return "No special permissions." + + const renderCategory = (category: AbilityCategoryInfo) => ( + <> + {category.action}{" "} + + + + {category.label} + + + + + + {category.abilities.map(ability => ( + + + {ability} + + ))} + + + + + + + ) + + if (categories.length === 1) { + const category = categories[0] + return <>Can {renderCategory(category)} + } + + const leadingCategories = categories.slice(0, -1) + const lastCategory = categories[categories.length - 1] + + return ( + <> + Can{" "} + {leadingCategories.map((category, index) => ( + + {index > 0 && ", "} + {renderCategory(category)} + + ))} + {" "}and {renderCategory(lastCategory)} + + ) +} + +export interface RolePermissionComponentProps { + abilities?: string[] +} + +export const RolePermissionComponent: React.FC = (props) => { + const {abilities} = props + const categories = React.useMemo( + () => buildAbilityCategories(abilities), + [abilities] + ) + + return ( + + {renderPermissionSummary(categories)} + + ) +} \ No newline at end of file diff --git a/src/packages/ce/src/role/pages/RoleCreatePage.tsx b/src/packages/ce/src/role/pages/RoleCreatePage.tsx new file mode 100644 index 00000000..e529caa0 --- /dev/null +++ b/src/packages/ce/src/role/pages/RoleCreatePage.tsx @@ -0,0 +1,46 @@ +"use client" + +import React from "react"; +import {Button, Col, Flex, Spacing, Text, TextInput} from "@code0-tech/pictor"; +import Link from "next/link"; + +export const RoleCreatePage: React.FC = () => { + + //TODO: user abilities for add role within namespace + + return
+ + + + Create new role + + + + Global runtimes are shared runtimes that can be used across multiple organizations. + + + + + + + + + + + + +
+} \ No newline at end of file diff --git a/src/packages/ce/src/role/pages/RoleSettingsPage.tsx b/src/packages/ce/src/role/pages/RoleSettingsPage.tsx new file mode 100644 index 00000000..feb1f344 --- /dev/null +++ b/src/packages/ce/src/role/pages/RoleSettingsPage.tsx @@ -0,0 +1,87 @@ +"use client" + +import React from "react"; +import { + Button, + DResizableHandle, + DResizablePanel, + DResizablePanelGroup, + Flex, + ScrollArea, + ScrollAreaScrollbar, + ScrollAreaThumb, + ScrollAreaViewport, + Text +} from "@code0-tech/pictor"; +import {Tab, TabList, TabTrigger} from "@code0-tech/pictor/dist/components/tab/Tab"; +import {RoleProjectView} from "@edition/role/views/RoleProjectView"; +import {RolePermissionView} from "@edition/role/views/RolePermissionView"; +import {RoleGeneralAdjustmentView} from "@edition/role/views/RoleGeneralAdjustmentView"; +import {RoleDeleteView} from "@edition/role/views/RoleDeleteView"; +import {IconLayoutSidebar} from "@tabler/icons-react"; + +export const RoleSettingsPage: React.FC = () => { + + //TODO: limit tabs based on user abilities for roles + + return <> + + + + + + Role settings + + + + + General settings and restrictions for your Sculptor application. These settings affect all + users + and organizations within the application. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/role/RolesPage.tsx b/src/packages/ce/src/role/pages/RolesPage.tsx similarity index 64% rename from src/packages/ce/src/dashboard/role/RolesPage.tsx rename to src/packages/ce/src/role/pages/RolesPage.tsx index 0d93b4b7..4e110b45 100644 --- a/src/packages/ce/src/dashboard/role/RolesPage.tsx +++ b/src/packages/ce/src/role/pages/RolesPage.tsx @@ -1,7 +1,7 @@ "use client" import React from "react"; -import {RolesView} from "@edition/dashboard/role/RolesView"; +import {RolesView} from "@edition/role/views/RolesView"; export const RolesPage: React.FC = () => { return diff --git a/src/packages/ce/src/role/Role.service.ts b/src/packages/ce/src/role/services/Role.service.ts similarity index 87% rename from src/packages/ce/src/role/Role.service.ts rename to src/packages/ce/src/role/services/Role.service.ts index db23bca7..581c94ba 100644 --- a/src/packages/ce/src/role/Role.service.ts +++ b/src/packages/ce/src/role/services/Role.service.ts @@ -20,18 +20,19 @@ import { Query } from "@code0-tech/sagittarius-graphql-types" import {GraphqlClient} from "@core/util/graphql-client"; -import rolesQuery from "@edition/role/queries/Roles.query.graphql"; -import roleUpdateMutation from "@edition/role/mutations/Role.update.mutation.graphql"; -import roleDeleteMutation from "@edition/role/mutations/Role.delete.mutation.graphql"; -import roleAssignAbilitiesMutation from "@edition/role/mutations/Role.assignAbilities.mutation.graphql"; -import roleAssignProjectsMutation from "@edition/role/mutations/Role.assignProjects.mutation.graphql"; +import rolesQuery from "@edition/role/services/queries/Roles.query.graphql"; +import roleUpdateMutation from "@edition/role/services/mutations/Role.update.mutation.graphql"; +import roleDeleteMutation from "@edition/role/services/mutations/Role.delete.mutation.graphql"; +import roleAssignAbilitiesMutation from "@edition/role/services/mutations/Role.assignAbilities.mutation.graphql"; +import roleAssignProjectsMutation from "@edition/role/services/mutations/Role.assignProjects.mutation.graphql"; +import {View} from "@code0-tech/pictor/dist/utils/view"; export class RoleService extends DNamespaceRoleReactiveService { private readonly client: GraphqlClient private i = 0; - constructor(client: GraphqlClient, store: ReactiveArrayStore) { + constructor(client: GraphqlClient, store: ReactiveArrayStore>) { super(store); this.client = client } @@ -61,7 +62,7 @@ export class RoleService extends DNamespaceRoleReactiveService { role.namespace?.id === namespaceId && !this.hasById(role.id) ) { - this.set(this.i++, new DNamespaceRoleView(role)) + this.set(this.i++, new View(new DNamespaceRoleView(role))) } }) }) @@ -93,7 +94,7 @@ export class RoleService extends DNamespaceRoleReactiveService { abilities: payload.abilities }) - this.set(index, newRole) + this.set(index, new View(newRole)) } return result.data?.namespacesRolesAssignAbilities ?? undefined @@ -122,7 +123,7 @@ export class RoleService extends DNamespaceRoleReactiveService { } }) - this.set(index, newRole) + this.set(index, new View(newRole)) } return result.data?.namespacesRolesAssignProjects ?? undefined @@ -146,7 +147,7 @@ export class RoleService extends DNamespaceRoleReactiveService { name: payload.name }) - this.set(index, newRole) + this.set(index, new View(newRole)) } return result.data?.namespacesRolesUpdate ?? undefined diff --git a/src/packages/ce/src/role/fragments/Role.basic.fragment.graphql b/src/packages/ce/src/role/services/fragments/Role.basic.fragment.graphql similarity index 82% rename from src/packages/ce/src/role/fragments/Role.basic.fragment.graphql rename to src/packages/ce/src/role/services/fragments/Role.basic.fragment.graphql index eb91d664..f03ce7ac 100644 --- a/src/packages/ce/src/role/fragments/Role.basic.fragment.graphql +++ b/src/packages/ce/src/role/services/fragments/Role.basic.fragment.graphql @@ -1,4 +1,4 @@ -#import "../../namespace/fragments/Namespace.id.fragment.graphql" +#import "@edition/namespace/services/fragments/Namespace.id.fragment.graphql" fragment RoleBasic on NamespaceRole { __typename id diff --git a/src/packages/ce/src/role/fragments/Role.fragment.graphql b/src/packages/ce/src/role/services/fragments/Role.fragment.graphql similarity index 77% rename from src/packages/ce/src/role/fragments/Role.fragment.graphql rename to src/packages/ce/src/role/services/fragments/Role.fragment.graphql index 150f9d3f..177da517 100644 --- a/src/packages/ce/src/role/fragments/Role.fragment.graphql +++ b/src/packages/ce/src/role/services/fragments/Role.fragment.graphql @@ -1,5 +1,5 @@ -#import "../../namespace/fragments/Namespace.id.fragment.graphql" -#import "../../project/fragments/Project.id.fragment.graphql" +#import "@edition/namespace/services/fragments/Namespace.id.fragment.graphql" +#import "@edition/project/services/fragments/Project.id.fragment.graphql" fragment Role on NamespaceRole { __typename id diff --git a/src/packages/ce/src/role/fragments/Role.id.fragment.graphql b/src/packages/ce/src/role/services/fragments/Role.id.fragment.graphql similarity index 100% rename from src/packages/ce/src/role/fragments/Role.id.fragment.graphql rename to src/packages/ce/src/role/services/fragments/Role.id.fragment.graphql diff --git a/src/packages/ce/src/role/mutations/Role.assignAbilities.mutation.graphql b/src/packages/ce/src/role/services/mutations/Role.assignAbilities.mutation.graphql similarity index 100% rename from src/packages/ce/src/role/mutations/Role.assignAbilities.mutation.graphql rename to src/packages/ce/src/role/services/mutations/Role.assignAbilities.mutation.graphql diff --git a/src/packages/ce/src/role/mutations/Role.assignProjects.mutation.graphql b/src/packages/ce/src/role/services/mutations/Role.assignProjects.mutation.graphql similarity index 100% rename from src/packages/ce/src/role/mutations/Role.assignProjects.mutation.graphql rename to src/packages/ce/src/role/services/mutations/Role.assignProjects.mutation.graphql diff --git a/src/packages/ce/src/role/mutations/Role.create.mutation.graphql b/src/packages/ce/src/role/services/mutations/Role.create.mutation.graphql similarity index 100% rename from src/packages/ce/src/role/mutations/Role.create.mutation.graphql rename to src/packages/ce/src/role/services/mutations/Role.create.mutation.graphql diff --git a/src/packages/ce/src/role/mutations/Role.delete.mutation.graphql b/src/packages/ce/src/role/services/mutations/Role.delete.mutation.graphql similarity index 100% rename from src/packages/ce/src/role/mutations/Role.delete.mutation.graphql rename to src/packages/ce/src/role/services/mutations/Role.delete.mutation.graphql diff --git a/src/packages/ce/src/role/mutations/Role.update.mutation.graphql b/src/packages/ce/src/role/services/mutations/Role.update.mutation.graphql similarity index 100% rename from src/packages/ce/src/role/mutations/Role.update.mutation.graphql rename to src/packages/ce/src/role/services/mutations/Role.update.mutation.graphql diff --git a/src/packages/ce/src/role/queries/Roles.query.graphql b/src/packages/ce/src/role/services/queries/Roles.query.graphql similarity index 100% rename from src/packages/ce/src/role/queries/Roles.query.graphql rename to src/packages/ce/src/role/services/queries/Roles.query.graphql diff --git a/src/packages/ce/src/dashboard/role/RoleDeleteView.tsx b/src/packages/ce/src/role/views/RoleDeleteView.tsx similarity index 83% rename from src/packages/ce/src/dashboard/role/RoleDeleteView.tsx rename to src/packages/ce/src/role/views/RoleDeleteView.tsx index 987c8d35..3b65d92b 100644 --- a/src/packages/ce/src/dashboard/role/RoleDeleteView.tsx +++ b/src/packages/ce/src/role/views/RoleDeleteView.tsx @@ -3,7 +3,7 @@ import React from "react"; import {useParams, useRouter} from "next/navigation"; import {Button, Card, Flex, Spacing, Text, toast, useService} from "@code0-tech/pictor"; -import {RoleService} from "@edition/role/Role.service"; +import {RoleService} from "@edition/role/services/Role.service"; import type {NamespaceRole} from "@code0-tech/sagittarius-graphql-types"; import {TabContent} from "@code0-tech/pictor/dist/components/tab/Tab"; @@ -36,20 +36,19 @@ export const RoleDeleteView: React.FC = () => { }, []) return - + Delete role - Delete role - + This will delete the role and cannot be undone. - diff --git a/src/packages/ce/src/dashboard/role/RoleGeneralAdjustmentView.tsx b/src/packages/ce/src/role/views/RoleGeneralAdjustmentView.tsx similarity index 91% rename from src/packages/ce/src/dashboard/role/RoleGeneralAdjustmentView.tsx rename to src/packages/ce/src/role/views/RoleGeneralAdjustmentView.tsx index 409fe687..4efafb52 100644 --- a/src/packages/ce/src/dashboard/role/RoleGeneralAdjustmentView.tsx +++ b/src/packages/ce/src/role/views/RoleGeneralAdjustmentView.tsx @@ -4,7 +4,7 @@ import React from "react"; import {Button, Card, Flex, Spacing, Text, TextInput, toast, useForm, useService, useStore} from "@code0-tech/pictor"; import CardSection from "@code0-tech/pictor/dist/components/card/CardSection"; import {TabContent} from "@code0-tech/pictor/dist/components/tab/Tab"; -import {RoleService} from "@edition/role/Role.service"; +import {RoleService} from "@edition/role/services/Role.service"; import type {Namespace, NamespaceRole} from "@code0-tech/sagittarius-graphql-types"; import {useParams} from "next/navigation"; @@ -58,15 +58,15 @@ export const RoleGeneralAdjustmentView: React.FC = () => { return - - General adjustments + + General - + Name diff --git a/src/packages/ce/src/dashboard/role/RolePermissionView.tsx b/src/packages/ce/src/role/views/RolePermissionView.tsx similarity index 95% rename from src/packages/ce/src/dashboard/role/RolePermissionView.tsx rename to src/packages/ce/src/role/views/RolePermissionView.tsx index a0e21c0a..2017bfcc 100644 --- a/src/packages/ce/src/dashboard/role/RolePermissionView.tsx +++ b/src/packages/ce/src/role/views/RolePermissionView.tsx @@ -21,7 +21,7 @@ import {DNamespaceRolePermissions} from "@code0-tech/pictor/dist/components/d-ro import CardSection from "@code0-tech/pictor/dist/components/card/CardSection"; import {TabContent} from "@code0-tech/pictor/dist/components/tab/Tab"; import {useParams} from "next/navigation"; -import {RoleService} from "@edition/role/Role.service"; +import {RoleService} from "@edition/role/services/Role.service"; type Permission = { label: string @@ -226,9 +226,14 @@ export const RolePermissionView: React.FC = () => { }) return - - Select from role templates - + + + Select from role templates + + + {React.useMemo(() => { return @@ -268,19 +273,13 @@ export const RolePermissionView: React.FC = () => { }, [initialValues, role])} - -
- Current stored - permissions - - -
- -
+ + Current stored permissions + + + - + {permissions.map(permissionGroup => { return diff --git a/src/packages/ce/src/dashboard/role/RoleProjectView.tsx b/src/packages/ce/src/role/views/RoleProjectView.tsx similarity index 95% rename from src/packages/ce/src/dashboard/role/RoleProjectView.tsx rename to src/packages/ce/src/role/views/RoleProjectView.tsx index df1c4db6..36e40da6 100644 --- a/src/packages/ce/src/dashboard/role/RoleProjectView.tsx +++ b/src/packages/ce/src/role/views/RoleProjectView.tsx @@ -19,7 +19,7 @@ import {IconTrash} from "@tabler/icons-react"; import {TabContent} from "@code0-tech/pictor/dist/components/tab/Tab"; import React from "react"; import {useParams} from "next/navigation"; -import {RoleService} from "@edition/role/Role.service"; +import {RoleService} from "@edition/role/services/Role.service"; import type {Namespace, NamespaceRole, Scalars} from "@code0-tech/sagittarius-graphql-types"; export const RoleProjectView: React.FC = () => { @@ -77,10 +77,11 @@ export const RoleProjectView: React.FC = () => { return - Projects that members can - access + + Projects that members can access + - + { + + const params = useParams() + const router = useRouter() + const namespaceId = params.namespaceId as any as number + + const [filter, setFilter] = React.useState({}) + const [sort, setSort] = React.useState({}) + + const rolesList = React.useMemo(() => { + return { + const roleIndex = role?.id?.match(/NamespaceRole\/(\d+)$/)?.[1] + router.push(`/namespace/${namespaceId}/roles/${roleIndex}/settings`) + }} namespaceId={`gid://sagittarius/Namespace/${namespaceId}`}/> + }, [namespaceId, filter, sort]) + + return <> + + + + + Roles + + + Manage roles that you belong to. You can create new roles and switch between them. + + + + + + + + + + + + + { + if (sort["name"] === undefined) + setSort(prev => ({...prev, name: "asc"})) + else if (sort["name"] === "asc") + setSort(prev => ({...prev, name: "desc"})) + else + setSort(prev => ({...prev, name: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["name"] === undefined ? : sort["name"] === "asc" ? + : } + Name + + { + if (sort["createdAt"] === undefined) + setSort(prev => ({...prev, createdAt: "asc"})) + else if (sort["createdAt"] === "asc") + setSort(prev => ({...prev, createdAt: "desc"})) + else + setSort(prev => ({...prev, createdAt: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["createdAt"] === undefined ? + : sort["createdAt"] === "asc" ? + : } + Created At + + { + if (sort["updatedAt"] === undefined) + setSort(prev => ({...prev, updatedAt: "asc"})) + else if (sort["updatedAt"] === "asc") + setSort(prev => ({...prev, updatedAt: "desc"})) + else + setSort(prev => ({...prev, updatedAt: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["updatedAt"] === undefined ? + : sort["updatedAt"] === "asc" ? + : } + Updated At + + + + + + + +
+ setFilter(filter)}/> +
+ + {rolesList} + + + +} \ No newline at end of file diff --git a/src/packages/ce/src/runtime/components/RuntimeDataTableComponent.tsx b/src/packages/ce/src/runtime/components/RuntimeDataTableComponent.tsx new file mode 100644 index 00000000..76321d8d --- /dev/null +++ b/src/packages/ce/src/runtime/components/RuntimeDataTableComponent.tsx @@ -0,0 +1,47 @@ +import React from "react"; +import {DataTable, DataTableColumn, Text, useService, useStore} from "@code0-tech/pictor"; +import {DataTableFilterProps, DataTableSortProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import {Namespace, NamespaceProject, NamespaceRole, Runtime} from "@code0-tech/sagittarius-graphql-types"; +import {ProjectService} from "@edition/project/services/Project.service"; +import {ProjectDataTableRowComponent} from "@edition/project/components/ProjectDataTableRowComponent"; +import {RoleService} from "@edition/role/services/Role.service"; +import {RoleDataTableRowComponent} from "@edition/role/components/RoleDataTableRowComponent"; +import {RuntimeService} from "@edition/runtime/services/Runtime.service"; +import {RuntimeDataTableRowComponent} from "@edition/runtime/components/RuntimeDataTableRowComponent"; + +export interface ProjectDataTableComponentProps { + namespaceId?: Namespace["id"] + sort?: DataTableSortProps + filter?: DataTableFilterProps + preFilter?: (project: Runtime, index: number) => boolean + onSelect?: (item: Runtime | undefined) => void + minimized?: boolean +} + +export const RuntimeDataTableComponent: React.FC = (props) => { + + const {namespaceId, sort, filter, preFilter = () => true, onSelect, minimized} = props + + const runtimeService = useService(RuntimeService) + const runtimeStore = useStore(RuntimeService) + + const runtimes = React.useMemo( + () => runtimeService.values({namespaceId: namespaceId}), + [runtimeStore, namespaceId] + ) + + return + + No runtime found. Create one to get started. + + } + onSelect={(item) => item && onSelect?.(item)} + data={runtimes.map(r => r.json()).filter(preFilter)}> + {(runtime, index) => { + return + }} + + +} \ No newline at end of file diff --git a/src/packages/ce/src/runtime/components/RuntimeDataTableFilterInputComponent.tsx b/src/packages/ce/src/runtime/components/RuntimeDataTableFilterInputComponent.tsx new file mode 100644 index 00000000..6747d11b --- /dev/null +++ b/src/packages/ce/src/runtime/components/RuntimeDataTableFilterInputComponent.tsx @@ -0,0 +1,90 @@ +import React from "react"; +import { + DataTableFilterInput, + DataTableFilterSuggestionMenu, DRuntimeView, + MenuCheckboxItem, + useService, + useStore +} from "@code0-tech/pictor"; +import {IconCheck} from "@tabler/icons-react"; +import {Namespace, Runtime} from "@code0-tech/sagittarius-graphql-types"; +import {DataTableFilterProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import {RoleService} from "@edition/role/services/Role.service"; +import {RuntimeService} from "@edition/runtime/services/Runtime.service"; + +export interface RoleDataTableFilterInputComponentProps { + namespaceId?: Namespace['id'] + onChange: (filter: DataTableFilterProps) => void + preFilter?: (project: DRuntimeView, index: number) => boolean +} + +export const RuntimeDataTableFilterInputComponent: React.FC = (props) => { + + const {namespaceId, onChange, preFilter = () => true} = props + + const runtimeService = useService(RuntimeService) + const runtimeStore = useStore(RuntimeService) + + const runtimes = React.useMemo( + () => runtimeService.values({namespaceId}).filter(preFilter), + [runtimeStore, namespaceId] + ) + + return { + + const split = currentValue.split(",").map(s => s.trim()).filter(Boolean) + + return + {runtimes.map(runtime => { + + const isChecked = split.includes(runtime?.name!) + + return { + e.preventDefault(); + e.stopPropagation(); + const updated = isChecked + ? split.filter(name => name !== runtime?.name) + : [...split, runtime?.name]; + applySuggestion(updated.join(","), true); + }}> + {isChecked ? : } + {runtime?.name} + + })} + + } + }, { + token: "Status", + key: "status", + operators: ["isOneOf"], + suggestion: (context, operator, currentValue, applySuggestion) => { + + const split = currentValue.split(",").map(s => s.trim()).filter(Boolean) + + return + {["CONNECTED", "DISCONNECTED"].map(status => { + + const isChecked = split.includes(status) + + return { + e.preventDefault(); + e.stopPropagation(); + const updated = isChecked + ? split.filter(name => name !== status) + : [...split, status]; + applySuggestion(updated.join(","), true); + }}> + {isChecked ? : } + {status} + + })} + + } + } + ]}/> +} \ No newline at end of file diff --git a/src/packages/ce/src/runtime/components/RuntimeDataTableRowComponent.tsx b/src/packages/ce/src/runtime/components/RuntimeDataTableRowComponent.tsx new file mode 100644 index 00000000..a7aed099 --- /dev/null +++ b/src/packages/ce/src/runtime/components/RuntimeDataTableRowComponent.tsx @@ -0,0 +1,50 @@ +import React from "react"; +import {Runtime} from "@code0-tech/sagittarius-graphql-types"; +import {Badge, DataTableColumn, Flex, Text, useService, useStore} from "@code0-tech/pictor"; +import {RuntimeService} from "@edition/runtime/services/Runtime.service"; +import {formatDistanceToNow} from "date-fns"; + +export interface ProjectDataTableRowComponentProps { + runtimeId: Runtime['id'] + minimized?: boolean +} + +export const RuntimeDataTableRowComponent: React.FC = (props) => { + + const {runtimeId, minimized} = props + + const runtimeService = useService(RuntimeService) + const runtimeStore = useStore(RuntimeService) + + const runtime = React.useMemo( + () => runtimeService.getById(runtimeId), + [runtimeStore, runtimeId] + ) + + return <> + + + + + {runtime?.name} + + {!minimized && ( + + {runtime?.description} + + )} + + {!minimized && ( + + Updated {formatDistanceToNow(runtime?.updatedAt!)} ago + + )} + + + + + {runtime?.status} + + + +} \ No newline at end of file diff --git a/src/packages/ce/src/runtime/components/RuntimeProjectDataTableComponent.tsx b/src/packages/ce/src/runtime/components/RuntimeProjectDataTableComponent.tsx new file mode 100644 index 00000000..44afd579 --- /dev/null +++ b/src/packages/ce/src/runtime/components/RuntimeProjectDataTableComponent.tsx @@ -0,0 +1,55 @@ +import React from "react"; +import {DataTable, DataTableColumn, Text, useService, useStore} from "@code0-tech/pictor"; +import {DataTableFilterProps, DataTableSortProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import {Namespace, NamespaceProject, NamespaceRole, Runtime} from "@code0-tech/sagittarius-graphql-types"; +import {ProjectService} from "@edition/project/services/Project.service"; +import {ProjectDataTableRowComponent} from "@edition/project/components/ProjectDataTableRowComponent"; +import {RoleService} from "@edition/role/services/Role.service"; +import {RoleDataTableRowComponent} from "@edition/role/components/RoleDataTableRowComponent"; +import {RuntimeService} from "@edition/runtime/services/Runtime.service"; +import {RuntimeDataTableRowComponent} from "@edition/runtime/components/RuntimeDataTableRowComponent"; +import {RuntimeProjectDataTableRowComponent} from "@edition/runtime/components/RuntimeProjectDataTableRowComponent"; + +export interface RuntimeProjectDataTableComponentProps { + projectId?: NamespaceProject["id"] + sort?: DataTableSortProps + filter?: DataTableFilterProps + preFilter?: (project: Runtime, index: number) => boolean + onSelect?: (item: Runtime | undefined) => void + minimized?: boolean +} + +export const RuntimeProjectDataTableComponent: React.FC = (props) => { + + const {projectId, sort, filter, preFilter = () => true, onSelect, minimized} = props + + const projectService = useService(ProjectService) + const projectStore = useStore(ProjectService) + const runtimeService = useService(RuntimeService) + const runtimeStore = useStore(RuntimeService) + + const project = React.useMemo( + () => projectService.getById(projectId), + [projectStore, projectId] + ) + + const runtimes = React.useMemo( + () => runtimeService.values().filter(runtime => project?.runtimes?.nodes?.some(r => r?.id === runtime.id)), + [runtimeStore, project] + ) + + return + + No runtime found. Create one to get started. + + } + onSelect={(item) => item && onSelect?.(item)} + data={runtimes.map(r => r.json()).filter(preFilter)}> + {(runtime, index) => { + return + }} + + +} \ No newline at end of file diff --git a/src/packages/ce/src/runtime/components/RuntimeProjectDataTableRowComponent.tsx b/src/packages/ce/src/runtime/components/RuntimeProjectDataTableRowComponent.tsx new file mode 100644 index 00000000..03960923 --- /dev/null +++ b/src/packages/ce/src/runtime/components/RuntimeProjectDataTableRowComponent.tsx @@ -0,0 +1,124 @@ +import React, {startTransition} from "react"; +import {NamespaceProject, Runtime} from "@code0-tech/sagittarius-graphql-types"; +import { + Avatar, + Badge, + Button, + DataTableColumn, + Flex, + hashToColor, + Menu, + MenuContent, + MenuItem, + MenuPortal, + MenuTrigger, + Text, + useService, + useStore +} from "@code0-tech/pictor"; +import {RuntimeService} from "@edition/runtime/services/Runtime.service"; +import {formatDistanceToNow} from "date-fns"; +import {IconDotsVertical, IconServerSpark, IconX} from "@tabler/icons-react"; +import {ProjectService} from "@edition/project/services/Project.service"; + +export interface RuntimeProjectDataTableRowComponentProps { + projectId: NamespaceProject['id'] + runtimeId: Runtime['id'] +} + +export const RuntimeProjectDataTableRowComponent: React.FC = (props) => { + + const {projectId, runtimeId} = props + + const projectService = useService(ProjectService) + const projectStore = useStore(ProjectService) + const runtimeService = useService(RuntimeService) + const runtimeStore = useStore(RuntimeService) + + const runtime = React.useMemo( + () => runtimeService.getById(runtimeId), + [runtimeStore, runtimeId] + ) + + const project = React.useMemo( + () => projectService.getById(projectId), + [projectStore, projectId] + ) + + const makePrimary = React.useCallback(() => { + startTransition(() => { + projectService.projectUpdate({ + primaryRuntimeId: runtimeId, + namespaceProjectId: projectId!, + }) + }) + }, [projectId, runtimeId]) + + const removeRuntime = React.useCallback(() => { + const runtimeIds = project?.runtimes?.nodes?.map(r => r?.id!) ?? [] + + startTransition(() => { + projectService.projectAssignRuntimes({ + runtimeIds: runtimeIds.filter(id => id !== runtimeId), + namespaceProjectId: projectId! + }) + }) + }, [projectId, project, runtimeId]) + + return <> + + + + + + + + {runtime?.name} + + {project?.primaryRuntime?.id === runtime?.id ? + Primary : null} + + + {runtime?.description} + + + + + Updated {formatDistanceToNow(runtime?.updatedAt!)} ago + + + + + + {runtime?.status} + + + + { + project?.primaryRuntime?.id !== runtime?.id && ( + + + + + + + + + Remove runtime + + + + Make primary + + + + + ) + } + + +} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/runtime/RuntimeCreatePage.tsx b/src/packages/ce/src/runtime/pages/RuntimeCreatePage.tsx similarity index 51% rename from src/packages/ce/src/dashboard/runtime/RuntimeCreatePage.tsx rename to src/packages/ce/src/runtime/pages/RuntimeCreatePage.tsx index bed0d10c..f56077b1 100644 --- a/src/packages/ce/src/dashboard/runtime/RuntimeCreatePage.tsx +++ b/src/packages/ce/src/runtime/pages/RuntimeCreatePage.tsx @@ -16,9 +16,9 @@ import { } from "@code0-tech/pictor"; import Link from "next/link"; import {notFound, useParams, useRouter} from "next/navigation"; -import {RuntimeService} from "@edition/runtime/Runtime.service"; -import {UserService} from "@edition/user/User.service"; -import {NamespaceService} from "@edition/namespace/Namespace.service"; +import {RuntimeService} from "@edition/runtime/services/Runtime.service"; +import {UserService} from "@edition/user/services/User.service"; +import {NamespaceService} from "@edition/namespace/services/Namespace.service"; export const RuntimeCreatePage: React.FC = () => { @@ -84,52 +84,54 @@ export const RuntimeCreatePage: React.FC = () => { } }) - return - - - {!token ? "Create new runtime" : "Runtime created successfully"} - - - - Runtimes are shared runtimes that can be used across multiple organizations. - - - {!token ? ( - <> - - - - - - ) : ( - <> - - - - )} - - - - + return
+ + + + {!token ? "Create new runtime" : "Runtime created successfully"} + + + + Runtimes are shared runtimes that can be used across multiple organizations. + + {!token ? ( - - ) : null} - - - + <> + + + + + + ) : ( + <> + + + + )} + + + + + {!token ? ( + + ) : null} + + + +
} \ No newline at end of file diff --git a/src/packages/ce/src/dashboard/runtime/RuntimeSettingsPage.tsx b/src/packages/ce/src/runtime/pages/RuntimeSettingsPage.tsx similarity index 71% rename from src/packages/ce/src/dashboard/runtime/RuntimeSettingsPage.tsx rename to src/packages/ce/src/runtime/pages/RuntimeSettingsPage.tsx index bff41d76..447e047f 100644 --- a/src/packages/ce/src/dashboard/runtime/RuntimeSettingsPage.tsx +++ b/src/packages/ce/src/runtime/pages/RuntimeSettingsPage.tsx @@ -4,7 +4,9 @@ import React from "react"; import { Button, Card, - DLayout, + DResizableHandle, + DResizablePanel, + DResizablePanelGroup, Flex, Spacing, Text, @@ -14,10 +16,11 @@ import { useService, useStore } from "@code0-tech/pictor"; -import {RuntimeService} from "@edition/runtime/Runtime.service"; +import {RuntimeService} from "@edition/runtime/services/Runtime.service"; import {notFound, useParams, useRouter} from "next/navigation"; import {Tab, TabContent, TabList, TabTrigger} from "@code0-tech/pictor/dist/components/tab/Tab"; import CardSection from "@code0-tech/pictor/dist/components/card/CardSection"; +import {IconLayoutSidebar} from "@tabler/icons-react"; export const RuntimeSettingsPage: React.FC = () => { @@ -112,49 +115,54 @@ export const RuntimeSettingsPage: React.FC = () => { }, [runtime]) - return <> - - - - {runtime?.name} - - - {runtime?.description} - - - - - - - - - - - - - - - - }> +
+ + General settings and restrictions for your Sculptor application. These settings affect all users + and organizations within the application. + + + + + + + + + + + + +
+ + + <> - General adjustments + General -
- - + Name @@ -174,9 +182,7 @@ export const RuntimeSettingsPage: React.FC = () => { How to connect -
- - + @@ -187,7 +193,7 @@ export const RuntimeSettingsPage: React.FC = () => { {token ? ( ) : ( - )} @@ -198,27 +204,24 @@ export const RuntimeSettingsPage: React.FC = () => { - Delete runtime forever + Delete -
- - Delete runtime - + This will delete the runtime and cannot be undone. - - - - + + + } \ No newline at end of file diff --git a/src/packages/ce/src/runtime/pages/RuntimesPage.tsx b/src/packages/ce/src/runtime/pages/RuntimesPage.tsx new file mode 100644 index 00000000..0ca50b6a --- /dev/null +++ b/src/packages/ce/src/runtime/pages/RuntimesPage.tsx @@ -0,0 +1,140 @@ +"use client" + +import React from "react"; +import { + Button, + DRuntimeList, + Flex, + Menu, MenuCheckboxItem, MenuContent, MenuPortal, MenuTrigger, + Spacing, + Text, + useService, + useStore, + useUserSession +} from "@code0-tech/pictor"; +import Link from "next/link"; +import {notFound, useParams, useRouter} from "next/navigation"; +import {UserService} from "@edition/user/services/User.service"; +import {RuntimeDataTableComponent} from "@edition/runtime/components/RuntimeDataTableComponent"; +import {DataTableFilterProps, DataTableSortProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import { + OrganizationDataTableFilterInputComponent +} from "@edition/organization/components/OrganizationDataTableFilterInputComponent"; +import {RuntimeDataTableFilterInputComponent} from "@edition/runtime/components/RuntimeDataTableFilterInputComponent"; +import {IconMinus, IconSortAscending, IconSortDescending} from "@tabler/icons-react"; +import {ButtonGroup} from "@code0-tech/pictor/dist/components/button-group/ButtonGroup"; + +export const RuntimesPage: React.FC = () => { + + const params = useParams() + const currentSession = useUserSession() + const userStore = useStore(UserService) + const userService = useService(UserService) + const currentUser = React.useMemo(() => userService.getById(currentSession?.user?.id), [userStore, currentSession]) + + const [filter, setFilter] = React.useState({}) + const [sort, setSort] = React.useState({}) + + const namespaceIndex = params.namespaceId as any as number + + if (!namespaceIndex && currentUser && !currentUser.admin) { + notFound() + } + + const router = useRouter() + return
+ + + + Runtimes + + + Manage runtimes that you have access to. Runtimes are the environments where your applications run. + + + + + + + + + + + + + { + if (sort["name"] === undefined) + setSort(prev => ({...prev, name: "asc"})) + else if (sort["name"] === "asc") + setSort(prev => ({...prev, name: "desc"})) + else + setSort(prev => ({...prev, name: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["name"] === undefined ? : sort["name"] === "asc" ? + : } + Name + + { + if (sort["createdAt"] === undefined) + setSort(prev => ({...prev, createdAt: "asc"})) + else if (sort["createdAt"] === "asc") + setSort(prev => ({...prev, createdAt: "desc"})) + else + setSort(prev => ({...prev, createdAt: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["createdAt"] === undefined ? + : sort["createdAt"] === "asc" ? + : } + Created At + + { + if (sort["updatedAt"] === undefined) + setSort(prev => ({...prev, updatedAt: "asc"})) + else if (sort["updatedAt"] === "asc") + setSort(prev => ({...prev, updatedAt: "desc"})) + else + setSort(prev => ({...prev, updatedAt: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["updatedAt"] === undefined ? + : sort["updatedAt"] === "asc" ? + : } + Updated At + + + + + + + +
+ namespaceIndex ? true : !runtime?.namespace?.id} namespaceId={namespaceIndex ? `gid://sagittarius/Namespace/${namespaceIndex}` : undefined} onChange={filter => setFilter(filter)}/> +
+ + namespaceIndex ? true : !runtime?.namespace?.id} onSelect={(runtime) => { + const number = runtime?.id?.match(/Runtime\/(\d+)$/)?.[1] + router.push(namespaceIndex ? `/namespace/${namespaceIndex}/runtimes/${number}/settings` : `/runtimes/${number}/settings`) + }}/> +
+} \ No newline at end of file diff --git a/src/packages/ce/src/runtime/Runtime.service.ts b/src/packages/ce/src/runtime/services/Runtime.service.ts similarity index 92% rename from src/packages/ce/src/runtime/Runtime.service.ts rename to src/packages/ce/src/runtime/services/Runtime.service.ts index 959e17f4..ac090117 100644 --- a/src/packages/ce/src/runtime/Runtime.service.ts +++ b/src/packages/ce/src/runtime/services/Runtime.service.ts @@ -19,13 +19,14 @@ import createRuntimeMutation from "./mutations/Runtime.create.mutation.graphql" import updateRuntimeMutation from "./mutations/Runtime.update.mutation.graphql" import deleteRuntimeMutation from "./mutations/Runtime.delete.mutation.graphql" import rotateTokenRuntimeMutation from "./mutations/Runtime.rotateToken.mutation.graphql" +import {View} from "@code0-tech/pictor/dist/utils/view"; export class RuntimeService extends DRuntimeReactiveService { private readonly client: GraphqlClient private i = 0 - constructor(client: GraphqlClient, store: ReactiveArrayStore) { + constructor(client: GraphqlClient, store: ReactiveArrayStore>) { super(store); this.client = client } @@ -50,7 +51,7 @@ export class RuntimeService extends DRuntimeReactiveService { const nodes = res.data?.globalRuntimes?.nodes ?? [] nodes.forEach(runtime => { if (runtime && !this.hasById(runtime.id)) { - this.set(this.i++, new DRuntimeView(runtime)) + this.set(this.i++, new View(new DRuntimeView(runtime))) } }) }) @@ -78,7 +79,7 @@ export class RuntimeService extends DRuntimeReactiveService { runtime.namespace?.id === namespaceId && !this.hasById(runtime.id) ) { - this.set(this.i++, new DRuntimeView(runtime)) + this.set(this.i++, new View(new DRuntimeView(runtime))) } }) }) @@ -98,7 +99,7 @@ export class RuntimeService extends DRuntimeReactiveService { if (result.data && result.data.runtimesCreate && result.data.runtimesCreate.runtime) { const runtime = result.data.runtimesCreate.runtime if (!this.hasById(runtime.id)) { - this.add(new DRuntimeView(runtime)) + this.add(new View(new DRuntimeView(runtime))) } } @@ -116,7 +117,7 @@ export class RuntimeService extends DRuntimeReactiveService { if (result.data && result.data.runtimesUpdate && result.data.runtimesUpdate.runtime) { const runtime = result.data.runtimesUpdate.runtime const index = this.values().findIndex(r => r.id === runtime.id) - this.set(index, new DRuntimeView(runtime)) + this.set(index, new View(new DRuntimeView(runtime))) } @@ -152,7 +153,7 @@ export class RuntimeService extends DRuntimeReactiveService { if (result.data && result.data.runtimesRotateToken && result.data.runtimesRotateToken.runtime) { const runtime = result.data.runtimesRotateToken.runtime const index = this.values().findIndex(r => r.id === runtime.id) - this.set(index, new DRuntimeView(runtime)) + this.set(index, new View(new DRuntimeView(runtime))) } diff --git a/src/packages/ce/src/runtime/fragments/Runtime.fragment.graphql b/src/packages/ce/src/runtime/services/fragments/Runtime.fragment.graphql similarity index 100% rename from src/packages/ce/src/runtime/fragments/Runtime.fragment.graphql rename to src/packages/ce/src/runtime/services/fragments/Runtime.fragment.graphql diff --git a/src/packages/ce/src/runtime/fragments/Runtime.id.fragment.graphql b/src/packages/ce/src/runtime/services/fragments/Runtime.id.fragment.graphql similarity index 100% rename from src/packages/ce/src/runtime/fragments/Runtime.id.fragment.graphql rename to src/packages/ce/src/runtime/services/fragments/Runtime.id.fragment.graphql diff --git a/src/packages/ce/src/runtime/mutations/Runtime.create.mutation.graphql b/src/packages/ce/src/runtime/services/mutations/Runtime.create.mutation.graphql similarity index 100% rename from src/packages/ce/src/runtime/mutations/Runtime.create.mutation.graphql rename to src/packages/ce/src/runtime/services/mutations/Runtime.create.mutation.graphql diff --git a/src/packages/ce/src/runtime/mutations/Runtime.delete.mutation.graphql b/src/packages/ce/src/runtime/services/mutations/Runtime.delete.mutation.graphql similarity index 100% rename from src/packages/ce/src/runtime/mutations/Runtime.delete.mutation.graphql rename to src/packages/ce/src/runtime/services/mutations/Runtime.delete.mutation.graphql diff --git a/src/packages/ce/src/runtime/mutations/Runtime.rotateToken.mutation.graphql b/src/packages/ce/src/runtime/services/mutations/Runtime.rotateToken.mutation.graphql similarity index 100% rename from src/packages/ce/src/runtime/mutations/Runtime.rotateToken.mutation.graphql rename to src/packages/ce/src/runtime/services/mutations/Runtime.rotateToken.mutation.graphql diff --git a/src/packages/ce/src/runtime/mutations/Runtime.update.mutation.graphql b/src/packages/ce/src/runtime/services/mutations/Runtime.update.mutation.graphql similarity index 100% rename from src/packages/ce/src/runtime/mutations/Runtime.update.mutation.graphql rename to src/packages/ce/src/runtime/services/mutations/Runtime.update.mutation.graphql diff --git a/src/packages/ce/src/runtime/queries/Runtime.global.query.graphql b/src/packages/ce/src/runtime/services/queries/Runtime.global.query.graphql similarity index 100% rename from src/packages/ce/src/runtime/queries/Runtime.global.query.graphql rename to src/packages/ce/src/runtime/services/queries/Runtime.global.query.graphql diff --git a/src/packages/ce/src/runtime/queries/Runtime.namespace.query.graphql b/src/packages/ce/src/runtime/services/queries/Runtime.namespace.query.graphql similarity index 100% rename from src/packages/ce/src/runtime/queries/Runtime.namespace.query.graphql rename to src/packages/ce/src/runtime/services/queries/Runtime.namespace.query.graphql diff --git a/src/packages/ce/src/dashboard/usage/UsageView.tsx b/src/packages/ce/src/runtime/views/UsageView.tsx similarity index 100% rename from src/packages/ce/src/dashboard/usage/UsageView.tsx rename to src/packages/ce/src/runtime/views/UsageView.tsx diff --git a/src/packages/ce/src/user/components/UserDataTableComponent.tsx b/src/packages/ce/src/user/components/UserDataTableComponent.tsx new file mode 100644 index 00000000..eae9fb21 --- /dev/null +++ b/src/packages/ce/src/user/components/UserDataTableComponent.tsx @@ -0,0 +1,41 @@ +import React from "react"; +import {DataTable, DataTableColumn, Text, useService, useStore} from "@code0-tech/pictor"; +import {DataTableFilterProps, DataTableSortProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import {User} from "@code0-tech/sagittarius-graphql-types"; +import {UserDataTableRowComponent} from "@edition/user/components/UserDataTableRowComponent"; +import {UserService} from "@edition/user/services/User.service"; + +export interface UserDataTableComponentProps { + sort?: DataTableSortProps + filter?: DataTableFilterProps + preFilter?: (project: User, index: number) => boolean + onSelect?: (item: User | undefined) => void +} + +export const UserDataTableComponent: React.FC = (props) => { + + const {sort, filter, preFilter = () => true, onSelect} = props + + const userService = useService(UserService) + const userStore = useStore(UserService) + + const users = React.useMemo( + () => userService.values(), + [userStore] + ) + + return + + No user found. Create one to get started. + + } + onSelect={(item) => item && onSelect?.(item)} + data={users.map(u => u.json()).filter(preFilter)}> + {(runtime, index) => { + return + }} + + +} \ No newline at end of file diff --git a/src/packages/ce/src/user/components/UserDataTableFilterInputComponent.tsx b/src/packages/ce/src/user/components/UserDataTableFilterInputComponent.tsx new file mode 100644 index 00000000..1b2cf287 --- /dev/null +++ b/src/packages/ce/src/user/components/UserDataTableFilterInputComponent.tsx @@ -0,0 +1,113 @@ +import React from "react"; +import { + DataTableFilterInput, + DataTableFilterSuggestionMenu, + MenuCheckboxItem, + useService, + useStore +} from "@code0-tech/pictor"; +import {IconCheck} from "@tabler/icons-react"; +import {DataTableFilterProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import {UserService} from "@edition/user/services/User.service"; + +export interface UserDataTableFilterInputComponentProps { + onChange: (filter: DataTableFilterProps) => void +} + +export const UserDataTableFilterInputComponent: React.FC = (props) => { + + const {onChange} = props + + const userService = useService(UserService) + const userStore = useStore(UserService) + + const users = React.useMemo( + () => userService.values(), + [userStore] + ) + + return { + + const split = currentValue.split(",").map(s => s.trim()).filter(Boolean) + + return + {users.map(user => { + + const isChecked = split.includes(user?.username!) + + return { + e.preventDefault(); + e.stopPropagation(); + const updated = isChecked + ? split.filter(name => name !== user?.username) + : [...split, user?.username]; + applySuggestion(updated.join(","), true); + }}> + {isChecked ? : } + @{user?.username} + + })} + + } + }, { + token: "Email", + key: "email", + operators: ["isOneOf"], + suggestion: (context, operator, currentValue, applySuggestion) => { + + const split = currentValue.split(",").map(s => s.trim()).filter(Boolean) + + return + {users.map(user => { + + const isChecked = split.includes(user?.email!) + + return { + e.preventDefault(); + e.stopPropagation(); + const updated = isChecked + ? split.filter(name => name !== user?.email) + : [...split, user?.email]; + applySuggestion(updated.join(","), true); + }}> + {isChecked ? : } + {user?.email} + + })} + + } + }, { + token: "Owner", + key: "admin", + operators: ["isOneOf"], + suggestion: (context, operator, currentValue, applySuggestion) => { + + const split = currentValue.split(",").map(s => s.trim()).filter(Boolean) + + return + {["true", "false"].map(admin => { + + const isChecked = split.includes(admin) + + return { + e.preventDefault(); + e.stopPropagation(); + const updated = isChecked + ? split.filter(name => name !== admin) + : [...split, admin]; + applySuggestion(updated.join(","), true); + }}> + {isChecked ? : } + {admin} + + })} + + } + } + ]}/> +} \ No newline at end of file diff --git a/src/packages/ce/src/user/components/UserDataTableRowComponent.tsx b/src/packages/ce/src/user/components/UserDataTableRowComponent.tsx new file mode 100644 index 00000000..f70de6c3 --- /dev/null +++ b/src/packages/ce/src/user/components/UserDataTableRowComponent.tsx @@ -0,0 +1,48 @@ +import React from "react"; +import {User} from "@code0-tech/sagittarius-graphql-types"; +import {Avatar, Badge, DataTableColumn, Flex, Text, useService, useStore} from "@code0-tech/pictor"; +import {formatDistanceToNow} from "date-fns"; +import {UserService} from "@edition/user/services/User.service"; + +export interface UserDataTableRowComponentProps { + userId: User['id'] +} + +export const UserDataTableRowComponent: React.FC = (props) => { + + const {userId} = props + + const userService = useService(UserService) + const userStore = useStore(UserService) + + const user = React.useMemo( + () => userService.getById(userId), + [userStore, userId] + ) + + return <> + + + + + + + + @{user?.username} + + {user?.admin ? Owner : null} + + + {user?.email ?? ""} + + + + + Account created {formatDistanceToNow(user?.createdAt!)} ago + + + + +} \ No newline at end of file diff --git a/src/packages/ce/src/auth/UserEmailVerificationPage.tsx b/src/packages/ce/src/user/pages/UserEmailVerificationPage.tsx similarity index 97% rename from src/packages/ce/src/auth/UserEmailVerificationPage.tsx rename to src/packages/ce/src/user/pages/UserEmailVerificationPage.tsx index 4c1199a6..bdc02e46 100644 --- a/src/packages/ce/src/auth/UserEmailVerificationPage.tsx +++ b/src/packages/ce/src/user/pages/UserEmailVerificationPage.tsx @@ -2,7 +2,7 @@ import React from "react"; import {Button, setUserSession, Text, TextInput, useForm, useService} from "@code0-tech/pictor"; -import {UserService} from "@edition/user/User.service"; +import {UserService} from "@edition/user/services/User.service"; import Link from "next/link"; import Image from "next/image"; import {useRouter} from "next/navigation"; diff --git a/src/packages/ce/src/auth/UserForgotPasswordPage.tsx b/src/packages/ce/src/user/pages/UserForgotPasswordPage.tsx similarity index 97% rename from src/packages/ce/src/auth/UserForgotPasswordPage.tsx rename to src/packages/ce/src/user/pages/UserForgotPasswordPage.tsx index 739e8af8..40144c35 100644 --- a/src/packages/ce/src/auth/UserForgotPasswordPage.tsx +++ b/src/packages/ce/src/user/pages/UserForgotPasswordPage.tsx @@ -2,7 +2,7 @@ import React from "react"; import {Button, EmailInput, emailValidation, Text, useForm, useService} from "@code0-tech/pictor"; -import {UserService} from "@edition/user/User.service"; +import {UserService} from "@edition/user/services/User.service"; import Link from "next/link"; import Image from "next/image"; import {useRouter} from "next/navigation"; diff --git a/src/packages/ce/src/auth/UserLoginPage.tsx b/src/packages/ce/src/user/pages/UserLoginPage.tsx similarity index 98% rename from src/packages/ce/src/auth/UserLoginPage.tsx rename to src/packages/ce/src/user/pages/UserLoginPage.tsx index e116c0e1..190587c7 100644 --- a/src/packages/ce/src/auth/UserLoginPage.tsx +++ b/src/packages/ce/src/user/pages/UserLoginPage.tsx @@ -13,7 +13,7 @@ import { useForm, useService } from "@code0-tech/pictor"; -import {UserService} from "@edition/user/User.service"; +import {UserService} from "@edition/user/services/User.service"; import Image from "next/image"; import Link from "next/link"; import {useRouter, useSearchParams} from "next/navigation"; diff --git a/src/packages/ce/src/auth/UserRegistrationPage.tsx b/src/packages/ce/src/user/pages/UserRegistrationPage.tsx similarity index 98% rename from src/packages/ce/src/auth/UserRegistrationPage.tsx rename to src/packages/ce/src/user/pages/UserRegistrationPage.tsx index 9d4d3d3d..354b8177 100644 --- a/src/packages/ce/src/auth/UserRegistrationPage.tsx +++ b/src/packages/ce/src/user/pages/UserRegistrationPage.tsx @@ -14,7 +14,7 @@ import { } from "@code0-tech/pictor"; import Image from "next/image"; import Link from "next/link"; -import {UserService} from "@edition/user/User.service"; +import {UserService} from "@edition/user/services/User.service"; import {useRouter} from "next/navigation"; export const UserRegistrationPage: React.FC = () => { diff --git a/src/packages/ce/src/auth/UserResetPasswordPage.tsx b/src/packages/ce/src/user/pages/UserResetPasswordPage.tsx similarity index 98% rename from src/packages/ce/src/auth/UserResetPasswordPage.tsx rename to src/packages/ce/src/user/pages/UserResetPasswordPage.tsx index c1d9c75a..b9d4ba14 100644 --- a/src/packages/ce/src/auth/UserResetPasswordPage.tsx +++ b/src/packages/ce/src/user/pages/UserResetPasswordPage.tsx @@ -2,7 +2,7 @@ import React from "react"; import {Alert, Button, PasswordInput, Spacing, Text, TextInput, useForm, useService} from "@code0-tech/pictor"; -import {UserService} from "@edition/user/User.service"; +import {UserService} from "@edition/user/services/User.service"; import Link from "next/link"; import Image from "next/image"; import {useRouter, useSearchParams} from "next/navigation"; diff --git a/src/packages/ce/src/user/pages/UsersPage.tsx b/src/packages/ce/src/user/pages/UsersPage.tsx new file mode 100644 index 00000000..9321eba3 --- /dev/null +++ b/src/packages/ce/src/user/pages/UsersPage.tsx @@ -0,0 +1,116 @@ +"use client" + +import React from "react"; +import {Button, ButtonGroup, Flex, Spacing, Text, useService, useStore, useUserSession, Menu, MenuTrigger, MenuPortal, MenuContent, MenuCheckboxItem} from "@code0-tech/pictor"; +import {UserService} from "@edition/user/services/User.service"; +import {notFound} from "next/navigation"; +import {UserDataTableComponent} from "@edition/user/components/UserDataTableComponent"; +import {DataTableFilterProps, DataTableSortProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import {UserDataTableFilterInputComponent} from "@edition/user/components/UserDataTableFilterInputComponent"; +import Link from "next/link"; +import {IconMinus, IconSortAscending, IconSortDescending} from "@tabler/icons-react"; + +export const UsersPage: React.FC = () => { + + const currentSession = useUserSession() + const userStore = useStore(UserService) + const userService = useService(UserService) + const currentUser = React.useMemo(() => userService.getById(currentSession?.user?.id), [userStore, currentSession]) + + const [filter, setFilter] = React.useState({}) + const [sort, setSort] = React.useState({}) + + if (currentUser && !currentUser.admin) { + notFound() + } + + return
+ + + + Users + + + Manage users who have access to your instance. You can invite new users and remove existing ones. + + + + + + + + + + + { + if (sort["username"] === undefined) + setSort(prev => ({...prev, username: "asc"})) + else if (sort["username"] === "asc") + setSort(prev => ({...prev, username: "desc"})) + else + setSort(prev => ({...prev, username: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["username"] === undefined ? : sort["name"] === "asc" ? + : } + Username + + { + if (sort["createdAt"] === undefined) + setSort(prev => ({...prev, createdAt: "asc"})) + else if (sort["createdAt"] === "asc") + setSort(prev => ({...prev, createdAt: "desc"})) + else + setSort(prev => ({...prev, createdAt: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["createdAt"] === undefined ? + : sort["createdAt"] === "asc" ? + : } + Created At + + { + if (sort["updatedAt"] === undefined) + setSort(prev => ({...prev, updatedAt: "asc"})) + else if (sort["updatedAt"] === "asc") + setSort(prev => ({...prev, updatedAt: "desc"})) + else + setSort(prev => ({...prev, updatedAt: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["updatedAt"] === undefined ? + : sort["updatedAt"] === "asc" ? + : } + Updated At + + + + + + + +
+ setFilter(filter)}/> +
+ + +
+} \ No newline at end of file diff --git a/src/packages/ce/src/user/User.service.ts b/src/packages/ce/src/user/services/User.service.ts similarity index 94% rename from src/packages/ce/src/user/User.service.ts rename to src/packages/ce/src/user/services/User.service.ts index 51daf1d6..89c3d4d5 100644 --- a/src/packages/ce/src/user/User.service.ts +++ b/src/packages/ce/src/user/services/User.service.ts @@ -40,13 +40,14 @@ import passwordResetRequestMutation from "./mutations/User.passwordResetRequest. import usersQuery from "./queries/Users.query.graphql"; import userByUsernameQuery from "./queries/User.byUsername.query.graphql"; import userByIdQuery from "./queries/User.byId.query.graphql"; +import {View} from "@code0-tech/pictor/dist/utils/view"; export class UserService extends DUserReactiveService { private readonly client: GraphqlClient private i = 0; - constructor(client: GraphqlClient, store: ReactiveArrayStore) { + constructor(client: GraphqlClient, store: ReactiveArrayStore>) { super(store); this.client = client } @@ -59,10 +60,10 @@ export class UserService extends DUserReactiveService { const data = result.data if (!data) return - if (data && data.currentUser && !this.hasById(data.currentUser.id)) this.set(this.i++, new DUserView(data.currentUser)) + if (data && data.currentUser && !this.hasById(data.currentUser.id)) this.set(this.i++, new View(new DUserView(data.currentUser))) if (data.users && data.users.nodes) { data.users.nodes.forEach((user) => { - if (user && !(user.id === data.currentUser?.id) && !this.hasById(user.id)) this.set(this.i++, new DUserView(user)) + if (user && !(user.id === data.currentUser?.id) && !this.hasById(user.id)) this.set(this.i++, new View(new DUserView(user))) }) } }) @@ -83,7 +84,7 @@ export class UserService extends DUserReactiveService { const data = result.data if (!data) return - if (data && data.user && !this.hasById(data.user.id)) this.set(this.i++, new DUserView(data.user)) + if (data && data.user && !this.hasById(data.user.id)) this.set(this.i++, new View(new DUserView(data.user))) }) } @@ -102,7 +103,7 @@ export class UserService extends DUserReactiveService { const data = result.data if (!data) return - if (data && data.user && !this.hasById(data.user.id)) this.set(this.i++, new DUserView(data.user)) + if (data && data.user && !this.hasById(data.user.id)) this.set(this.i++, new View(new DUserView(data.user))) }) return super.getByUsername(username) @@ -163,7 +164,7 @@ export class UserService extends DUserReactiveService { }) if (result.data && result.data.usersLogin && result.data.usersLogin.userSession?.user && !this.hasById(result.data.usersLogin.userSession?.user.id)) { - this.add(new DUserView(result.data.usersLogin.userSession.user)) + this.add(new View(new DUserView(result.data.usersLogin.userSession.user))) } return result.data?.usersLogin ?? undefined @@ -231,7 +232,7 @@ export class UserService extends DUserReactiveService { }) if (result.data && result.data.usersRegister && result.data.usersRegister.userSession?.user && !this.hasById(result.data.usersRegister.userSession?.user.id)) { - this.add(new DUserView(result.data.usersRegister.userSession.user)) + this.add(new View(new DUserView(result.data.usersRegister.userSession.user))) } return result.data?.usersRegister ?? undefined diff --git a/src/packages/ce/src/user/fragments/User.basic.fragment.graphql b/src/packages/ce/src/user/services/fragments/User.basic.fragment.graphql similarity index 100% rename from src/packages/ce/src/user/fragments/User.basic.fragment.graphql rename to src/packages/ce/src/user/services/fragments/User.basic.fragment.graphql diff --git a/src/packages/ce/src/user/fragments/User.fragment.graphql b/src/packages/ce/src/user/services/fragments/User.fragment.graphql similarity index 81% rename from src/packages/ce/src/user/fragments/User.fragment.graphql rename to src/packages/ce/src/user/services/fragments/User.fragment.graphql index 90282af6..187ec202 100644 --- a/src/packages/ce/src/user/fragments/User.fragment.graphql +++ b/src/packages/ce/src/user/services/fragments/User.fragment.graphql @@ -1,5 +1,5 @@ -#import "../identity/fragments/Identity.fragment.graphql" -#import "../session/fragments/Session.fragment.graphql" +#import "@edition/user/services/identity/fragments/Identity.fragment.graphql" +#import "@edition/user/services/session/fragments/Session.fragment.graphql" fragment User on User { __typename admin diff --git a/src/packages/ce/src/user/fragments/User.id.fragment.graphql b/src/packages/ce/src/user/services/fragments/User.id.fragment.graphql similarity index 100% rename from src/packages/ce/src/user/fragments/User.id.fragment.graphql rename to src/packages/ce/src/user/services/fragments/User.id.fragment.graphql diff --git a/src/packages/ce/src/user/identity/fragments/Identity.fragment.graphql b/src/packages/ce/src/user/services/identity/fragments/Identity.fragment.graphql similarity index 100% rename from src/packages/ce/src/user/identity/fragments/Identity.fragment.graphql rename to src/packages/ce/src/user/services/identity/fragments/Identity.fragment.graphql diff --git a/src/packages/ce/src/user/mutations/User.emailVerification.mutation.graphql b/src/packages/ce/src/user/services/mutations/User.emailVerification.mutation.graphql similarity index 100% rename from src/packages/ce/src/user/mutations/User.emailVerification.mutation.graphql rename to src/packages/ce/src/user/services/mutations/User.emailVerification.mutation.graphql diff --git a/src/packages/ce/src/user/mutations/User.login.mutation.graphql b/src/packages/ce/src/user/services/mutations/User.login.mutation.graphql similarity index 100% rename from src/packages/ce/src/user/mutations/User.login.mutation.graphql rename to src/packages/ce/src/user/services/mutations/User.login.mutation.graphql diff --git a/src/packages/ce/src/user/mutations/User.logout.mutation.graphql b/src/packages/ce/src/user/services/mutations/User.logout.mutation.graphql similarity index 100% rename from src/packages/ce/src/user/mutations/User.logout.mutation.graphql rename to src/packages/ce/src/user/services/mutations/User.logout.mutation.graphql diff --git a/src/packages/ce/src/user/mutations/User.passwordReset.mutation.graphql b/src/packages/ce/src/user/services/mutations/User.passwordReset.mutation.graphql similarity index 100% rename from src/packages/ce/src/user/mutations/User.passwordReset.mutation.graphql rename to src/packages/ce/src/user/services/mutations/User.passwordReset.mutation.graphql diff --git a/src/packages/ce/src/user/mutations/User.passwordResetRequest.mutation.graphql b/src/packages/ce/src/user/services/mutations/User.passwordResetRequest.mutation.graphql similarity index 100% rename from src/packages/ce/src/user/mutations/User.passwordResetRequest.mutation.graphql rename to src/packages/ce/src/user/services/mutations/User.passwordResetRequest.mutation.graphql diff --git a/src/packages/ce/src/user/mutations/User.register.mutation.graphql b/src/packages/ce/src/user/services/mutations/User.register.mutation.graphql similarity index 100% rename from src/packages/ce/src/user/mutations/User.register.mutation.graphql rename to src/packages/ce/src/user/services/mutations/User.register.mutation.graphql diff --git a/src/packages/ce/src/user/queries/User.byId.query.graphql b/src/packages/ce/src/user/services/queries/User.byId.query.graphql similarity index 100% rename from src/packages/ce/src/user/queries/User.byId.query.graphql rename to src/packages/ce/src/user/services/queries/User.byId.query.graphql diff --git a/src/packages/ce/src/user/queries/User.byUsername.query.graphql b/src/packages/ce/src/user/services/queries/User.byUsername.query.graphql similarity index 100% rename from src/packages/ce/src/user/queries/User.byUsername.query.graphql rename to src/packages/ce/src/user/services/queries/User.byUsername.query.graphql diff --git a/src/packages/ce/src/user/queries/Users.query.graphql b/src/packages/ce/src/user/services/queries/Users.query.graphql similarity index 100% rename from src/packages/ce/src/user/queries/Users.query.graphql rename to src/packages/ce/src/user/services/queries/Users.query.graphql diff --git a/src/packages/ce/src/user/session/fragments/Session.fragment.graphql b/src/packages/ce/src/user/services/session/fragments/Session.fragment.graphql similarity index 100% rename from src/packages/ce/src/user/session/fragments/Session.fragment.graphql rename to src/packages/ce/src/user/services/session/fragments/Session.fragment.graphql