From e997f071b6484405623d9fa636c33e2bc24df28b Mon Sep 17 00:00:00 2001 From: Tom Hiller Date: Sun, 26 Oct 2025 19:39:01 -0400 Subject: [PATCH 1/5] feat: replace setting.json with enviromental variables --- .env | 3 +++ public/settings.json | 1 - src/core/utils/constants.ts | 10 ++++++++++ vite.config.ts | 1 + 4 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 .env delete mode 100644 public/settings.json create mode 100644 src/core/utils/constants.ts diff --git a/.env b/.env new file mode 100644 index 0000000..ab3c310 --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +MMP_BACKEND_HOST="localhost:8081" +MMP_BACKEND_PATH="/api" + diff --git a/public/settings.json b/public/settings.json deleted file mode 100644 index 78c7455..0000000 --- a/public/settings.json +++ /dev/null @@ -1 +0,0 @@ -{"localBackend":"/api"} \ No newline at end of file diff --git a/src/core/utils/constants.ts b/src/core/utils/constants.ts new file mode 100644 index 0000000..dae0abf --- /dev/null +++ b/src/core/utils/constants.ts @@ -0,0 +1,10 @@ +const BACKEND_SCHEMALESS_URL_ROOT = [ + import.meta.env.MMP_BACKEND_HOST ?? window.location.host, + import.meta.env.MMP_BACKEND_PATH +].join(''); + +const BACKEND_HTTP_URL_ROOT = `http://${BACKEND_SCHEMALESS_URL_ROOT}`; + +export { + BACKEND_HTTP_URL_ROOT, +} \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index 09c65ba..7e92be1 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -4,6 +4,7 @@ import react from '@vitejs/plugin-react' // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], + envPrefix: 'MMP_', resolve: { alias: [ { find: '@', replacement: '/src' }, From ad85f7e8d948c3a5ff08f51d237a6c73c0d5e91a Mon Sep 17 00:00:00 2001 From: Tom Hiller Date: Sun, 26 Oct 2025 19:39:48 -0400 Subject: [PATCH 2/5] chore(package.json): add missing types for react-modal-image --- package-lock.json | 35 ++++++++++++++++++++++++++++++++++- package.json | 1 + 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 6491829..5807454 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,6 +44,7 @@ "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", "@types/react-grid-layout": "^1.3.5", + "@types/react-modal-image": "^2.6.4", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "@vitejs/plugin-react": "^4.0.3", @@ -1868,6 +1869,18 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, + "node_modules/@types/node": { + "version": "24.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz", + "integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "undici-types": "~7.16.0" + } + }, "node_modules/@types/object.omit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/object.omit/-/object.omit-3.0.3.tgz", @@ -1918,6 +1931,16 @@ "@types/react": "*" } }, + "node_modules/@types/react-modal-image": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@types/react-modal-image/-/react-modal-image-2.6.4.tgz", + "integrity": "sha512-wL/ymT7/5cqk5xWOALHk+655QvD0CxuDFaxYorWUgMkltadIqCJJf+XVtPT8pcLhLDzTi2I5g/yCLr248+eobg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-reconciler": { "version": "0.26.7", "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.26.7.tgz", @@ -4523,7 +4546,8 @@ "node_modules/react-modal-image": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/react-modal-image/-/react-modal-image-2.6.0.tgz", - "integrity": "sha512-NNc1xPKzFAn0VsNMdJ8NXt6c54aL/z0fcoYmw9qn4SBUONdGl+8LOQ0sTfo0wtdzcjLiby/ncloHcAL+UI+wIA==" + "integrity": "sha512-NNc1xPKzFAn0VsNMdJ8NXt6c54aL/z0fcoYmw9qn4SBUONdGl+8LOQ0sTfo0wtdzcjLiby/ncloHcAL+UI+wIA==", + "license": "MIT" }, "node_modules/react-number-format": { "version": "5.3.1", @@ -5125,6 +5149,15 @@ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", "peer": true }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/update-browserslist-db": { "version": "1.0.13", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", diff --git a/package.json b/package.json index a7338a8..26fe266 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", "@types/react-grid-layout": "^1.3.5", + "@types/react-modal-image": "^2.6.4", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "@vitejs/plugin-react": "^4.0.3", From 92428e0b81ce373dacf26d4552a9435bd50d1128 Mon Sep 17 00:00:00 2001 From: Tom Hiller Date: Tue, 28 Oct 2025 21:28:33 -0400 Subject: [PATCH 3/5] chore(package.json): add tanstack react query --- package-lock.json | 334 +++++++++++++++++++++++++++++++++++++++------- package.json | 2 + 2 files changed, 291 insertions(+), 45 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5807454..5d9920e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "@react-three/drei": "^9.88.13", "@react-three/fiber": "^8.15.11", "@tabler/icons-react": "^2.42.0", + "@tanstack/react-query": "^5.90.5", "@tiptap/extension-link": "^2.1.13", "@tiptap/react": "^2.1.13", "@tiptap/starter-kit": "^2.1.13", @@ -41,6 +42,7 @@ "three": "^0.158.0" }, "devDependencies": { + "@tanstack/eslint-plugin-query": "^5.91.2", "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", "@types/react-grid-layout": "^1.3.5", @@ -789,16 +791,20 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "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==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } @@ -863,10 +869,11 @@ } }, "node_modules/@eslint/js": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", - "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -920,13 +927,15 @@ "integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==" }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { @@ -947,10 +956,12 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", - "dev": true + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", @@ -1457,6 +1468,204 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0" } }, + "node_modules/@tanstack/eslint-plugin-query": { + "version": "5.91.2", + "resolved": "https://registry.npmjs.org/@tanstack/eslint-plugin-query/-/eslint-plugin-query-5.91.2.tgz", + "integrity": "sha512-UPeWKl/Acu1IuuHJlsN+eITUHqAaa9/04geHHPedY8siVarSaWprY0SVMKrkpKfk5ehRT7+/MZ5QwWuEtkWrFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.44.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/@tanstack/eslint-plugin-query/node_modules/@typescript-eslint/scope-manager": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.2.tgz", + "integrity": "sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@tanstack/eslint-plugin-query/node_modules/@typescript-eslint/types": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.2.tgz", + "integrity": "sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@tanstack/eslint-plugin-query/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.2.tgz", + "integrity": "sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.46.2", + "@typescript-eslint/tsconfig-utils": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", + "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" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@tanstack/eslint-plugin-query/node_modules/@typescript-eslint/utils": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.2.tgz", + "integrity": "sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@tanstack/eslint-plugin-query/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.2.tgz", + "integrity": "sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@tanstack/eslint-plugin-query/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tanstack/eslint-plugin-query/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@tanstack/eslint-plugin-query/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tanstack/eslint-plugin-query/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/@tanstack/query-core": { + "version": "5.90.5", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.5.tgz", + "integrity": "sha512-wLamYp7FaDq6ZnNehypKI5fNvxHPfTYylE0m/ZpuuzJfJqhR5Pxg9gvGBHZx4n7J+V5Rg5mZxHHTlv25Zt5u+w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.90.5", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.5.tgz", + "integrity": "sha512-pN+8UWpxZkEJ/Rnnj2v2Sxpx1WFlaa9L6a4UO89p6tTQbeo+m0MS8oYDjbggrR8QcTyjKoYWKS3xJQGr3ExT8Q==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.90.5" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, "node_modules/@tiptap/core": { "version": "2.1.13", "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.1.13.tgz", @@ -2052,6 +2261,42 @@ } } }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.2.tgz", + "integrity": "sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.46.2", + "@typescript-eslint/types": "^8.46.2", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service/node_modules/@typescript-eslint/types": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.2.tgz", + "integrity": "sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/scope-manager": { "version": "6.13.2", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.2.tgz", @@ -2069,6 +2314,23 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.2.tgz", + "integrity": "sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, "node_modules/@typescript-eslint/type-utils": { "version": "6.13.2", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.13.2.tgz", @@ -2841,16 +3103,18 @@ } }, "node_modules/eslint": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", - "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.55.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -4846,13 +5110,11 @@ } }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -4860,24 +5122,6 @@ "node": ">=10" } }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", diff --git a/package.json b/package.json index 26fe266..ef5356a 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@react-three/drei": "^9.88.13", "@react-three/fiber": "^8.15.11", "@tabler/icons-react": "^2.42.0", + "@tanstack/react-query": "^5.90.5", "@tiptap/extension-link": "^2.1.13", "@tiptap/react": "^2.1.13", "@tiptap/starter-kit": "^2.1.13", @@ -43,6 +44,7 @@ "three": "^0.158.0" }, "devDependencies": { + "@tanstack/eslint-plugin-query": "^5.91.2", "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", "@types/react-grid-layout": "^1.3.5", From 70d5c3d2da9f855c5dbfb0703eb96ca3321b2f63 Mon Sep 17 00:00:00 2001 From: Tom Hiller Date: Tue, 28 Oct 2025 21:30:45 -0400 Subject: [PATCH 4/5] chore(eslint): add tanstack reacy query --- .eslintrc.cjs | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index d6c9537..c64c105 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -5,6 +5,7 @@ module.exports = { 'eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:react-hooks/recommended', + 'plugin:@tanstack/query/recommended', ], ignorePatterns: ['dist', '.eslintrc.cjs'], parser: '@typescript-eslint/parser', From 5aac25088d47d352cf218b54eb09018e619fe4f4 Mon Sep 17 00:00:00 2001 From: Tom Hiller Date: Tue, 28 Oct 2025 21:41:05 -0400 Subject: [PATCH 5/5] feat: replace axios hook with react-query --- src/apiServices/axios.ts | 9 ++ src/apiServices/downloader.ts | 15 ++ src/apiServices/printers.ts | 92 ++++++++++++ src/apiServices/projects.ts | 136 ++++++++++++++++++ src/apiServices/system.ts | 54 +++++++ src/apiServices/tempFiles.ts | 60 ++++++++ .../components/asset-card/AssetCard.tsx | 17 ++- .../components/asset-details/AssetDetails.tsx | 1 - .../model-detail-pane/ModelDetailPane.tsx | 13 +- .../parts/drop-down-menu/DropDownMenu.tsx | 39 +---- .../parts/set-as-main/SetAsMain.tsx | 28 +--- src/core/settings/settingsContext.ts | 27 ++-- src/core/settings/settingsProvider.tsx | 50 ++----- src/core/sse/SSEContext.ts | 5 +- src/core/sse/SSEProvider.tsx | 16 +-- src/main.tsx | 13 +- .../edit-printer-page/EditPrinterPage.tsx | 13 +- .../parts/printer-form/PrinterForm.tsx | 41 +++--- .../sent-to-printer-btn/SendToPrinterBtn.tsx | 37 ++--- .../components/printers-page/PrintersPage.tsx | 41 +++--- .../widgets/configs/PrinterWidgetConfig.tsx | 10 +- .../PrinterTableWidget.tsx | 13 +- .../widgets/printer-widget/PrinterWidget.tsx | 13 +- .../parts/project-form/ProjectForm.tsx | 27 ++-- .../components/project-page/ProjectPage.tsx | 9 +- .../project-page-body/ProjectPageBody.tsx | 12 +- .../parts/add-asset/AddAsset.tsx | 27 ++-- .../project-operations/ProjectOperations.tsx | 43 +++--- .../delete-btn/DeleteBtn.tsx | 22 ++- .../discover-btn/DiscoverBtn.tsx | 43 +++--- .../parts/import-project/ImportProject.tsx | 17 ++- .../parts/projects-list/ProjectsList.tsx | 6 +- .../parts/project-card/ProjectCard.tsx | 7 +- .../project-filter-card/ProjectFilterCard.tsx | 13 +- .../parts/project-filter/ProjectFilter.tsx | 11 +- .../server-operations/ServerOperations.tsx | 37 ++--- .../parts/settings-form/SettingsForm.tsx | 25 ++-- .../components/temp-files/TempFiles.tsx | 87 ++++++----- 38 files changed, 684 insertions(+), 445 deletions(-) create mode 100644 src/apiServices/axios.ts create mode 100644 src/apiServices/downloader.ts create mode 100644 src/apiServices/printers.ts create mode 100644 src/apiServices/projects.ts create mode 100644 src/apiServices/system.ts create mode 100644 src/apiServices/tempFiles.ts diff --git a/src/apiServices/axios.ts b/src/apiServices/axios.ts new file mode 100644 index 0000000..926f618 --- /dev/null +++ b/src/apiServices/axios.ts @@ -0,0 +1,9 @@ +import axios from 'axios'; + +import { BACKEND_HTTP_URL_ROOT } from "@/core//utils/constants"; + +const backendAxiosInstance = axios.create({ + baseURL: BACKEND_HTTP_URL_ROOT, +}); + +export default backendAxiosInstance; \ No newline at end of file diff --git a/src/apiServices/downloader.ts b/src/apiServices/downloader.ts new file mode 100644 index 0000000..ba761b0 --- /dev/null +++ b/src/apiServices/downloader.ts @@ -0,0 +1,15 @@ +import backendAxiosInstance from './axios'; + +/** + * + * @returns + */ +const useDownloader = () => ( + (data: unknown) => ( + backendAxiosInstance.post('downloader/fetch', data) + ) +); + +export { + useDownloader, +} \ No newline at end of file diff --git a/src/apiServices/printers.ts b/src/apiServices/printers.ts new file mode 100644 index 0000000..583bd01 --- /dev/null +++ b/src/apiServices/printers.ts @@ -0,0 +1,92 @@ +import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { Printer } from '@/printers/entities/Printer'; +import backendAxiosInstance from './axios'; + +/** + * + * @returns + */ +const useGetPrinters = () => ( + useQuery({ + queryKey: ['GetPrinters'], + queryFn: async () => await backendAxiosInstance.get('/printers'), + }) +); + +/** + * + * @returns + */ +const useGetPrinter = (printerUuid: string) => ( + useQuery({ + queryKey: [`GetPrinters-${printerUuid}`], + queryFn: async () => await backendAxiosInstance.get(`/printers${printerUuid}`), + }) +); + +/** + * + * @returns + */ +const useSendToPrinter = () => ( + (printerUuid: string, assetId: string) => ( + backendAxiosInstance.get(`/printers/${printerUuid}/send/${assetId}`) + ) +); + +/** + * + * @returns + */ +const usePostTestPrinters = () => ( + (data: unknown) => backendAxiosInstance.post('/printers/test', data) +); + +/** + * + * @returns + */ +const usePostSavePrinter = () => { + const queryClient = useQueryClient(); + + return (printerUuid: string|undefined, data: unknown) => ( + backendAxiosInstance.post(`/printers${printerUuid ? '/' + printerUuid : ''}`, data) + .then((response) => { + queryClient.invalidateQueries({ queryKey: ['GetPrinters']}); + return response; + }) + .catch((response) => { + queryClient.invalidateQueries({ queryKey: ['GetPrinters']}); + return response; + }) + ) +} + +/** + * + * @returns + */ +const useDeletePrinter = () => { + const queryClient = useQueryClient(); + + return (printerUuid: string) => ( + backendAxiosInstance.post(`/printers/${printerUuid}/delete`) + .then((data) => { + queryClient.invalidateQueries({ queryKey: ['GetPrinters']}); + return data; + }) + .catch((data) => { + queryClient.invalidateQueries({ queryKey: ['GetPrinters']}); + return data; + }) + ) +} + +export { + useGetPrinters, + useGetPrinter, + usePostTestPrinters, + usePostSavePrinter, + useDeletePrinter, + useSendToPrinter, +}; \ No newline at end of file diff --git a/src/apiServices/projects.ts b/src/apiServices/projects.ts new file mode 100644 index 0000000..027003f --- /dev/null +++ b/src/apiServices/projects.ts @@ -0,0 +1,136 @@ +// import { Asset } from "@/assets/entities/Assets"; +import { Project } from '@/projects/entities/Project'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; + +import backendAxiosInstance from './axios'; + +const useGetProjects = () => ( + useQuery({ + queryKey: ['GetProjects'], + queryFn: async () => { + return await backendAxiosInstance.get('/projects'); + }, + }) +); + +const useGetProjectsList = () => ( + useQuery({ + queryKey: ['GetProjectsList'], + queryFn: async () => { + return await backendAxiosInstance.get('/projects/lists'); + }, + }) +); + +const useDiscoverProject = (projectUuid: string, enabled: boolean = false) => ( + useQuery({ + queryKey: [`GetProjectDiscover$${projectUuid}`], + queryFn: async () => { + return await backendAxiosInstance.get(`projects/${projectUuid}/discover`); + }, + enabled, + }) +); + + +const usePostProject = () => { + const queryClient = useQueryClient(); + + return (projectUuid: string, data: unknown) => ( + backendAxiosInstance.post(`/projects${projectUuid ? "/" + projectUuid: ''}`, data) + .then((data) => { + queryClient.invalidateQueries({ queryKey: ['GetProjects']}); + return data; + }) + .catch((data) => { + queryClient.invalidateQueries({ queryKey: ['GetProjects']}); + return data; + }) + ) +}; + + +const useMoveProject = () => { + const queryClient = useQueryClient(); + + return (projectUuid: string, data: unknown) => ( + backendAxiosInstance.post(`/projects/${projectUuid}`, data) + .then((data) => { + queryClient.invalidateQueries({ queryKey: ['GetProjects']}); + return data; + }) + .catch((data) => { + queryClient.invalidateQueries({ queryKey: ['GetProjects']}); + return data; + }) + ) +} + +const useDeleteProject = () => { + const queryClient = useQueryClient(); + + return (projectUuid: string) => ( + backendAxiosInstance.post(`/projects/${projectUuid}`) + .then((data) => { + queryClient.invalidateQueries({ queryKey: ['GetProjects']}); + return data; + }) + .catch((data) => { + queryClient.invalidateQueries({ queryKey: ['GetProjects']}); + return data; + }) + ) +} + +const usePostProjectAsset = () => { + const queryClient = useQueryClient(); + + return (projectUuid: string, data: unknown) => ( + backendAxiosInstance.post(`/projects${projectUuid}/assets`, data) + .then((data) => { + queryClient.invalidateQueries({ queryKey: ['GetProjects']}); + return data; + }) + .catch((data) => { + queryClient.invalidateQueries({ queryKey: ['GetProjects']}); + return data; + }) + ) +}; + +const useDeleteProjectAsset = () => { + const queryClient = useQueryClient(); + + return (projectUuid: string, assetId: string) => ( + backendAxiosInstance.post(`/projects/${projectUuid}/assets/${assetId}/delete`) + .then((data) => { + queryClient.invalidateQueries({ queryKey: ['GetProjects']}); + return data; + }) + .catch((data) => { + queryClient.invalidateQueries({ queryKey: ['GetProjects']}); + return data; + }) + ) +} + +const useSetMainImage = () => ( + (projectUuid: string, assetId: string) => ( + backendAxiosInstance.post(`projects/${projectUuid}/image`, { + uuid: projectUuid, + default_image_id: assetId + }) + ) +); + +export { + useGetProjects, + usePostProject, + useDeleteProject, + useDiscoverProject, + usePostProjectAsset, + useDeleteProjectAsset, + useMoveProject, + useSetMainImage, + useGetProjectsList, +}; \ No newline at end of file diff --git a/src/apiServices/system.ts b/src/apiServices/system.ts new file mode 100644 index 0000000..1e228d2 --- /dev/null +++ b/src/apiServices/system.ts @@ -0,0 +1,54 @@ +import { useQuery, useQueryClient } from '@tanstack/react-query'; +import backendAxiosInstance from './axios'; +import { AgentSettings } from "@/settings/entities/AgentSettings"; + +const useGetPaths = () => ( + useQuery({ + queryKey: ['GetPaths'], + queryFn: async () => { + return await backendAxiosInstance.get('/system/paths'); + }, + }) +); + +const useGetSettings = () => ( + useQuery({ + queryKey: ['GetSettings'], + queryFn: async () => { + return await backendAxiosInstance.get('/system/settings'); + }, + }) +); + +const useGetDiscovery = (enabled: boolean = false) => ( + useQuery({ + queryKey: ['GetDiscovery'], + queryFn: async () => { + return await backendAxiosInstance.get('/system/discovery'); + }, + enabled, + }) +); + +const usePostSettings = () => { + const queryClient = useQueryClient(); + + return (data: unknown) => ( + backendAxiosInstance.post('/system/settings', data) + .then((data) => { + queryClient.invalidateQueries({ queryKey: ['GetSettings']}); + return data; + }) + .catch((data) => { + queryClient.invalidateQueries({ queryKey: ['GetSettings']}); + return data; + }) + ) +}; + +export { + useGetPaths, + useGetSettings, + useGetDiscovery, + usePostSettings, +} \ No newline at end of file diff --git a/src/apiServices/tempFiles.ts b/src/apiServices/tempFiles.ts new file mode 100644 index 0000000..f3ebb58 --- /dev/null +++ b/src/apiServices/tempFiles.ts @@ -0,0 +1,60 @@ +import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { TempFile } from '@/tempfiles/entities/TempFile'; +import backendAxiosInstance from './axios'; + +/** + * + * @returns + */ +const useGetTempFiles = () => ( + useQuery({ + queryKey: ['GetTempFiles'], + queryFn: async () => await backendAxiosInstance.get('/tempfiles'), + }) +); + +/** + * + * @returns + */ +const usePostTempFile = () => { + const queryClient = useQueryClient(); + + return (tempfileUuid: string|undefined, data: unknown,) => ( + backendAxiosInstance.post(`/tempfiles${tempfileUuid ? '/' + tempfileUuid : ''}`, data) + .then((response) => { + queryClient.invalidateQueries({ queryKey: ['GetTempFiles']}); + return response; + }) + .catch((response) => { + queryClient.invalidateQueries({ queryKey: ['GetTempFiles']}); + return response; + }) + ) +} + +/** + * + * @returns + */ +const useDeleteTempFile = () => { + const queryClient = useQueryClient(); + + return (tempfileUuid: string) => ( + backendAxiosInstance.post(`/tempfiles/${tempfileUuid}/delete`) + .then((data) => { + queryClient.invalidateQueries({ queryKey: ['GetTempFiles']}); + return data; + }) + .catch((data) => { + queryClient.invalidateQueries({ queryKey: ['GetTempFiles']}); + return data; + }) + ) +} + +export { + usePostTempFile, + useDeleteTempFile, + useGetTempFiles, +}; \ No newline at end of file diff --git a/src/assets/components/asset-card/AssetCard.tsx b/src/assets/components/asset-card/AssetCard.tsx index b09d7d7..dd83af1 100644 --- a/src/assets/components/asset-card/AssetCard.tsx +++ b/src/assets/components/asset-card/AssetCard.tsx @@ -4,11 +4,11 @@ import classes from './AssetCard.module.css'; import { Icon3dRotate, IconFile, IconFile3d, IconFileTypePdf, IconZoomScan } from "@tabler/icons-react"; import { DropDownMenu } from "../parts/drop-down-menu/DropDownMenu"; import { SetAsMain } from "../parts/set-as-main/SetAsMain"; -import { SettingsContext } from "@/core/settings/settingsContext"; -import { useCallback, useContext, useState } from "react"; +import { useCallback, useState } from "react"; import { Lightbox } from "react-modal-image"; import { useToggle } from "@mantine/hooks"; import { SelectBtn } from "../parts/select-btn/SelectBtn"; +import { BACKEND_HTTP_URL_ROOT } from "@/core/utils/constants"; type AssetCardProps = { asset: Asset; @@ -27,21 +27,20 @@ iconMap.set('.stl', ); export function AssetCard({ asset, focused, onFocused, onDelete, onChange, view3d, onView3dChange }: AssetCardProps) { const theme = useMantineTheme(); - const { settings } = useContext(SettingsContext); const [loading, setLoading] = useState(false); const [modal, toggleModal] = useToggle([false, true]); const toggleLoadingCallback = useCallback(() => { setLoading((l) => { return !l }) - }, [loading]) + }, []) const size = rem('280px'); return ( <> {modal && asset.image_id && asset.image_id != "" && } @@ -50,7 +49,7 @@ export function AssetCard({ asset, focused, onFocused, onDelete, onChange, view3 {asset?.image_id === "" ? (iconMap.get(asset.extension) ?? ) : {asset.name} } @@ -78,9 +77,9 @@ export function AssetCard({ asset, focused, onFocused, onDelete, onChange, view3 } < DropDownMenu projectUuid={asset.project_uuid} - id={asset.id} + assetId={asset.id} openDetails={() => { onFocused() }} - downloadURL={`${settings.localBackend}/projects/${asset.project_uuid}/assets/${asset.id}/file?download=true'`} + downloadURL={`${BACKEND_HTTP_URL_ROOT}/projects/${asset.project_uuid}/assets/${asset.id}/file?download=true'`} onDelete={onDelete} toggleLoad={toggleLoadingCallback}> diff --git a/src/assets/components/asset-details/AssetDetails.tsx b/src/assets/components/asset-details/AssetDetails.tsx index 72bea46..e1a4d6e 100644 --- a/src/assets/components/asset-details/AssetDetails.tsx +++ b/src/assets/components/asset-details/AssetDetails.tsx @@ -7,7 +7,6 @@ type AssetDetailsProps = { asset: Asset; } - export function AssetDetails({ asset }: AssetDetailsProps) { const [tab, setTab] = useState('file') const [propFilter, setPropFilter] = useState("") diff --git a/src/assets/components/model/model-detail-pane/ModelDetailPane.tsx b/src/assets/components/model/model-detail-pane/ModelDetailPane.tsx index 2548ff3..a67c3e5 100644 --- a/src/assets/components/model/model-detail-pane/ModelDetailPane.tsx +++ b/src/assets/components/model/model-detail-pane/ModelDetailPane.tsx @@ -1,12 +1,12 @@ import * as THREE from 'three' import { Canvas, useLoader, useThree } from '@react-three/fiber' import { STLLoader } from 'three/examples/jsm/loaders/STLLoader.js'; -import { Suspense, useContext, useLayoutEffect, useRef, useState } from "react"; +import { Suspense, useLayoutEffect, useRef, useState } from "react"; import { Asset } from "../../../entities/Assets.ts"; import { Center, GizmoHelper, GizmoViewport, Grid, Html, OrbitControls, useProgress } from '@react-three/drei' import { useElementSize } from "@mantine/hooks"; -import { Alert, lighten } from "@mantine/core"; -import { SettingsContext } from '@/core/settings/settingsContext.ts'; +import { Alert } from "@mantine/core"; +import { BACKEND_HTTP_URL_ROOT } from '@/core/utils/constants.ts'; type ModelProps = { @@ -16,8 +16,7 @@ type ModelProps = { } function Model({ color, model, projectUuid }: ModelProps) { - const { settings } = useContext(SettingsContext); - const geom = useLoader(STLLoader, `${settings.localBackend}/projects/${projectUuid}/assets/${model.id}/file`); + const geom = useLoader(STLLoader, `${ BACKEND_HTTP_URL_ROOT}/projects/${projectUuid}/assets/${model.id}/file`); const meshRef = useRef(null!) const [active, setActive] = useState(false) @@ -85,8 +84,8 @@ function MoveCamera({ children, models }: { children: JSX.Element[], models: Ass box.getSize(size); const fov = camera.fov * (Math.PI / 180); const fovh = 2 * Math.atan(Math.tan(fov / 2) * camera.aspect); - let dx = size.z / 2 + Math.abs(size.x / 2 / Math.tan(fovh / 2)); - let dy = size.z / 2 + Math.abs(size.y / 2 / Math.tan(fov / 2)); + const dx = size.z / 2 + Math.abs(size.x / 2 / Math.tan(fovh / 2)); + const dy = size.z / 2 + Math.abs(size.y / 2 / Math.tan(fov / 2)); let cameraZ = Math.max(dx, dy); // offset the camera, if desired (to avoid filling the whole canvas) diff --git a/src/assets/components/parts/drop-down-menu/DropDownMenu.tsx b/src/assets/components/parts/drop-down-menu/DropDownMenu.tsx index 81c5d57..8799439 100644 --- a/src/assets/components/parts/drop-down-menu/DropDownMenu.tsx +++ b/src/assets/components/parts/drop-down-menu/DropDownMenu.tsx @@ -1,43 +1,18 @@ -import { SettingsContext } from "@/core/settings/settingsContext"; import { ActionIcon, Menu, rem } from "@mantine/core"; import { IconDotsVertical, IconDownload, IconTrash } from "@tabler/icons-react"; -import useAxios from "axios-hooks"; -import { useContext } from "react"; +import { useDeleteProjectAsset } from "@/apiServices/projects"; type DropDownMenuProps = { - id: string; + assetId: string; projectUuid: string; children?: React.ReactNode; downloadURL?: string - onDelete?: () => void; + canDelete?: boolean; openDetails?: () => void; - toggleLoad?: () => void; } -export function DropDownMenu({ id, projectUuid, children, downloadURL, onDelete, openDetails, toggleLoad }: DropDownMenuProps) { - const { settings } = useContext(SettingsContext); - const [{ }, callDelete] = useAxios( - { - url: `${settings.localBackend}/projects/${projectUuid}/assets/${id}/delete`, - method: 'POST' - }, - { manual: true } - ); - - const handleDelete = () => { - toggleLoad && toggleLoad(); - callDelete() - .then((data) => { - console.log(data); - onDelete && onDelete(); - }).catch((e) => { - console.log(e); - }) - .finally(() => { - console.log('finally') - toggleLoad && toggleLoad(); - }) - } +export function DropDownMenu({ assetId, projectUuid, children, downloadURL, canDelete, openDetails }: DropDownMenuProps) { + const callDelete = useDeleteProjectAsset(); return ( @@ -61,10 +36,10 @@ export function DropDownMenu({ id, projectUuid, children, downloadURL, onDelete, href={downloadURL} leftSection={} >Download} - {onDelete && <> + {canDelete && <> callDelete(projectUuid, assetId)} leftSection={} >Delete} diff --git a/src/assets/components/parts/set-as-main/SetAsMain.tsx b/src/assets/components/parts/set-as-main/SetAsMain.tsx index 30de2db..b706746 100644 --- a/src/assets/components/parts/set-as-main/SetAsMain.tsx +++ b/src/assets/components/parts/set-as-main/SetAsMain.tsx @@ -1,34 +1,18 @@ -import { SettingsContext } from "@/core/settings/settingsContext"; import { Menu, rem } from "@mantine/core"; import { notifications } from "@mantine/notifications"; import { IconHeart } from "@tabler/icons-react"; -import useAxios from "axios-hooks"; -import { useCallback, useContext } from "react"; +import { useSetMainImage } from '@/apiServices/projects'; export type SetAsMainProps = { projectUuid: string; - assetId?: string; + assetId: string; onChange: () => void; } export function SetAsMain({ projectUuid, assetId, onChange }: SetAsMainProps) { - const { settings } = useContext(SettingsContext); - const [{ }, callSetMainImage] = useAxios( - { - url: `${settings.localBackend}/projects/${projectUuid}/image`, - method: 'POST' - }, - { manual: true } - ); - const setMainImage = useCallback(() => { - - callSetMainImage({ - data: { - uuid: projectUuid, - default_image_id: assetId - } - }) - .then(({ data }) => { + const callSetMainImage = useSetMainImage(); + const setMainImage = () => { + callSetMainImage(projectUuid, assetId).then(({ data }) => { console.log(data); notifications.show({ title: 'Great Success!', @@ -40,7 +24,7 @@ export function SetAsMain({ projectUuid, assetId, onChange }: SetAsMainProps) { .catch((e) => { console.log(e) }); - }, [projectUuid]); + }; if (!assetId) return null; diff --git a/src/core/settings/settingsContext.ts b/src/core/settings/settingsContext.ts index cf7a05a..26347f6 100644 --- a/src/core/settings/settingsContext.ts +++ b/src/core/settings/settingsContext.ts @@ -1,15 +1,14 @@ -import React from 'react'; +// import React from 'react'; -export interface Settings { - localBackend: string, - agent?: {} - experimental: ExperimentalFeatures -} -export interface ExperimentalFeatures { - dashboard: boolean -} -interface SettingsProviderType { - settings: Settings, - setExperimental: (mutator: (prev: ExperimentalFeatures) => ExperimentalFeatures) => void, -} -export const SettingsContext = React.createContext({} as SettingsProviderType); \ No newline at end of file +// export interface Settings { +// agent?: Record +// experimental: ExperimentalFeatures +// } +// export interface ExperimentalFeatures { +// dashboard: boolean +// } +// interface SettingsProviderType { +// settings: Settings, +// setExperimental: (mutator: (prev: ExperimentalFeatures) => ExperimentalFeatures) => void, +// } +// export const SettingsContext = React.createContext({} as SettingsProviderType); \ No newline at end of file diff --git a/src/core/settings/settingsProvider.tsx b/src/core/settings/settingsProvider.tsx index 002909b..2b6097e 100644 --- a/src/core/settings/settingsProvider.tsx +++ b/src/core/settings/settingsProvider.tsx @@ -1,43 +1,21 @@ -import { useEffect, useState } from "react"; -import { ExperimentalFeatures, Settings, SettingsContext } from "../settings/settingsContext"; -import useAxios from "axios-hooks"; -import { useLocalStorage } from "@mantine/hooks"; +// import { ExperimentalFeatures, SettingsContext } from "../settings/settingsContext"; +// import { useLocalStorage } from "@mantine/hooks"; +import { useGetSettings } from "@/apiServices/system"; -export function SettingsProvider({ loading, children }) { - const [settings, setSettings] = useState({} as Settings); - const [{ }, getSettings] = useAxios(`/settings.json`, { manual: true }); - const [{ }, getAgentSettings] = useAxios({}, { manual: true }); - const [ready, setReady] = useState(false); - const [experimental, setExperimental] = useLocalStorage({ - key: 'experimental', - defaultValue: { - dashboard: false - } - }) +export function SettingsProvider({ loading, children }: {loading: JSX.Element, children: JSX.Element}) { + const { data: settings} = useGetSettings(); - useEffect(() => { - setSettings(prev => ({ ...prev, experimental })) - }, [experimental]) - - useEffect(() => { - getSettings() - .then(({ data: s }) => { - getAgentSettings({ url: `${s.localBackend}/system/settings` }) - .then(({ data: agent }) => { - setSettings(prev => ({ ...prev, ...s, agent })) - console.log(s); - setReady(true); - }) - }) - .catch((e) => { - console.log(e) - }); - }, []) + // const [experimental, setExperimental] = useLocalStorage({ + // key: 'experimental', + // defaultValue: { + // dashboard: false + // } + // }) return ( - - {ready ? children : loading} - + // + (settings) ? children : loading + // ) } \ No newline at end of file diff --git a/src/core/sse/SSEContext.ts b/src/core/sse/SSEContext.ts index 4349346..24fa2cc 100644 --- a/src/core/sse/SSEContext.ts +++ b/src/core/sse/SSEContext.ts @@ -4,6 +4,7 @@ export type Subscription = { subscriberId: string, provider: string, event: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any callback: (data: any) => void } @@ -11,8 +12,8 @@ interface SSEContextType { connected: boolean, loading: boolean, error: Error | null, - subscribe: (Subscription: Subscription) => Promise, - unsubscribe(subscriberId: string): void, + subscribe: ((Subscription: Subscription) => Promise) | undefined, + unsubscribe: ((subscriberId: string) => void) | undefined, } export const SSEContext = createContext({} as SSEContextType) diff --git a/src/core/sse/SSEProvider.tsx b/src/core/sse/SSEProvider.tsx index 27bdc57..ca061fe 100644 --- a/src/core/sse/SSEProvider.tsx +++ b/src/core/sse/SSEProvider.tsx @@ -1,11 +1,9 @@ -import { useContext, useEffect, useMemo, useState } from "react"; -import { SettingsContext } from "../settings/settingsContext"; +import { useEffect, useMemo, useState } from "react"; import { SSEContext } from "./SSEContext"; import { SubscriptionManager, createSubsManager } from "./SubscriptionManager"; +import { BACKEND_HTTP_URL_ROOT } from "../utils/constants"; -export function SSEProvider({ children }) { - const { settings } = useContext(SettingsContext); - +export function SSEProvider({ children }: { children: JSX.Element}) { const [subManager, setSubManager] = useState() const [loading, setLoading] = useState(false); @@ -15,11 +13,11 @@ export function SSEProvider({ children }) { useEffect(() => { - if (settings.localBackend) { + if (BACKEND_HTTP_URL_ROOT) { setLoading(true); setConnected(false); setError(null); - const subManager = createSubsManager(settings.localBackend) + const subManager = createSubsManager(BACKEND_HTTP_URL_ROOT) setSubManager(subManager); subManager.onConnect(() => { setLoading(false); @@ -37,9 +35,7 @@ export function SSEProvider({ children }) { console.log('qweqew') subManager?.close(); } - }, [settings.localBackend]) - - + }, [subManager]) return ( ({ connected, loading, error, subscribe: subManager?.subscribe, unsubscribe: subManager?.unsubscribe }), [connected, loading, error, subManager])}> diff --git a/src/main.tsx b/src/main.tsx index 1f3baeb..ef5c5e1 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,5 +1,7 @@ import React from 'react' import ReactDOM from 'react-dom/client' +import { QueryClient, QueryClientProvider} from '@tanstack/react-query'; + import App from './App.tsx' import '@mantine/core/styles/global.css'; import '@mantine/core/styles.css'; @@ -32,11 +34,12 @@ import { routes as tempFilesRoutes } from "./tempfiles/routes.tsx"; import { routes as printersRoutes } from "./printers/routes.tsx"; import { routes as settingsRoutes } from "./settings/routes.tsx"; +const queryClient = new QueryClient(); + const theme = createTheme({ /** Put your mantine theme override here */ }); - const router = createBrowserRouter([ { path: "/", @@ -69,8 +72,10 @@ console.log(router); ReactDOM.createRoot(document.getElementById('root')!).render( - - - + + + + + ) diff --git a/src/printers/components/edit-printer-page/EditPrinterPage.tsx b/src/printers/components/edit-printer-page/EditPrinterPage.tsx index 1041ac4..f19e9f6 100644 --- a/src/printers/components/edit-printer-page/EditPrinterPage.tsx +++ b/src/printers/components/edit-printer-page/EditPrinterPage.tsx @@ -1,6 +1,4 @@ -import { SettingsContext } from "@/core/settings/settingsContext"; import useAxios from "axios-hooks"; -import { useContext } from "react"; import { useParams, useNavigate } from "react-router-dom"; import { PrinterForm } from "../parts/printer-form/PrinterForm"; import { Printer } from "@/printers/entities/Printer"; @@ -9,16 +7,17 @@ import { Container } from "@mantine/core"; export function EditPrinterPage() { const navigate = useNavigate(); - const { settings } = useContext(SettingsContext); const { id } = useParams(); - const [{ data, loading, error }] = useAxios( - `${settings.localBackend}/printers/${id}` - ); + const [{ + data, + // loading, + // error, + }] = useAxios(`/printers/${id}`); return (<>
- { navigate("/printers") }} /> diff --git a/src/printers/components/parts/printer-form/PrinterForm.tsx b/src/printers/components/parts/printer-form/PrinterForm.tsx index 89ea2f3..2946c56 100644 --- a/src/printers/components/parts/printer-form/PrinterForm.tsx +++ b/src/printers/components/parts/printer-form/PrinterForm.tsx @@ -1,19 +1,21 @@ -import { SettingsContext } from "@/core/settings/settingsContext"; import { Printer, printerTypes } from "@/printers/entities/Printer"; import { ActionIcon, Button, Group, Input, Select, TextInput } from "@mantine/core"; import { hasLength, isNotEmpty, useForm } from "@mantine/form"; import { notifications } from "@mantine/notifications"; import { IconPlugConnected } from "@tabler/icons-react"; -import useAxios from "axios-hooks"; -import { useContext, useEffect } from "react"; +import { useState } from 'react'; +import { + usePostSavePrinter, + usePostTestPrinters, +} from '@/apiServices/printers'; type PrinterFormProps = { printer?: Printer + // eslint-disable-next-line @typescript-eslint/no-explicit-any onPrinterChange: (p: any) => void } export function PrinterForm({ printer, onPrinterChange }: PrinterFormProps) { - const { settings } = useContext(SettingsContext); const form = useForm({ initialValues: { name: '', @@ -27,21 +29,16 @@ export function PrinterForm({ printer, onPrinterChange }: PrinterFormProps) { address: hasLength({ min: 8 }, "You must insert an address (with http://)") }, }); - const [{ loading }, executeSave] = useAxios({ method: 'POST' }, { manual: true }) - const [{ loading: cLoading }, executTest] = useAxios({ method: 'POST', url: `${settings.localBackend}/printers/test` }, { manual: true }) - useEffect(() => { - if (!printer) return; - form.setValues(printer) - }, [printer]) + const [isSaving, setIsSaving] = useState(false); + const [isConnecting, setIsConnecting] = useState(false); + const executeTest = usePostTestPrinters(); + const executeSave = usePostSavePrinter(); + const onSave = () => { - const url = `${settings.localBackend}/printers${printer?.uuid ? '/' + printer.uuid : ''}` - executeSave({ - url, - data: { - ...form.values, - } - }) + setIsSaving(true); + executeSave(form.values, printer?.uuid) .then(({ data }) => { + setIsSaving(false); onPrinterChange(data) notifications.show({ title: 'Great Success!', @@ -50,6 +47,7 @@ export function PrinterForm({ printer, onPrinterChange }: PrinterFormProps) { }) }) .catch((e) => { + setIsSaving(false); console.log(e) }); }; @@ -58,13 +56,16 @@ export function PrinterForm({ printer, onPrinterChange }: PrinterFormProps) { if (form.values.address != '' && form.values.type != '') { const tyype = printerTypes.get(form.values.type) if (!tyype) return; - executTest({ data: form.values }) + setIsConnecting(true); + executeTest(form.values) .then(({ data }) => { + setIsConnecting(false); form.setFieldValue('version', data.version) form.setFieldValue('state', data.state) form.setFieldValue('status', data.status) }) .catch((e) => { + setIsConnecting(true); console.log(e) }); } @@ -98,7 +99,7 @@ export function PrinterForm({ printer, onPrinterChange }: PrinterFormProps) { mb="sm" {...form.getInputProps('address')} rightSection={ - + } @@ -123,7 +124,7 @@ export function PrinterForm({ printer, onPrinterChange }: PrinterFormProps) { {...form.getInputProps('state')} />} - + ) diff --git a/src/printers/components/parts/sent-to-printer-btn/SendToPrinterBtn.tsx b/src/printers/components/parts/sent-to-printer-btn/SendToPrinterBtn.tsx index 46122aa..00e7ef2 100644 --- a/src/printers/components/parts/sent-to-printer-btn/SendToPrinterBtn.tsx +++ b/src/printers/components/parts/sent-to-printer-btn/SendToPrinterBtn.tsx @@ -1,30 +1,22 @@ -import { SettingsContext } from "@/core/settings/settingsContext"; import { IconPrinter } from "@tabler/icons-react"; import { Printer } from "@/printers/entities/Printer"; import { ActionIcon, Menu, rem } from "@mantine/core"; -import useAxios from "axios-hooks"; -import { useContext, useEffect, useState } from "react"; +import { useState } from "react"; import { notifications } from "@mantine/notifications"; +import { + useGetPrinters, + useSendToPrinter, +} from '@/apiServices/printers'; -type SentToPrinterBtnProps = { - id: string -} - -export function SendToPrinterBtn({ id }: SentToPrinterBtnProps) { - const { settings } = useContext(SettingsContext); - const [printers, setPrinters] = useState([]) - const [{ data, loading }] = useAxios({ url: `${settings.localBackend}/printers` }) - const [{ loading: sLoading }, executeSendToPrinter] = useAxios({}, { manual: true }) - useEffect(() => { - if (!data) return; - setPrinters(data) - }, [data]) - +export function SendToPrinterBtn({ id }: { id: string }) { + const { data: printers, isLoading } = useGetPrinters(); + const executeSendToPrinter = useSendToPrinter(); + const [isSending, setIsSending] = useState(false); function sentToPrinter(p: Printer) { - executeSendToPrinter({ - url: `${settings.localBackend}/printers/${p.uuid}/send/${id}` - }) + setIsSending(true); + executeSendToPrinter(p.uuid, id) .then(() => { + setIsSending(false); notifications.show({ title: 'Great Success!', message: 'File sent to printer!', @@ -33,6 +25,7 @@ export function SendToPrinterBtn({ id }: SentToPrinterBtnProps) { }) .catch((e) => { console.log(e) + setIsSending(false); }); } @@ -43,12 +36,12 @@ export function SendToPrinterBtn({ id }: SentToPrinterBtnProps) { withinPortal > - + - {printers.map((p, i) => sentToPrinter(p)}>{p.name})} + {printers?.map((p, i) => sentToPrinter(p)}>{p.name})}
) } \ No newline at end of file diff --git a/src/printers/components/printers-page/PrintersPage.tsx b/src/printers/components/printers-page/PrintersPage.tsx index 131ccf0..2ac25ac 100644 --- a/src/printers/components/printers-page/PrintersPage.tsx +++ b/src/printers/components/printers-page/PrintersPage.tsx @@ -1,41 +1,44 @@ -import useAxios from "axios-hooks"; import { AddPrinter } from "./parts/add-printer/AddPrinter"; -import { useContext, useEffect, useRef, useState } from "react"; -import { SettingsContext } from "@/core/settings/settingsContext"; +import { useState } from "react"; import { Anchor, Avatar, Badge, Group, Table, Text, ActionIcon, rem, Menu, Tabs } from "@mantine/core"; -import { Printer, printerTypes } from "@/printers/entities/Printer"; +import { printerTypes } from "@/printers/entities/Printer"; import { IconDots, IconPhoto, IconReportAnalytics, IconSettings, IconTrash } from "@tabler/icons-react"; import { Header } from "@/core/header/Header"; import { notifications } from "@mantine/notifications"; import { Link } from "react-router-dom"; +import { + useGetPrinters, + useDeletePrinter, +} from '@/apiServices/printers'; export function PrintersPage() { - const reload = useRef(Math.floor(1000 + Math.random() * 9000)); const iconStyle = { width: rem(12), height: rem(12) }; - const { settings } = useContext(SettingsContext); - const [printers, setPrinters] = useState([]) - const [{ data, loading: cLoading, error }] = useAxios({ url: `${settings.localBackend}/printers?_=${reload.current}` }) - const [{ loading: dLoading }, executeDelete] = useAxios({ method: 'POST' }, { manual: true }) - useEffect(() => { - setPrinters(data) - }, [data]); + const { data: printers, isLoading } = useGetPrinters(); + const [isDeleting, setIsDeleting] = useState(false); + const executeDelete = useDeletePrinter() + function deletePrinter(i: number): void { + if (!printers) { + return; + } + const printer = printers[i]; - executeDelete({ - url: `${settings.localBackend}/printers/${printer.uuid}/delete` - }) + if (!printer) { + return; + } + setIsDeleting(true); + executeDelete(printer.uuid) .then(() => { notifications.show({ title: 'Great Success!', message: 'Printer deleted!', color: 'indigo', }) - const copy = [...printers] - copy.splice(i, 1) - setPrinters(copy) + setIsDeleting(false); }) .catch((e) => { console.log(e) + setIsDeleting(true); }); } @@ -101,7 +104,7 @@ export function PrintersPage() { withinPortal > - + diff --git a/src/printers/components/widgets/configs/PrinterWidgetConfig.tsx b/src/printers/components/widgets/configs/PrinterWidgetConfig.tsx index e3ab272..0fa60f8 100644 --- a/src/printers/components/widgets/configs/PrinterWidgetConfig.tsx +++ b/src/printers/components/widgets/configs/PrinterWidgetConfig.tsx @@ -1,15 +1,11 @@ -import { SettingsContext } from "@/core/settings/settingsContext"; import { WidgetConfig } from "@/dashboard/entities/WidgetType"; -import { Printer } from "@/printers/entities/Printer"; import { Select } from "@mantine/core"; -import useAxios from "axios-hooks"; -import { useContext, useRef, useState } from "react"; +import { useState } from "react"; +import { useGetPrinters } from '@/apiServices/printers'; export function PrinterWidgetConfig({ config, onChange }: WidgetConfig) { const [cfg, setCfg] = useState(config) - const reload = useRef(Math.floor(1000 + Math.random() * 9000)); - const { settings } = useContext(SettingsContext); - const [{ data, loading, error }] = useAxios({ url: `${settings.localBackend}/printers?_=${reload.current}` }) + const {data} = useGetPrinters(); const proxyOnChange = (v: string | null) => { const c = { ...cfg, printer: v } diff --git a/src/printers/components/widgets/printer-table-widget/PrinterTableWidget.tsx b/src/printers/components/widgets/printer-table-widget/PrinterTableWidget.tsx index 1b0b0a4..0ec96f0 100644 --- a/src/printers/components/widgets/printer-table-widget/PrinterTableWidget.tsx +++ b/src/printers/components/widgets/printer-table-widget/PrinterTableWidget.tsx @@ -1,9 +1,7 @@ import { Widget } from "@/dashboard/entities/WidgetType"; import { Card, Group, Text } from "@mantine/core"; import { useContext, useEffect, useState } from "react"; -import { SettingsContext } from "@/core/settings/settingsContext"; -import { Job, Printer, Thermal } from "@/printers/entities/Printer"; -import useAxios from "axios-hooks"; +import { Job, Thermal } from "@/printers/entities/Printer"; import { PrintProgressBar } from "../parts/print-progress-bar/PrintProgressBar"; import Printer3dNozzleHeatOutlineIcon from "mdi-react/Printer3dNozzleHeatOutlineIcon"; import { IconFile3d, IconPercentage, IconSkateboarding } from "@tabler/icons-react"; @@ -11,18 +9,19 @@ import RadiatorDisabledIcon from "mdi-react/RadiatorDisabledIcon"; import { SSEContext } from "@/core/sse/SSEContext"; import { useCumulativeEvent } from "@/core/sse/useCumulativeEvent"; import { useId } from '@mantine/hooks'; +import { useGetPrinter } from '@/apiServices/printers'; export function PrinterTableWidget(w: Widget) { - const { settings } = useContext(SettingsContext); const subscriberId = useId(); - const [{ data: printer, loading }] = useAxios({ url: `${settings.localBackend}/printers/${w.config.printer}` }) + const { data: printer, isLoading } = useGetPrinter(w.config.printer); + const { connected, subscribe, unsubscribe } = useContext(SSEContext) const [error, setError] = useState(null); const [extruder, setExtruder] = useCumulativeEvent({ temperature: 0 }); const [heaterBed, setHeaterBed] = useCumulativeEvent({ temperature: 0 }); const [job, setJob] = useCumulativeEvent({ progress: 0, fileName: "", message: "" }); useEffect(() => { - if (!connected) return; + if (!connected || !subscribe || !unsubscribe) return; setExtruder({ temperature: 0 }); setHeaterBed({ temperature: 0 }); const subscription = { @@ -49,7 +48,7 @@ export function PrinterTableWidget(w: Widget) { } }, [w.config.printer, connected]) - if (loading) return <>Loading...; + if (isLoading) return <>Loading...; return ( diff --git a/src/printers/components/widgets/printer-widget/PrinterWidget.tsx b/src/printers/components/widgets/printer-widget/PrinterWidget.tsx index 8edda20..0f70c41 100644 --- a/src/printers/components/widgets/printer-widget/PrinterWidget.tsx +++ b/src/printers/components/widgets/printer-widget/PrinterWidget.tsx @@ -1,20 +1,17 @@ import { Widget } from "@/dashboard/entities/WidgetType"; import { Card, Image, Group, Badge, Anchor, Center } from "@mantine/core"; import classes from './PrinterWidget.module.css'; -import { useContext } from "react"; -import { SettingsContext } from "@/core/settings/settingsContext"; -import { Printer } from "@/printers/entities/Printer"; -import useAxios from "axios-hooks"; import { ExtruderTemp } from "../parts/heater-temp/ExtruderTemp"; import { BedTemp } from "../parts/bed-temp/BedTemp"; import { PrintProgress } from "../parts/print-progress/PrintProgress"; import { PrintProgressBar } from "../parts/print-progress-bar/PrintProgressBar"; +import { BACKEND_HTTP_URL_ROOT } from "@/core/utils/constants"; +import { useGetPrinter } from '@/apiServices/printers'; export function PrinterWidget(w: Widget) { - const { settings } = useContext(SettingsContext); - const [{ data: printer, loading }] = useAxios({ url: `${settings.localBackend}/printers/${w.config.printer}` }) + const { data: printer, isLoading } = useGetPrinter(w.config.printer); const state = {}; - if (loading) return <>Loading...; + if (isLoading) return <>Loading...; return ( @@ -23,7 +20,7 @@ export function PrinterWidget(w: Widget) { h={300} w="auto" fit="cover" - src={`${settings.localBackend}/printers/${w.config.printer}/stream`} /> : + src={`${BACKEND_HTTP_URL_ROOT}/printers/${w.config.printer}/stream`} /> : } diff --git a/src/projects/components/parts/project-form/ProjectForm.tsx b/src/projects/components/parts/project-form/ProjectForm.tsx index db80778..aa505ed 100644 --- a/src/projects/components/parts/project-form/ProjectForm.tsx +++ b/src/projects/components/parts/project-form/ProjectForm.tsx @@ -1,9 +1,7 @@ import { Button, Group, rem, TagsInput, Text, Textarea, TextInput } from "@mantine/core"; import { useForm } from "@mantine/form"; import { Project } from "../../../entities/Project.ts"; -import useAxios from "axios-hooks"; -import { useContext, useState } from "react"; -import { SettingsContext } from "@/core/settings/settingsContext.ts"; +import { useState } from "react"; import { notifications } from '@mantine/notifications'; import { Dropzone } from "@mantine/dropzone"; import { IconPhoto, IconUpload, IconX } from "@tabler/icons-react"; @@ -13,19 +11,16 @@ type ProjectFormProps = { onProjectChange: (p: Project) => void; withUpload?: boolean; }; +import { usePostProject } from '@/apiServices/projects.ts'; export function ProjectForm({ project, onProjectChange, withUpload }: ProjectFormProps) { - const { settings } = useContext(SettingsContext); const [files, setFiles] = useState([]); - const [{ data, loading, error }, executeSave] = useAxios( - { - method: 'POST' - }, - { manual: true } - ) + const executeSave = usePostProject(); + const [isLoading, setIsLoading] = useState(false); + const form = useForm({ initialValues: { - tags: [], + // tags: [], ...project, }, validate: { @@ -42,11 +37,10 @@ export function ProjectForm({ project, onProjectChange, withUpload }: ProjectFor if (files.length > 0) { files.forEach((file) => formData.append("files", file)); } - executeSave({ - url: `${settings.localBackend}/projects${project.uuid ? "/" + project.uuid : ''}`, - data: formData - }) + setIsLoading(true); + executeSave(project.uuid, formData) .then(({ data }) => { + setIsLoading(false); onProjectChange(data) notifications.show({ title: 'Great Success!', @@ -55,6 +49,7 @@ export function ProjectForm({ project, onProjectChange, withUpload }: ProjectFor }) }) .catch((e) => { + setIsLoading(false); console.log(e) }); }; @@ -121,7 +116,7 @@ export function ProjectForm({ project, onProjectChange, withUpload }: ProjectFor { console.log(name); form.setFieldValue('default_image_name', name) }} /> } - + ); diff --git a/src/projects/components/project-page/ProjectPage.tsx b/src/projects/components/project-page/ProjectPage.tsx index a6dba2c..feab95c 100644 --- a/src/projects/components/project-page/ProjectPage.tsx +++ b/src/projects/components/project-page/ProjectPage.tsx @@ -1,20 +1,17 @@ import { useNavigate, useParams } from "react-router-dom"; import useAxios from "axios-hooks"; import { Project } from "../../entities/Project.ts"; -import { useContext } from "react"; import { ProjectPageBody } from "./parts/project-page-body/ProjectPageBody.tsx"; import { Header } from "@/core/header/Header.tsx"; -import { SettingsContext } from "@/core/settings/settingsContext.ts"; import { Refresher } from "./parts/refresher/Refresher.tsx"; - +import { BACKEND_HTTP_URL_ROOT } from "@/core/utils/constants.ts"; export function ProjectPage() { const navigate = useNavigate(); - const { settings } = useContext(SettingsContext); const { id } = useParams(); const [{ data: project, loading, error }, refetch] = useAxios( - `${settings.localBackend}/projects/${id}` + `projects/${id}` ); return ( <> @@ -24,7 +21,7 @@ export function ProjectPage() { description={project?.description} tags={project?.tags} link={project?.external_link} - imagePath={`${settings.localBackend}/projects/${project?.uuid}/assets/${project?.default_image_id}/file`} + imagePath={`${BACKEND_HTTP_URL_ROOT}/projects/${project?.uuid}/assets/${project?.default_image_id}/file`} onTagClick={(t) => navigate(`/projects/list?filter=${JSON.stringify({ tags: [t.value] })}`)} /> {error &&

Error!

} diff --git a/src/projects/components/project-page/parts/project-page-body/ProjectPageBody.tsx b/src/projects/components/project-page/parts/project-page-body/ProjectPageBody.tsx index 3394702..7ec0273 100644 --- a/src/projects/components/project-page/parts/project-page-body/ProjectPageBody.tsx +++ b/src/projects/components/project-page/parts/project-page-body/ProjectPageBody.tsx @@ -30,12 +30,12 @@ export function ProjectPageBody({ projectUuid, project, onProjectChange }: Proje const [selectedModels, selectedModelsHandlers] = useListState([]); const [selectedAsset, setSelectedAsset] = useState(); const [typeFilter, setTypeFilter] = useState(searchParams.get('tab')); - const [{ data: assetTypes, loading: tLoading, error: tError }] = useAxios( - `${settings.localBackend}/assettypes` - ); - const [{ data, loading, error }, refetch] = useAxios( - `${settings.localBackend}/projects/${projectUuid}/assets` - ); + const [{ + data: assetTypes, + // loading: tLoading, + // error: tError, + }] = useAxios('assettypes'); + const [{ data, loading, error }, refetch] = useAxios(`/projects/${projectUuid}/assets`); useEffect(() => { if (data) { setAssets(data); diff --git a/src/projects/components/project-page/parts/project-page-body/parts/add-asset/AddAsset.tsx b/src/projects/components/project-page/parts/project-page-body/parts/add-asset/AddAsset.tsx index c102757..cd15b2f 100644 --- a/src/projects/components/project-page/parts/project-page-body/parts/add-asset/AddAsset.tsx +++ b/src/projects/components/project-page/parts/project-page-body/parts/add-asset/AddAsset.tsx @@ -1,37 +1,29 @@ import { Dropzone } from "@mantine/dropzone"; import { Container, Group, rem, Text } from "@mantine/core"; import { IconPhoto, IconUpload, IconX } from "@tabler/icons-react"; -import useAxios from "axios-hooks"; -import { useContext } from "react"; -import { SettingsContext } from "@/core/settings/settingsContext"; +import { useState } from 'react'; import { notifications } from "@mantine/notifications"; - +import { usePostProjectAsset } from '@/apiServices/projects.ts'; type AddAssetProps = { projectUuid: string } export function AddAsset({ projectUuid }: AddAssetProps) { - const { settings } = useContext(SettingsContext); - const [{ loading }, executeSave] = useAxios( - { - url: `${settings.localBackend}/projects/${projectUuid}/assets`, - method: 'POST' - }, - { - manual: true, - autoCancel: false - } - ) + const [isSaving, setIsSaving] = useState(false); + const executeSave = usePostProjectAsset(); + const onDrop = (files: File[]) => { console.log(files); for (const i in files) { const formData = new FormData(); formData.append("project_uuid", projectUuid); formData.append("files", files[i]); - executeSave({ data: formData }) + setIsSaving(true); + executeSave(projectUuid, { data: formData }) .then(({ data }) => { console.log(data); + setIsSaving(false); notifications.show({ title: 'Great Success!', message: `${data.name} as added to your project!`, @@ -39,6 +31,7 @@ export function AddAsset({ projectUuid }: AddAssetProps) { }) }) .catch((e) => { + setIsSaving(false); console.log(e) }); } @@ -46,7 +39,7 @@ export function AddAsset({ projectUuid }: AddAssetProps) { return ( <> - + void; } -export function ProjectOperations({ project, onProjectChange }: ProjectOperationsProps) { - const { settings } = useContext(SettingsContext); - +export function ProjectOperations({ project }: ProjectOperationsProps) { + const [isMoving, setIsLoading] = useState(false); const [path, setPath] = useState(project.path); - const [{ loading }, moveProject] = useAxios({ - method: 'post', - }, { manual: true }) - const [{ data: paths, loading: lPaths, error: ePaths }] = useAxios( - { - url: `${settings.localBackend}/system/paths` - } - ) + const moveProject = useMoveProject(); + + const { + data: paths, + isLoading: isLoadingPaths, + // error: ePaths + } = useGetPaths(); const onMoveHandler = () => { - moveProject({ - url: `${settings.localBackend}/projects/${project.uuid}/move`, - data: { - uuid: project.uuid, - path: path - } - }).then(({ data }) => { + setIsLoading(true); + moveProject(project.uuid, path).then(({ data }) => { console.log(data); - setPath(data.path) + setPath(data.path); + setIsLoading(false); notifications.show({ title: 'Great Success!', message: 'Project moved', @@ -42,6 +36,7 @@ export function ProjectOperations({ project, onProjectChange }: ProjectOperation }) }) .catch((e) => { + setIsLoading(false); console.log(e) }); } @@ -51,9 +46,9 @@ export function ProjectOperations({ project, onProjectChange }: ProjectOperation data={paths} value={path} onChange={setPath} - disabled={lPaths} + disabled={isLoadingPaths} rightSection={ - + } diff --git a/src/projects/components/project-page/parts/project-page-body/parts/edit-project/parts/project-operations/delete-btn/DeleteBtn.tsx b/src/projects/components/project-page/parts/project-page-body/parts/edit-project/parts/project-operations/delete-btn/DeleteBtn.tsx index 1205658..9242115 100644 --- a/src/projects/components/project-page/parts/project-page-body/parts/edit-project/parts/project-operations/delete-btn/DeleteBtn.tsx +++ b/src/projects/components/project-page/parts/project-page-body/parts/edit-project/parts/project-operations/delete-btn/DeleteBtn.tsx @@ -1,10 +1,9 @@ import { ConfirmDialog } from "@/core/dialogs/confirm-dialog/ConfirmDialog"; -import { SettingsContext } from "@/core/settings/settingsContext"; import { Button } from "@mantine/core"; import { notifications } from "@mantine/notifications"; -import useAxios from "axios-hooks"; -import { useCallback, useContext, useState } from "react"; +import { useCallback, useState } from "react"; import { useNavigate } from "react-router-dom"; +import { useDeleteProject } from "@/apiServices/projects"; interface DeleteBtnProps { projectUuid: string; @@ -12,19 +11,17 @@ interface DeleteBtnProps { export function DeleteBtn({ projectUuid }: DeleteBtnProps) { const navigate = useNavigate(); - const { settings } = useContext(SettingsContext); const [isOpen, setIsOpen] = useState(false); - const [{ loading }, doDelete] = useAxios( - { - url: `${settings.localBackend}/projects/${projectUuid}/delete`, - method: 'post', - }, { manual: true }) + const [isDeleting, setIsDeleting] = useState(false); + const doDelete = useDeleteProject(); const onOk = useCallback(() => { setIsOpen(false); - doDelete() + setIsDeleting(true); + doDelete(projectUuid) .then(({ data }) => { console.log(data); + setIsDeleting(false); notifications.show({ title: 'Great Success!', message: 'Project deleted', @@ -34,12 +31,13 @@ export function DeleteBtn({ projectUuid }: DeleteBtnProps) { navigate(`/projects?tab=list`) }) .catch((e) => { + setIsDeleting(false); console.log(e) }); - }, [doDelete]) + }, [doDelete, navigate, projectUuid]) return (<> - + setIsOpen(false)} /> ) diff --git a/src/projects/components/project-page/parts/project-page-body/parts/edit-project/parts/project-operations/discover-btn/DiscoverBtn.tsx b/src/projects/components/project-page/parts/project-page-body/parts/edit-project/parts/project-operations/discover-btn/DiscoverBtn.tsx index a7641f3..849ba5f 100644 --- a/src/projects/components/project-page/parts/project-page-body/parts/edit-project/parts/project-operations/discover-btn/DiscoverBtn.tsx +++ b/src/projects/components/project-page/parts/project-page-body/parts/edit-project/parts/project-operations/discover-btn/DiscoverBtn.tsx @@ -1,41 +1,34 @@ import { ConfirmDialog } from "@/core/dialogs/confirm-dialog/ConfirmDialog"; -import { SettingsContext } from "@/core/settings/settingsContext"; import { Button } from "@mantine/core"; import { notifications } from "@mantine/notifications"; -import useAxios from "axios-hooks"; -import { useCallback, useContext, useState } from "react"; +import { useCallback, useState } from "react"; +import { useDiscoverProject } from "@/apiServices/projects"; interface DiscoverBtnProps { projectUuid: string; } export function DiscoverBtn({ projectUuid }: DiscoverBtnProps) { - const { settings } = useContext(SettingsContext); const [isOpen, setIsOpen] = useState(false); - const [{ loading }, doDiscovery] = useAxios( - { - url: `${settings.localBackend}/projects/${projectUuid}/discover` - }, { manual: true }) + const [isEnabled, setIsEnabled] = useState(false); + const {data, isLoading} = useDiscoverProject(projectUuid, isEnabled) + + if (data) { + notifications.show({ + title: 'Great Success!', + message: 'Project discovery started', + color: 'indigo', + }) + } const onOk = useCallback(() => { setIsOpen(false); - doDiscovery() - .then(({ data }) => { - console.log(data); - notifications.show({ - title: 'Great Success!', - message: 'Project discovery started', - color: 'indigo', - }) - }) - .catch((e) => { - console.log(e) - }); - }, [doDiscovery]) + setIsEnabled(true); + }, []) return (<> - - setIsOpen(false)} /> - - ) + + setIsOpen(false)} /> + + ) } \ No newline at end of file diff --git a/src/projects/components/projects-page/parts/import-project/ImportProject.tsx b/src/projects/components/projects-page/parts/import-project/ImportProject.tsx index 9f386d8..27ded8b 100644 --- a/src/projects/components/projects-page/parts/import-project/ImportProject.tsx +++ b/src/projects/components/projects-page/parts/import-project/ImportProject.tsx @@ -1,15 +1,12 @@ import { Anchor, Button, Container, Group, Text, Textarea } from "@mantine/core"; import { useForm } from "@mantine/form"; -import useAxios from "axios-hooks"; -import { useContext } from "react"; -import { SettingsContext } from "@/core/settings/settingsContext"; +import { useDownloader } from '@/apiServices/downloader'; +import { useState } from 'react'; export function ImportProject() { - const { settings } = useContext(SettingsContext); - const [{ loading, error }, fetchProject] = useAxios({ - url: `${settings.localBackend}/downloader/fetch`, - method: 'post', - }, { manual: true }) + const fetchProject = useDownloader(); + const [isDownloading, setIsDownloading] = useState(false); + const form = useForm({ initialValues: { urls: '', @@ -20,11 +17,13 @@ export function ImportProject() { }); const onFetch = () => { const urls = form.values.urls.split('\n'); + setIsDownloading(true); fetchProject({ data: { url: urls.join(',') } }).then(({ data }) => { + setIsDownloading(false); console.log(data); }) } @@ -41,7 +40,7 @@ export function ImportProject() { /> Check out MMP Companion to import from more platforms. - + diff --git a/src/projects/components/projects-page/parts/projects-list/ProjectsList.tsx b/src/projects/components/projects-page/parts/projects-list/ProjectsList.tsx index 7f0f294..2979db3 100644 --- a/src/projects/components/projects-page/parts/projects-list/ProjectsList.tsx +++ b/src/projects/components/projects-page/parts/projects-list/ProjectsList.tsx @@ -3,22 +3,20 @@ import { Filter } from "./parts/project-filter-card/ProjectFilterCard.tsx"; import { ProjectCard } from "./parts/project-card/ProjectCard.tsx"; import { useSearchParams } from "react-router-dom"; import useAxios from "axios-hooks"; -import { useContext, useEffect, useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { Project } from "@/projects/entities/Project.ts"; -import { SettingsContext } from "@/core/settings/settingsContext.ts"; import { ProjectFilter } from "./parts/project-filter/ProjectFilter.tsx"; export function ProjectsList() { const [searchParams, setSearchParams] = useSearchParams(); const reload = useRef(Math.floor(1000 + Math.random() * 9000)); - const { settings } = useContext(SettingsContext); const [page, setPage] = useState(1); const [perPage, setPerPage] = useState('20') const [projects, setProjects] = useState([]) const [filter, setFilter] = useState({ name: '', tags: [] }) const size = rem('280px'); const [{ data, loading, error }] = useAxios( - `${settings.localBackend}/projects?page=${page - 1}&size=${perPage}${filter.name ? '&name=' + filter.name : ''}${filter.tags.length > 0 ? '&tags=' + filter.tags?.join(",") : ''}&_=${reload.current}` + `/projects?page=${page - 1}&size=${perPage}${filter.name ? '&name=' + filter.name : ''}${filter.tags.length > 0 ? '&tags=' + filter.tags?.join(",") : ''}&_=${reload.current}` ); useEffect(() => { if (!data?.items) return; diff --git a/src/projects/components/projects-page/parts/projects-list/parts/project-card/ProjectCard.tsx b/src/projects/components/projects-page/parts/projects-list/parts/project-card/ProjectCard.tsx index 40d3281..cad7c1a 100644 --- a/src/projects/components/projects-page/parts/projects-list/parts/project-card/ProjectCard.tsx +++ b/src/projects/components/projects-page/parts/projects-list/parts/project-card/ProjectCard.tsx @@ -2,16 +2,13 @@ import { Card, Text, Group, rem } from '@mantine/core'; import classes from './ProjectCard.module.css'; import { Project } from "@/projects/entities/Project.ts"; import { Link } from "react-router-dom"; -import { SettingsContext } from '@/core/settings/settingsContext'; -import { useContext } from 'react'; +import { BACKEND_HTTP_URL_ROOT } from '@/core/utils/constants'; type ProjectCardProps = { project: Project, } export function ProjectCard({ project }: ProjectCardProps) { - const { settings } = useContext(SettingsContext); - const size = rem('280px'); return ( } diff --git a/src/projects/components/projects-page/parts/projects-list/parts/project-filter-card/ProjectFilterCard.tsx b/src/projects/components/projects-page/parts/projects-list/parts/project-filter-card/ProjectFilterCard.tsx index 21d5fae..d0ed083 100644 --- a/src/projects/components/projects-page/parts/projects-list/parts/project-filter-card/ProjectFilterCard.tsx +++ b/src/projects/components/projects-page/parts/projects-list/parts/project-filter-card/ProjectFilterCard.tsx @@ -1,10 +1,8 @@ import { Button, Card, Group, LoadingOverlay, TagsInput, Text, TextInput } from '@mantine/core'; import classes from './ProjectFilterCard.module.css'; -import { useContext, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { Tag } from "@/projects/entities/Project.ts"; import useAxios from 'axios-hooks'; -import { SettingsContext } from '@/core/settings/settingsContext'; - export type Filter = { name: string; @@ -16,12 +14,13 @@ type ProjectFilterCardProps = { }; export function ProjectFilterCard({ onChange }: ProjectFilterCardProps) { - const { settings } = useContext(SettingsContext); const [filter, setFilter] = useState({ name: '', tags: [] }) const [tags, setTags] = useState([]); - const [{ data, loading, error }] = useAxios( - `${settings.localBackend}/tags` - ); + const [{ + data, + loading, + // error, + }] = useAxios('tags'); useEffect(() => { if (!data) return; diff --git a/src/projects/components/projects-page/parts/projects-list/parts/project-filter/ProjectFilter.tsx b/src/projects/components/projects-page/parts/projects-list/parts/project-filter/ProjectFilter.tsx index 32a0179..4b17331 100644 --- a/src/projects/components/projects-page/parts/projects-list/parts/project-filter/ProjectFilter.tsx +++ b/src/projects/components/projects-page/parts/projects-list/parts/project-filter/ProjectFilter.tsx @@ -4,7 +4,7 @@ import { ActionIcon, Group, TagsInput, TextInput, Transition, rem } from "@manti import { useDisclosure } from "@mantine/hooks"; import { IconFilter, IconSearch, IconX } from "@tabler/icons-react"; import useAxios from "axios-hooks"; -import { useContext, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; export type Filter = { @@ -18,12 +18,13 @@ type ProjectFilterProps = { }; export function ProjectFilter({ value, onChange }: ProjectFilterProps) { - const { settings } = useContext(SettingsContext); const [filter, setFilter] = useState(value) const [tags, setTags] = useState([]); - const [{ data, loading, error }] = useAxios( - `${settings.localBackend}/tags` - ); + const [{ + data, + loading, + // error, + }] = useAxios('tags'); useEffect(() => { if (!data) return; diff --git a/src/settings/components/settings-page/parts/server-operations/ServerOperations.tsx b/src/settings/components/settings-page/parts/server-operations/ServerOperations.tsx index 1cc6692..0f0e1e9 100644 --- a/src/settings/components/settings-page/parts/server-operations/ServerOperations.tsx +++ b/src/settings/components/settings-page/parts/server-operations/ServerOperations.tsx @@ -1,36 +1,29 @@ import { ConfirmDialog } from "@/core/dialogs/confirm-dialog/ConfirmDialog"; -import { SettingsContext } from "@/core/settings/settingsContext"; import { Button, Fieldset } from "@mantine/core"; import { notifications } from "@mantine/notifications"; -import useAxios from "axios-hooks"; -import { useContext, useState, useCallback } from "react"; +import { useState, useCallback } from "react"; +import { useGetDiscovery } from "@/apiServices/system"; export function ServerOperations() { - const { settings } = useContext(SettingsContext); const [isOpen, setIsOpen] = useState(false); - const [{ loading }, doDiscovery] = useAxios( - { - url: `${settings.localBackend}/system/discovery` - }, { manual: true }) + const [isEnabled, setIsEnabled] = useState(false); + const { data, isLoading } = useGetDiscovery(isEnabled); + + if (data) { + notifications.show({ + title: 'Great Success!', + message: 'Global discovery started', + color: 'indigo', + }) + } const onOk = useCallback(() => { setIsOpen(false); - doDiscovery() - .then(({ data }) => { - console.log(data); - notifications.show({ - title: 'Great Success!', - message: 'Global discovery started', - color: 'indigo', - }) - }) - .catch((e) => { - console.log(e) - }); - }, [doDiscovery]) + setIsEnabled(true); + }, []) return (
- + setIsOpen(false)} />
) diff --git a/src/settings/components/settings-page/parts/settings-form/SettingsForm.tsx b/src/settings/components/settings-page/parts/settings-form/SettingsForm.tsx index 190bda0..4623892 100644 --- a/src/settings/components/settings-page/parts/settings-form/SettingsForm.tsx +++ b/src/settings/components/settings-page/parts/settings-form/SettingsForm.tsx @@ -1,6 +1,4 @@ -import useAxios from "axios-hooks"; -import { useContext, useEffect, useRef } from "react"; -import { SettingsContext } from "@/core/settings/settingsContext"; +import { useEffect, useState } from "react"; import { Button, Container, Fieldset, Group } from "@mantine/core"; import { FormProvider, useForm } from "./context"; import { Core } from "./parts/Core"; @@ -11,16 +9,12 @@ import { Integrations } from "./parts/Integrations"; import { Form } from "react-router-dom"; import { AgentSettings } from "@/settings/entities/AgentSettings"; import { notifications } from "@mantine/notifications"; +import { useGetSettings, usePostSettings } from "@/apiServices/system"; export function SettingsForm() { - const reload = useRef(Math.floor(1000 + Math.random() * 9000)); - const { settings } = useContext(SettingsContext); - const [{ data, loading: cLoading, error }] = useAxios({ url: `${settings.localBackend}/system/settings?_=${reload.current}` }) - - const [{ loading: sLoading }, executeSave] = useAxios({ - url: `${settings.localBackend}/system/settings`, - method: 'POST' - }, { manual: true }) + const { data, isLoading } = useGetSettings(); + const executeSave = usePostSettings(); + const [isSaving, setIsSaving] = useState(false); const form = useForm({ initialValues: { @@ -56,13 +50,15 @@ export function SettingsForm() { form.setInitialValues(data); form.setValues(data); } - }, [data]) + }, [data, form]) const onSave = (settings: AgentSettings) => { + setIsSaving(true); executeSave({ data: settings }) - .then(({ data }) => { + .then(() => { + setIsSaving(false); notifications.show({ title: 'Great Success!', message: 'Settings updated', @@ -70,6 +66,7 @@ export function SettingsForm() { }) }) .catch((e) => { + setIsSaving(false); console.log(e) }); }; @@ -85,7 +82,7 @@ export function SettingsForm() {
- +
diff --git a/src/tempfiles/components/temp-files/TempFiles.tsx b/src/tempfiles/components/temp-files/TempFiles.tsx index 6585bfe..7f92104 100644 --- a/src/tempfiles/components/temp-files/TempFiles.tsx +++ b/src/tempfiles/components/temp-files/TempFiles.tsx @@ -1,54 +1,52 @@ -import { SettingsContext } from "@/core/settings/settingsContext"; -import { TempFile } from "@/tempfiles/entities/TempFile"; +import { Project } from '@/projects/entities/Project'; import { IconTrash, IconFileArrowRight } from "@tabler/icons-react"; import { ActionIcon, Table, Group, Center, Skeleton } from "@mantine/core"; -import useAxios from "axios-hooks"; -import { useContext, useEffect, useRef, useState } from "react"; +import { useState } from "react"; import { ProjectSelect } from "./parts/project-select/ProjectSelect"; -import { Project } from "@/projects/entities/Project"; import { Header } from "@/core/header/Header"; import { notifications } from "@mantine/notifications"; +import { + usePostTempFile, + useDeleteTempFile, + useGetTempFiles +} from '@/apiServices/tempFiles'; +import { + useGetProjectsList +} from '@/apiServices/projects'; export function TempFiles() { - const reload = useRef(Math.floor(1000 + Math.random() * 9000)); - const { settings } = useContext(SettingsContext); - const [tempFiles, setTempFiles] = useState([]); const [actionLoading, setActionLoading] = useState(false); - const [{ }, callSendToProject] = useAxios({ url: `${settings.localBackend}/tempfiles/xxx`, method: 'post' }, { manual: true }) - const [{ }, callDeleteTemp] = useAxios({ url: `${settings.localBackend}/tempfiles/xxx/delete`, method: 'post' }, { manual: true }) - const [{ data, loading, error }] = useAxios( - `${settings.localBackend}/tempfiles?_=${reload.current}` - ); - useEffect(() => { - if (!data) return; - setTempFiles(data); - }, [data]); + const callSendToProject = usePostTempFile(); + const callDeleteTemp = useDeleteTempFile(); - const [{ data: projects, loading: pLoading, error: pError }] = useAxios( - `${settings.localBackend}/projects/list?_=${reload.current}` - ); + const { + data, + isLoading, + // error, + } = useGetTempFiles(); + // useEffect(() => { + // if (!data) return; + // setTempFiles(data); + // }, [data]); + const { data: projects, isLoading: pLoading } = useGetProjectsList(); const setProjectUUID = (i: number, p: Project) => { - const copy = [...tempFiles] - copy[i].project_uuid = p.uuid - setTempFiles(copy) + if (!data || !data[i]) { + return; + } + data[i].project_uuid = p.uuid; } const sendToProject = (i: number) => { - if (!tempFiles[i].project_uuid) return; + if (!data || !data[i]) { + return; + } setActionLoading((s) => !s) - callSendToProject({ - url: `${settings.localBackend}/tempfiles/${tempFiles[i].uuid}`, - data: tempFiles[i] - }) - .then(({ data }) => { - console.log(data); - const copy = [...tempFiles] - copy.splice(i, 1) - setTempFiles(copy) + + callSendToProject(data[i].uuid, data[i]).then(() => { notifications.show({ title: 'Great Success!', - message: 'Tempory moved do project!', + message: 'Temporary moved do project!', color: 'indigo', }) setActionLoading((s) => !s) @@ -61,18 +59,15 @@ export function TempFiles() { } const deleteTemp = (i: number) => { + if (!data || !data[i]) { + return; + } setActionLoading((s) => !s) - callDeleteTemp({ - url: `${settings.localBackend}/tempfiles/${tempFiles[i].uuid}/delete` - }) - .then(({ data }) => { - console.log(data); - const copy = [...tempFiles] - copy.splice(i, 1) - setTempFiles(copy) + callDeleteTemp(data[i].uuid) + .then(() => { notifications.show({ title: 'Great Success!', - message: 'Tempory sucessfuly deleted!', + message: 'Temporary successfully deleted!', color: 'indigo', }) setActionLoading((s) => !s) @@ -94,10 +89,10 @@ export function TempFiles() { - {tempFiles.map((t, i) => + {data?.map((t, i) => {t.name} - { setProjectUUID(i, p) }} loading={pLoading} value={t.project_uuid} /> + { setProjectUUID(i, p) }} loading={pLoading} value={t.project_uuid} /> @@ -110,7 +105,7 @@ export function TempFiles() { )} - {loading && Array.from(Array(10)) + {isLoading && Array.from(Array(10)) .map((_, i) =>